#ifndef PYFINS_RPC_FRAME_CODEC_H #define PYFINS_RPC_FRAME_CODEC_H #include #include #include #include // Shared binary protocol used by the pyRpcFins binary RPC server. // [magic "ERPC":4][payload length:4][request id:4][command:2][payload] class RpcFrameCodec { public: static const quint32 Magic = 0x45525043; // "ERPC" static const int HeaderSize = 14; static const quint32 MaxPayloadSize = 64u * 1024u * 1024u; enum CmdType { CmdInit = 1, CmdExecute = 2, CmdIsConnected = 3, RespOk = 0x0100, RespError = 0x0101, }; struct Frame { quint32 id = 0; quint16 cmd = 0; QByteArray payload; }; static QByteArray build(quint32 id, quint16 cmd, const QByteArray& payload) { QByteArray out; out.resize(HeaderSize); uchar* header = reinterpret_cast(out.data()); qToBigEndian(Magic, header); qToBigEndian(static_cast(payload.size()), header + 4); qToBigEndian(id, header + 8); qToBigEndian(cmd, header + 12); out.append(payload); return out; } static QByteArray requestPayload(const QString& module, const QString& text = QString()) { QByteArray payload = module.toUtf8(); if (!text.isEmpty()) { payload.append('\n'); payload.append(text.toUtf8()); } return payload; } void append(const QByteArray& chunk) { buffer_.append(chunk); } void clear() { buffer_.clear(); } QList takeFrames() { QList frames; const QByteArray magicBytes("ERPC", 4); for (;;) { const int magicIndex = buffer_.indexOf(magicBytes); if (magicIndex < 0) { if (buffer_.size() > 3) { buffer_ = buffer_.right(3); } break; } if (magicIndex > 0) { buffer_.remove(0, magicIndex); } if (buffer_.size() < HeaderSize) { break; } const uchar* header = reinterpret_cast(buffer_.constData()); const quint32 payloadLength = qFromBigEndian(header + 4); if (payloadLength > MaxPayloadSize) { buffer_.remove(0, 1); continue; } const qint64 frameSize = static_cast(HeaderSize) + payloadLength; if (buffer_.size() < frameSize) { break; } Frame frame; frame.id = qFromBigEndian(header + 8); frame.cmd = qFromBigEndian(header + 12); frame.payload = buffer_.mid(HeaderSize, static_cast(payloadLength)); buffer_.remove(0, static_cast(frameSize)); frames.append(frame); } return frames; } private: QByteArray buffer_; }; #endif // PYFINS_RPC_FRAME_CODEC_H