Introduce message threads and message handling (#4)

This commit is contained in:
Chalith Desaman
2021-06-04 12:06:22 +05:30
committed by GitHub
parent 23df070313
commit 2dfd7cf6bc
18 changed files with 762 additions and 43 deletions

252
src/msg/json/msg_json.cpp Normal file
View File

@@ -0,0 +1,252 @@
#include "msg_json.hpp"
namespace msg::json
{
// JSON separators
constexpr const char *SEP_COMMA = "\",\"";
constexpr const char *SEP_COLON = "\":\"";
constexpr const char *SEP_COMMA_NOQUOTE = ",\"";
constexpr const char *SEP_COLON_NOQUOTE = "\":";
constexpr const char *DOUBLE_QUOTE = "\"";
/**
* Parses a json message sent by the message board.
* @param d Jsoncons document to which the parsed json should be loaded.
* @param message The message to parse.
* Accepted message format:
* {
* 'type': '<message type>'
* ...
* }
* @return 0 on successful parsing. -1 for failure.
*/
int parse_message(jsoncons::json &d, std::string_view message)
{
try
{
d = jsoncons::json::parse(message, jsoncons::strict_json_parsing());
}
catch (const std::exception &e)
{
LOG_ERROR << "JSON message parsing failed. " << e.what();
return -1;
}
// Check existence of msg type field.
if (!d.contains(msg::FLD_TYPE) || !d[msg::FLD_TYPE].is<std::string>())
{
LOG_ERROR << "JSON message 'type' missing or invalid.";
return -1;
}
return 0;
}
/**
* Extracts the message 'type' value from the json document.
*/
int extract_type(std::string &extracted_type, const jsoncons::json &d)
{
extracted_type = d[msg::FLD_TYPE].as<std::string>();
return 0;
}
/**
* Extracts type, id and pubkey in the msg.
* @param type Type in the message.
* @param id id in the message.
* @param pubkey Pubkey in the message.
* @param d The json document holding the read request message.
* Accepted signed input container format:
* {
* ...
* "type": "<message type>",
* "id": "<message id>",
* "owner_pubkey": "<pubkey of the owner>",
* ...
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_commons(std::string &type, std::string &id, std::string &pubkey, const jsoncons::json &d)
{
if (extract_type(type, d) == -1)
return -1;
if (!d.contains(msg::FLD_ID))
{
LOG_ERROR << "Field id is missing.";
return -1;
}
if (!d[msg::FLD_ID].is<std::string>())
{
LOG_ERROR << "Invalid id value.";
return -1;
}
if (!d.contains(msg::FLD_PUBKEY))
{
LOG_ERROR << "Field owner_pubkey is missing.";
return -1;
}
if (!d[msg::FLD_PUBKEY].is<std::string>())
{
LOG_ERROR << "Invalid owner_pubkey value.";
return -1;
}
id = d[msg::FLD_ID].as<std::string>();
pubkey = d[msg::FLD_PUBKEY].as<std::string>();
return 0;
}
/**
* Extracts create message from msg.
* @param msg Populated msg object.
* @param d The json document holding the read request message.
* Accepted signed input container format:
* {
* "type": "create",
* "owner_pubkey": "<pubkey of the owner>"
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_create_message(create_msg &msg, const jsoncons::json &d)
{
if (extract_commons(msg.type, msg.id, msg.pubkey, d) == -1)
return -1;
return 0;
}
/**
* Extracts destroy message from msg.
* @param msg Populated msg object.
* @param d The json document holding the read request message.
* Accepted signed input container format:
* {
* "type": "destroy",
* "owner_pubkey": "<pubkey of the owner>",
* "contract_id": "<contract id>",
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_destroy_message(destroy_msg &msg, const jsoncons::json &d)
{
if (extract_commons(msg.type, msg.id, msg.pubkey, d) == -1)
return -1;
if (!d.contains(msg::FLD_CONTRACT_ID))
{
LOG_ERROR << "Field contract_id is missing.";
return -1;
}
if (!d[msg::FLD_CONTRACT_ID].is<std::string>())
{
LOG_ERROR << "Invalid contract_id value.";
return -1;
}
msg.contract_id = d[msg::FLD_CONTRACT_ID].as<std::string>();
return 0;
return 0;
}
/**
* Extracts start message from msg.
* @param msg Populated msg object.
* @param d The json document holding the read request message.
* Accepted signed input container format:
* {
* "type": "start",
* "owner_pubkey": "<pubkey of the owner>",
* "contract_id": "<contract id>",
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_start_message(start_msg &msg, const jsoncons::json &d)
{
if (extract_commons(msg.type, msg.id, msg.pubkey, d) == -1)
return -1;
if (!d.contains(msg::FLD_CONTRACT_ID))
{
LOG_ERROR << "Field contract_id is missing.";
return -1;
}
if (!d[msg::FLD_CONTRACT_ID].is<std::string>())
{
LOG_ERROR << "Invalid contract_id value.";
return -1;
}
msg.contract_id = d[msg::FLD_CONTRACT_ID].as<std::string>();
return 0;
return 0;
}
/**
* Extracts stop message from msg.
* @param msg Populated msg object.
* @param d The json document holding the read request message.
* Accepted signed input container format:
* {
* "type": "stop",
* "owner_pubkey": "<pubkey of the owner>",
* "contract_id": "<contract id>",
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_stop_message(stop_msg &msg, const jsoncons::json &d)
{
if (extract_commons(msg.type, msg.id, msg.pubkey, d) == -1)
return -1;
if (!d.contains(msg::FLD_CONTRACT_ID))
{
LOG_ERROR << "Field contract_id is missing.";
return -1;
}
if (!d[msg::FLD_CONTRACT_ID].is<std::string>())
{
LOG_ERROR << "Invalid contract_id value.";
return -1;
}
msg.contract_id = d[msg::FLD_CONTRACT_ID].as<std::string>();
return 0;
return 0;
}
/**
* Constructs a response json.
* @param msg Buffer to construct the generated json message string into.
* Message format:
* {
* 'type': '<message type>',
* "content": "<any string>"
* }
* @param response_type Type of the response.
* @param content Content inside the response.
*/
void create_response(std::string &msg, std::string_view response_type, std::string_view content)
{
msg.reserve(1024);
msg += "{\"";
msg += msg::FLD_TYPE;
msg += SEP_COLON;
msg += response_type;
msg += SEP_COMMA;
msg += msg::FLD_CONTENT;
msg += SEP_COLON;
msg += content;
msg += "\"}";
}
} // namespace msg::json

30
src/msg/json/msg_json.hpp Normal file
View File

@@ -0,0 +1,30 @@
#ifndef _HP_MSG_MSG_JSON_
#define _HP_MSG_MSG_JSON_
#include "../../pchheader.hpp"
#include "../msg_common.hpp"
/**
* Parser helpers for json messages.
*/
namespace msg::json
{
int parse_message(jsoncons::json &d, std::string_view message);
int extract_type(std::string &extracted_type, const jsoncons::json &d);
int extract_commons(std::string &type, std::string &id, std::string &pubkey, const jsoncons::json &d);
int extract_create_message(create_msg &msg, const jsoncons::json &d);
int extract_destroy_message(destroy_msg &msg, const jsoncons::json &d);
int extract_start_message(start_msg &msg, const jsoncons::json &d);
int extract_stop_message(stop_msg &msg, const jsoncons::json &d);
void create_response(std::string &msg, std::string_view response_type, std::string_view content);
} // namespace msg::json
#endif

55
src/msg/msg_common.hpp Normal file
View File

@@ -0,0 +1,55 @@
#ifndef _HP_MSG_MSG_COMMON_
#define _HP_MSG_MSG_COMMON_
#include "../pchheader.hpp"
namespace msg
{
struct create_msg
{
std::string id;
std::string type;
std::string pubkey;
};
struct destroy_msg
{
std::string id;
std::string type;
std::string pubkey;
std::string contract_id;
};
struct start_msg
{
std::string id;
std::string type;
std::string pubkey;
std::string contract_id;
};
struct stop_msg
{
std::string id;
std::string type;
std::string pubkey;
std::string contract_id;
};
// Message field names
constexpr const char *FLD_TYPE = "type";
constexpr const char *FLD_CONTENT = "content";
constexpr const char *FLD_PUBKEY = "owner_pubkey";
constexpr const char *FLD_CONTRACT_ID = "contract_id";
constexpr const char *FLD_ID = "id";
// Message types
constexpr const char *MSGTYPE_INIT = "init";
constexpr const char *MSGTYPE_CREATE = "create";
constexpr const char *MSGTYPE_DESTROY = "destroy";
constexpr const char *MSGTYPE_START = "start";
constexpr const char *MSGTYPE_STOP = "stop";
} // namespace msg
#endif

41
src/msg/msg_parser.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "msg_parser.hpp"
#include "json/msg_json.hpp"
namespace msg
{
int msg_parser::parse(std::string_view message)
{
return json::parse_message(jdoc, message);
}
int msg_parser::extract_type(std::string &extracted_type) const
{
return json::extract_type(extracted_type, jdoc);
}
int msg_parser::extract_create_message(create_msg &msg) const
{
return json::extract_create_message(msg, jdoc);
}
int msg_parser::extract_destroy_message(destroy_msg &msg) const
{
return json::extract_destroy_message(msg, jdoc);
}
int msg_parser::extract_start_message(start_msg &msg) const
{
return json::extract_start_message(msg, jdoc);
}
int msg_parser::extract_stop_message(stop_msg &msg) const
{
return json::extract_stop_message(msg, jdoc);
}
void msg_parser::create_response(std::string &msg, std::string_view response_type, std::string_view content) const
{
json::create_response(msg, response_type, content);
}
} // namespace msg

25
src/msg/msg_parser.hpp Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _SA_MSG_MSG_PARSER_
#define _SA_MSG_MSG_PARSER_
#include "../pchheader.hpp"
#include "msg_common.hpp"
namespace msg
{
class msg_parser
{
jsoncons::json jdoc;
public:
int parse(std::string_view message);
int extract_type(std::string &extracted_type) const;
int extract_create_message(create_msg &msg) const;
int extract_destroy_message(destroy_msg &msg) const;
int extract_start_message(start_msg &msg) const;
int extract_stop_message(stop_msg &msg) const;
void create_response(std::string &msg, std::string_view response_type, std::string_view content) const;
};
} // namespace msg
#endif