2017-07-17 17:28:54 +01:00
|
|
|
#include "rpc_connection.h"
|
2017-07-20 21:24:18 +01:00
|
|
|
#include "serialization.h"
|
2017-07-17 17:28:54 +01:00
|
|
|
|
2017-07-17 22:49:31 +01:00
|
|
|
#include <atomic>
|
|
|
|
|
|
|
|
static const int RpcVersion = 1;
|
|
|
|
static RpcConnection Instance;
|
2017-07-17 17:28:54 +01:00
|
|
|
|
|
|
|
/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId)
|
|
|
|
{
|
|
|
|
Instance.connection = BaseConnection::Create();
|
2017-07-20 21:24:18 +01:00
|
|
|
StringCopy(Instance.appId, applicationId);
|
2017-07-17 17:28:54 +01:00
|
|
|
return &Instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ void RpcConnection::Destroy(RpcConnection*& c)
|
|
|
|
{
|
2017-07-17 22:49:31 +01:00
|
|
|
c->Close();
|
2017-07-17 17:28:54 +01:00
|
|
|
BaseConnection::Destroy(c->connection);
|
|
|
|
}
|
|
|
|
|
2017-07-17 22:49:31 +01:00
|
|
|
void RpcConnection::Open()
|
|
|
|
{
|
|
|
|
if (state == State::Connected) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state == State::Disconnected) {
|
|
|
|
if (connection->Open()) {
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:54:52 +01:00
|
|
|
if (state == State::SentHandshake) {
|
2017-07-25 17:06:48 +01:00
|
|
|
JsonDocument message;
|
2017-07-21 21:54:52 +01:00
|
|
|
if (Read(message)) {
|
|
|
|
auto cmd = message.FindMember("cmd");
|
|
|
|
if (cmd == message.MemberEnd() || !cmd->value.IsString()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto evt = message.FindMember("evt");
|
|
|
|
if (evt == message.MemberEnd() || !evt->value.IsString()) {
|
|
|
|
return;
|
|
|
|
}
|
2017-07-25 17:27:48 +01:00
|
|
|
if (!strcmp(cmd->value.GetString(), "DISPATCH") &&
|
|
|
|
!strcmp(evt->value.GetString(), "READY")) {
|
2017-07-21 21:54:52 +01:00
|
|
|
state = State::Connected;
|
|
|
|
if (onConnect) {
|
|
|
|
onConnect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sendFrame.opcode = Opcode::Handshake;
|
2017-07-25 17:27:48 +01:00
|
|
|
sendFrame.length =
|
|
|
|
JsonWriteHandshakeObj(sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId);
|
2017-07-21 21:54:52 +01:00
|
|
|
|
|
|
|
if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) {
|
|
|
|
state = State::SentHandshake;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Close();
|
2017-07-17 22:49:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RpcConnection::Close()
|
|
|
|
{
|
2017-07-25 19:41:12 +01:00
|
|
|
if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) {
|
2017-07-17 22:49:31 +01:00
|
|
|
onDisconnect(lastErrorCode, lastErrorMessage);
|
|
|
|
}
|
|
|
|
connection->Close();
|
|
|
|
state = State::Disconnected;
|
|
|
|
}
|
|
|
|
|
2017-07-18 22:29:54 +01:00
|
|
|
bool RpcConnection::Write(const void* data, size_t length)
|
2017-07-17 22:49:31 +01:00
|
|
|
{
|
2017-07-17 23:42:06 +01:00
|
|
|
sendFrame.opcode = Opcode::Frame;
|
|
|
|
memcpy(sendFrame.message, data, length);
|
|
|
|
sendFrame.length = length;
|
|
|
|
if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) {
|
2017-07-17 22:49:31 +01:00
|
|
|
Close();
|
2017-07-18 22:29:54 +01:00
|
|
|
return false;
|
2017-07-17 22:49:31 +01:00
|
|
|
}
|
2017-07-18 22:29:54 +01:00
|
|
|
return true;
|
2017-07-17 22:49:31 +01:00
|
|
|
}
|
|
|
|
|
2017-07-24 18:54:47 +01:00
|
|
|
bool RpcConnection::Read(JsonDocument& message)
|
2017-07-17 22:49:31 +01:00
|
|
|
{
|
2017-07-21 21:54:52 +01:00
|
|
|
if (state != State::Connected && state != State::SentHandshake) {
|
2017-07-17 22:49:31 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
MessageFrame readFrame;
|
|
|
|
for (;;) {
|
|
|
|
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
|
|
|
|
if (!didRead) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (readFrame.length > 0) {
|
|
|
|
didRead = connection->Read(readFrame.message, readFrame.length);
|
|
|
|
if (!didRead) {
|
|
|
|
lastErrorCode = -2;
|
|
|
|
StringCopy(lastErrorMessage, "Partial data in frame");
|
|
|
|
Close();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
readFrame.message[readFrame.length] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (readFrame.opcode) {
|
2017-07-25 17:27:48 +01:00
|
|
|
case Opcode::Close: {
|
2017-07-18 22:49:44 +01:00
|
|
|
message.ParseInsitu(readFrame.message);
|
2017-07-17 22:49:31 +01:00
|
|
|
lastErrorCode = message["code"].GetInt();
|
|
|
|
const auto& m = message["message"];
|
2017-07-20 21:24:18 +01:00
|
|
|
StringCopy(lastErrorMessage, m.GetString());
|
2017-07-17 22:49:31 +01:00
|
|
|
Close();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case Opcode::Frame:
|
2017-07-18 22:49:44 +01:00
|
|
|
message.ParseInsitu(readFrame.message);
|
2017-07-17 22:49:31 +01:00
|
|
|
return true;
|
|
|
|
case Opcode::Ping:
|
2017-07-18 22:49:44 +01:00
|
|
|
readFrame.opcode = Opcode::Pong;
|
|
|
|
if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) {
|
2017-07-17 22:49:31 +01:00
|
|
|
Close();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Opcode::Pong:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// something bad happened
|
|
|
|
lastErrorCode = -1;
|
|
|
|
StringCopy(lastErrorMessage, "Bad ipc frame");
|
|
|
|
Close();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|