How to get data from Photon eventContent dictionary - c++

We are receiving this callback using ExitGames Photon Realtime engine when an event is fired
customEventAction(int playerNr,
nByte eventCode,
const ExitGames::Common::Object& eventContent)
If the object is a string we use this code to extract it
ExitGames::Common::JString str =
ExitGames::Common::ValueObject<ExitGames::Common::JString>(eventContent).getDataCopy();
However, the object being sent is a dictionary. It's being sent from the server using BroadcastEvent.
How do we get data out of it ?
We've tried this, but it doesn't make any sense:
ExitGames::Common::Dictionary<byte,ExitGames::Common::Object> pdic
= ExitGames::Common::ValueObject<ExitGames::Common::Dictionary<byte,ExitGames::Common::Object>>(eventContent).getDataCopy();
I've found code to get the data from a hashtable, but that doesn't work either.
thanks
Shaun

ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> dic = ExitGames::Common::ValueObject<ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> >(eventContent).getDataCopy();
is absolutely correct and works for me.
The cause of your problem must be inside another line.
When you replace the implementations of sendEvent() and customEventAction() in demo_loadBalancing inside one of the Photon C++ client SDKs with the following snippets, then that demo successfully sends and receives a Dictionary:
send:
void NetworkLogic::sendEvent(void)
{
ExitGames::Common::ValueObject<ExitGames::Common::JString> obj(L"test");
ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> dic;
dic.put(1, obj);
mLoadBalancingClient.opRaiseEvent(false, dic, 0);
}
receive:
void NetworkLogic::customEventAction(int /*playerNr*/, nByte /*eventCode*/, const ExitGames::Common::Object& eventContent)
{
EGLOG(ExitGames::Common::DebugLevel::ALL, L"");
ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> dic = ExitGames::Common::ValueObject<ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> >(eventContent).getDataCopy();
const ExitGames::Common::Object* pObj = dic.getValue(1);
ExitGames::Common::JString str = ExitGames::Common::ValueObject<ExitGames::Common::JString>(pObj).getDataCopy();
mpOutputListener->write(L"received the following string as Dictionary value: " + str);
}
This gives me the following line of output on the receiving client:
received the following string as Dictionary value: test

Related

Arduino can NOT send JSON

I want so send data via a JSON object. All 7 variables you can see in the code should be well defined.
I get the following "error message"/incomplete JSON from Arduino monitor:
{"topic":"Statistics","DrillDuration":"1000","SpeedToDrill":"20","SpeedWithObjectBefore":"100","SpeedWithObjectAfter":"100⸮⸮
Any idea? Is the package for my JSON too small?
I tested my function on a separate Arduino, where I cut my hole program. There it runs without any problems. This function "sendSummary" runs at the end of a bigger code, maybe this could lead to some issues?
Thanks a lot for your help!
void sendSummary()
{
const size_t capacity = JSON_OBJECT_SIZE(14);
DynamicJsonDocument doc(capacity);
doc["topic"] = "Statistics";
doc["DrillDuration"] = DrillDuration;
doc["SpeedToDrill"] = SpeedToDrill;
doc["SpeedWithObjectBefore"] = SpeedWithObjectBefore;
doc["SpeedWithObjectAfter"] = SpeedWithObjectAfter;
doc["SpeedWithoutObject"] = SpeedWithoutObject;
doc["DrillSpeed"] = DrillSpeedVar;
serializeJson(doc, Serial);
Serial.write("\n");
}

Replacing value of a member in rapidjson

I am currently working on a project in C++ using rapidjson.
My program receives some JSON data on a socket which includes some authentication details. I log the incoming message, but I want to hide the password so it can't be seen in the log file. So I am trying to get the JSON object, and replace each character of the string and put this replaced string back into the json object where the password was.
Below is the code that I have:
rapidjson::Document jsonObject;
jsonObject.Parse(command.c_str());
string method = jsonObject["method"].GetString();
if (jsonObject.HasMember("sshDetails"))
{
Value& sshDetails = jsonObject["sshDetails"];
string sshPassword = sshDetails["sshPassword"].GetString();
for (int i = 0; i < sshPassword.length(); i++)
{
sshPassword[i] = '*';
}
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->name.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
//Convert it back to a string
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer>writer(buffer);
Document jsonDoc;
jsonDoc.Accept(writer);
string jsonString = string(buffer.GetString());
I'm getting an error on the following line:
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
The error I am getting is:
No suitable conversion function from rapidjson::GenericMemberIterator<false, rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CtrlAllocator>> to rapidjson::GenericMember::UTF8<char>, myProject...SocketProcessor.cpp
rapidjson::MemoryPoolAllocator<rapidjson::CtrlAllocator>>*exists
I took the above from an example on another question on SO which was an accepted answer from rapidjson - change key to another value, so what am I missing.
I've managed to find the answer to this with a bit of playing round and luck.
I changed
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->name.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
to be
rapidjson::Value::MemberIterator sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->value.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
using rapidjson in my project I found out that many of such problems can be omitted by the use of auto instead of specifying the type

How to create new GMimeMessage from string?

In my project i use libgmime for MIME types. I'm trying to create new GMimeMessage using std::string as a body.
According to docs it can be done using GMimeStream and GMimeDataWrapper for preparing data, and then creating GMimePart from this data to be set as MIME part of new message.
The code:
std::string body = "some test data";
GMimeMessage* message = g_mime_message_new(FALSE);
//set header
g_mime_object_set_header((GMimeObject *) message, name.c_str()), value.c_str();
//create stream and write data into it.
GMimeStream* stream;
g_mime_stream_construct(stream, 0, body.length());
g_mime_stream_write_string(stream, body.c_str());
GMimeDataWrapper* wrapper = g_mime_data_wrapper_new_with_stream(stream, GMIME_CONTENT_ENCODING_DEFAULT);
//create GMimePart to be set as mime part of GMimeMessage
GMimePart* mime_part = g_mime_part_new();
g_mime_part_set_content_object(mime_part, wrapper);
g_mime_message_set_mime_part(message, (GMimeObject *) mime_part);
When i try to create message in this way, i get segfault here:
g_mime_stream_write_string(stream, body.c_str());
Maybe i'm using wrong method of message creation...
What's the right way it can be done?
You have bad initialization GMimeStream *stream. Need:
GMimeStream *stream;
/* initialize GMime */
g_mime_init (0);
/* create a stream around stdout */
stream = g_mime_stream_mem_new_with_buffer(body_part.c_str(), body_part.length());
See doc: http://spruce.sourceforge.net/gmime/tutorial/x49.html
And sample: http://fossies.org/linux/gmime/examples/basic-example.c

Sending data using Hashtable on Photon Cloud

I am trying to send data using Hashtable on photon cloud, I do receive the data with correct eventCode, but the key-value pair returns some random numbers. My code is like this while sending data:-
void NetworkLogic::sendEvent(void)
{
ExitGames::Common::Hashtable* table =new ExitGames::Common::Hashtable;
table->put<int,int>(4,21);
const ExitGames::Common::Hashtable temp = (const ExitGames::Common::Hashtable)*table;//= new ExitGames::Common::Hashtable;
mLoadBalancingClient.opRaiseEvent(false, temp, 100);
}
While receiving data, the code is like this:-
void NetworkLogic::customEventAction(int playerNr, nByte eventCode, const ExitGames::Common::Hashtable& eventContent)
{
// you do not receive your own events, unless you specify yourself as one of the receivers explicitly, so you must start 2 clients, to receive the events, which you have sent, as sendEvent() uses the default receivers of opRaiseEvent() (all players in same room like the sender, except the sender itself)
PhotonPeer_sendDebugOutput(&mLoadBalancingClient, DEBUG_LEVEL_ALL, L"");
cout<<((int)(eventContent.getValue(4)));
}
What I get printed on console is some random values or int, while it should be 21. What am I doing wrong here?
Edit:
In customEventAction() when I used the following statement:
cout<<eventContent.getValue(4)->getType()<<endl;
cout<<"Event code = "<<eventCode<<endl;
I got the following output:
i
Event code = d
I searched and found that 'i' is the value of EG_INTEGER which means the value I am sending is getting received properly. I am just not been able to convert it back to int. And why the event code is coming as 'd'?
eventContent.getValue(4)
returns an Object.
You can't simply cast that Object to int, but have to access the int value inside it:
if(eventContent.getValue(4))
myInt = ExitGames::Common::ValueObject<int>(eventContent.getValue(4)).getDataCopy();
cout << myInt;

Passing Protocol buffer serialized datas from C++ to Python via LevelDB

Though I've followed the excellent Protocol Buffer documentation and tutorials for C++ and Python, I can't achieve my goal which is :
- to serialize datas from a C++ process.
- insert it into LevelDB from that same process.
- extract the serialized datas from a Python process
- Deseralize it from this same Python process
- Use those deseralized datas in Python
I can serialize my datas using protocol buffer in C++ (using a std::string container). I can insert it into LevelDB. But, when I levelDB->Get my serialized datas, though Python seems to recognize it as a String, and showing me their raw content, whenever I deserialize it into a Python String, it is empty!
Here is how I serialize and insert my datas in C++ :
int main(int arg, char** argv)
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
leveldb::DB* db;
leveldb::Options options;
leveldb::Status status;
tutorial::AddressBook address_book;
tutorial::Person* person1;
tutorial::Person* person2;
options.create_if_missing = true;
status = leveldb::DB::Open(options, "test_db", &db);
assert(status.ok());
person1 = address_book.add_person();
person1->set_id(1);
person1->set_name("ME");
person1->set_email("me#me.com");
person2 = address_book.add_person();
person2->set_id(2);
person2->set_name("SHE");
person2->set_email("she#she.com");
std::string test;
if (!address_book.SerializeToString(&test))
{
std::cerr << "Failed to write address book" << std::endl;
return -1;
}
if (status.ok()) status = db->Put(leveldb::WriteOptions(), "Test", test);
And here is how I try to deserialize it in Python:
address_book = addressbook_pb2.AddressBook()
db = leveldb.LevelDB('test_db')
ab = address_book.ParseFromString(db.Get("Test"))
ad var type is NoneType
Edit :
before the db.Get(), ab.ByteSize() returns 0, 76 after the ParseFromString(), I assume it's a Type problem then...
+
ab.ListFields() returns a unexploitable list of the contained field: succesfully couting two person instances, but unable to let me acces to it.
Any clues, any ideas of what I didn't understand, what I'm doing wrong here?
Many thanks!
Ok, so this was my bad.
I went back into the Protocol Buffers Python documentation, and the fact is that even if the AdressBook object I was retrieving did not showed any description, it was still able to be iterated over and even had a .str() method.
so, if anyone comes to that problem again, just try to explore your ProtocolBuffers object using iPython like I did, and you'll find that every of your proto elements are fields of your object.
Using my example:
ab = adress_book.ParseFromString(db.Get('Test'))
ab.__str__() # Shows a readable version of my object
for person in adress_book.person: # I'm even able to iterate over any of my ab fields values
print person.id
print person.name
Try using ' instead of ":
ab = address_book.ParseFromString(db->Get('Test'))