/** * Decode the received message flatbuffer and ensure messages are processed in * order * * @param eventData * @param rawbuf * @param receivedDataStats */ void NexusSubscriber::decodeMessage( std::shared_ptr<EventData> eventData, const std::string &rawbuf, std::shared_ptr<ReceivedDataStats> receivedDataStats) { // if the message is in order or is the first message then go ahead and decode // it auto currentMessageID = getMessageID(rawbuf); if (currentMessageID == receivedDataStats->previousMessageID + 1 || receivedDataStats->previousMessageID == std::numeric_limits<uint64_t>::max()) { eventData->decodeMessage(reinterpret_cast<const uint8_t *>(rawbuf.c_str())); processMessage(eventData, rawbuf, receivedDataStats); receivedDataStats->previousMessageID = currentMessageID; // if this was a message in the map then remove it if (m_futureMessages.count(currentMessageID) > 0) { m_futureMessages.erase(currentMessageID); } // if the next messageID is a key in the map then decode it if (m_futureMessages.count(currentMessageID + 1) > 0) { decodeMessage(eventData, m_futureMessages[currentMessageID + 1], receivedDataStats); } } else { // message is out of order so add it to map to go back to listening m_futureMessages[currentMessageID] = rawbuf; } }
int SendTextIMPacket::putContents(unsigned char *buf) { int pos=0; //multi-fragment information buf[pos++] = numFragments; buf[pos++] = seqFragments; memcpy(buf+pos, &messageID, 2); pos+=2; bool hasImage = false; std::string str2send = EvaUtil::convertToSend(message, &hasImage); buf[pos++] = hasImage?QQ_IM_IMAGE_REPLY:replyType; // auto-reply or not memcpy(buf+pos, str2send.c_str(), str2send.length()); pos += str2send.length(); if (getNumFragments() == (getSeqOfFragments() + 1)) { buf[pos++] = 0x20; // a space, witch is needed in the last fragment setMessageID(getMessageID() + 1); } buf[pos++] = 0x00; // C style string terminator buf[pos++] = fontFlag; buf[pos++] = red; buf[pos++] = green; buf[pos++] = blue; buf[pos++] = 0; short tmpEncoding = htons(encoding); // encoding for text memcpy(buf+pos,&tmpEncoding, 2); pos+=2; int len = fontName.length(); // font name memcpy(buf+pos, fontName.c_str(), len); pos+=len; buf[pos++] = 0x0D; // an Enter return pos; }
void MessageQueueBase::removeRepetitions() { ASSERT(!messageIndex); unsigned short messagesPerType[5][numOfMessageIDs]; unsigned char numberOfProcesses = 0, processes[26], currentProcess = 0; memset(messagesPerType, 0, sizeof(messagesPerType)); memset(processes, 255, sizeof(processes)); selectedMessageForReadingPosition = 0; for(int i = 0; i < numberOfMessages; ++i) { if(getMessageID() == idProcessBegin) { unsigned char process = getData()[0] - 'a'; if(processes[process] == 255) processes[process] = numberOfProcesses++; currentProcess = processes[process]; } ++messagesPerType[currentProcess][getMessageID()]; selectedMessageForReadingPosition += getMessageSize() + headerSize; } selectedMessageForReadingPosition = 0; usedSize = 0; int numOfDeleted = 0; int frameBegin = -1; bool frameEmpty = true; for(int i = 0; i < numberOfMessages; ++i) { int mlength = getMessageSize() + headerSize; bool copy; switch(getMessageID()) { // accept up to 20 times, process id is not important case idText: copy = --messagesPerType[currentProcess][idText] <= 20; break; // accept always, process id is not important case idDebugRequest: case idDebugResponse: case idDebugDataResponse: case idPlot: case idConsole: case idAudioData: case idAnnotation: case idLogResponse: copy = true; break; // data only from latest frame case idStopwatch: case idDebugImage: case idDebugJPEGImage: case idDebugDrawing: case idDebugDrawing3D: copy = messagesPerType[currentProcess][idProcessFinished] == 1; break; // always accept, but may be reverted later case idProcessBegin: if(frameBegin != -1) // nothing between last idProcessBegin and this one, so remove idProcessBegin as well { usedSize = frameBegin; ++numOfDeleted; } currentProcess = processes[getData()[0] - 'a']; copy = true; break; case idProcessFinished: ASSERT(currentProcess == processes[getData()[0] - 'a']); copy = !frameEmpty; // nothing since last idProcessBegin or idProcessFinished, no new idProcessFinished required --messagesPerType[currentProcess][idProcessFinished]; break; default: if(getMessageID() < numOfDataMessageIDs) // data only from latest frame copy = messagesPerType[currentProcess][idProcessFinished] == 1; else // only the latest other messages copy = --messagesPerType[currentProcess][getMessageID()] == 0; } if(copy) { // Remember position of begin of frame, but forget it, when another message was copied. // So idProcessBegin idProcessFinished+ will be removed. if(getMessageID() == idProcessBegin) // remember begin of frame { frameBegin = usedSize; frameEmpty = true; // assume next frame as empty } else if(getMessageID() == idProcessFinished) frameEmpty = true; // assume next frame as empty else // we copy a message within a frame so the idProcessBegin/Finished must stay { frameBegin = -1; frameEmpty = false; } //this message is important, it shall be copied if(usedSize != selectedMessageForReadingPosition) memmove(buf + usedSize, buf + selectedMessageForReadingPosition, mlength); usedSize += mlength; } else ++numOfDeleted; selectedMessageForReadingPosition += mlength; } numberOfMessages -= numOfDeleted; readPosition = 0; selectedMessageForReadingPosition = 0; lastMessage = 0; }