mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-19 13:48:11 +00:00
Added MtNotification message for sending client ready. Moved parsing message to MtMessage source code
This commit is contained in:
Executable
+63
@@ -0,0 +1,63 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "MtMessage.h"
|
||||||
|
|
||||||
|
#include <boost/spirit/include/qi.hpp>
|
||||||
|
#include <boost/phoenix/core.hpp>
|
||||||
|
#include <boost/phoenix/operator.hpp>
|
||||||
|
|
||||||
|
std::unique_ptr<MtCommand> MtCommand::Parse(const std::string& msg)
|
||||||
|
{
|
||||||
|
std::string::size_type pos = msg.find(';');
|
||||||
|
|
||||||
|
using namespace boost::spirit;
|
||||||
|
using rule_s = qi::rule<std::string::const_iterator, std::string()>;
|
||||||
|
using rule = qi::rule<std::string::const_iterator>;
|
||||||
|
|
||||||
|
std::string message_type;
|
||||||
|
std::string expert_handle;
|
||||||
|
std::string command_id;
|
||||||
|
std::string command_type;
|
||||||
|
std::string payload;
|
||||||
|
|
||||||
|
rule_s word_p = qi::as_string[+(qi::char_ - qi::char_(';'))];
|
||||||
|
rule message_type_p = word_p[boost::phoenix::ref(message_type) = qi::_1];
|
||||||
|
rule expert_handle_p = +qi::char_(';') >> word_p[boost::phoenix::ref(expert_handle) = qi::_1];
|
||||||
|
rule command_id_p = +qi::char_(';') >> word_p[boost::phoenix::ref(command_id) = qi::_1];
|
||||||
|
rule command_type_p = +qi::char_(';') >> word_p[boost::phoenix::ref(command_type) = qi::_1];
|
||||||
|
rule payload_p = +qi::char_(';') >> word_p[boost::phoenix::ref(payload) = qi::_1];
|
||||||
|
|
||||||
|
std::unique_ptr<MtCommand> command;
|
||||||
|
|
||||||
|
bool ok = qi::parse(msg.begin(), msg.end(), message_type_p >> -expert_handle_p >> -command_id_p >> -command_type_p >> -payload_p);
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
command = std::make_unique<MtCommand>(std::stoi(expert_handle),
|
||||||
|
std::stoi(command_id), std::stoi(command_type), std::move(payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<MtNotification> MtNotification::Parse(const std::string& msg)
|
||||||
|
{
|
||||||
|
std::string::size_type pos = msg.find(';');
|
||||||
|
|
||||||
|
using namespace boost::spirit;
|
||||||
|
using rule_s = qi::rule<std::string::const_iterator, std::string()>;
|
||||||
|
using rule = qi::rule<std::string::const_iterator>;
|
||||||
|
|
||||||
|
std::string message_type;
|
||||||
|
std::string notification_type;
|
||||||
|
|
||||||
|
rule_s word_p = qi::as_string[+(qi::char_ - qi::char_(';'))];
|
||||||
|
rule message_type_p = word_p[boost::phoenix::ref(message_type) = qi::_1];
|
||||||
|
rule notification_type_p = +qi::char_(';') >> word_p[boost::phoenix::ref(notification_type) = qi::_1];
|
||||||
|
|
||||||
|
std::unique_ptr<MtNotification> command;
|
||||||
|
|
||||||
|
bool ok = qi::parse(msg.begin(), msg.end(), message_type_p >> -notification_type_p);
|
||||||
|
if (ok)
|
||||||
|
command = std::make_unique<MtNotification>((NotificationType)std::stoi(notification_type));
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
+22
-5
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
const std::string MT_MESSAGE_DELIMETER{ ";" };
|
const std::string MT_MESSAGE_DELIMETER{ ";" };
|
||||||
|
|
||||||
@@ -13,7 +14,12 @@ enum MessageType
|
|||||||
EXPERT_LIST = 3,
|
EXPERT_LIST = 3,
|
||||||
EXPERT_ADDED = 4,
|
EXPERT_ADDED = 4,
|
||||||
EXPERT_REMOVED = 5,
|
EXPERT_REMOVED = 5,
|
||||||
CLIENT_READY = 6
|
NOTIFICATION = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NotificationType
|
||||||
|
{
|
||||||
|
CLIENT_READY = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
class MtMessage
|
class MtMessage
|
||||||
@@ -83,6 +89,8 @@ public:
|
|||||||
|
|
||||||
std::string getPayload() const { return payload_; }
|
std::string getPayload() const { return payload_; }
|
||||||
|
|
||||||
|
static std::unique_ptr<MtCommand> Parse(const std::string& msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MessageType GetType() const override
|
MessageType GetType() const override
|
||||||
{
|
{
|
||||||
@@ -103,23 +111,33 @@ private:
|
|||||||
std::string payload_;
|
std::string payload_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MtClientReady : public MtMessage
|
class MtNotification : public MtMessage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MtClientReady()
|
MtNotification(NotificationType type)
|
||||||
|
: notification_type_(type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationType GetNotificationType() const
|
||||||
|
{
|
||||||
|
return notification_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<MtNotification> Parse(const std::string& msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MessageType GetType() const override
|
MessageType GetType() const override
|
||||||
{
|
{
|
||||||
return MessageType::CLIENT_READY;
|
return MessageType::NOTIFICATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetBody() const override
|
std::string GetBody() const override
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationType notification_type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MtEvent : public MtMessage
|
class MtEvent : public MtMessage
|
||||||
@@ -176,7 +194,6 @@ private:
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
int expert_handle_;
|
|
||||||
std::vector<int> experts_;
|
std::vector<int> experts_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+66
-86
@@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <boost/spirit/include/qi.hpp>
|
|
||||||
#include <boost/phoenix/core.hpp>
|
|
||||||
#include <boost/phoenix/operator.hpp>
|
|
||||||
|
|
||||||
#include "MtConnection.h"
|
#include "MtConnection.h"
|
||||||
#include "MtExpert.h"
|
#include "MtExpert.h"
|
||||||
@@ -165,59 +162,15 @@ void MtServer::OnAccept(boost::beast::error_code ec,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
connection->OnMessageReceived.connect([con = connection->weak_from_this(), this](const std::string& msg) {
|
connection->OnMessageReceived.connect([con = connection->weak_from_this(), this](const std::string& msg) {
|
||||||
log_.Trace("MtServer::OnMessageReceived: %s", msg.c_str());
|
try
|
||||||
|
|
||||||
std::string::size_type pos = msg.find(';');
|
|
||||||
if (pos == std::string::npos)
|
|
||||||
{
|
{
|
||||||
log_.Warning("MtServer::OnMessageReceived: invalid message type.");
|
ProcessMessage(msg, con);
|
||||||
return;
|
}
|
||||||
|
catch (std::exception e)
|
||||||
|
{
|
||||||
|
log_.Error("MtServer::OnMessageReceived: Failed to process message: %s", msg.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string msg_type_str = msg.substr(0, pos);;
|
|
||||||
auto msg_type = std::atoi(msg_type_str.c_str());
|
|
||||||
if (msg_type == MessageType::COMMAND)
|
|
||||||
{
|
|
||||||
auto command = ParseCommand(msg);
|
|
||||||
if (command)
|
|
||||||
{
|
|
||||||
auto expert_handle = command->getExpertHandle();
|
|
||||||
if (experts_.count(expert_handle) > 0)
|
|
||||||
{
|
|
||||||
experts_[expert_handle]->expert->Process(std::move(command), [&](const MtResponse& response) {
|
|
||||||
auto connection = con.lock();
|
|
||||||
if (connection)
|
|
||||||
connection->Send(response.Serialize());
|
|
||||||
else
|
|
||||||
log_.Warning("MtServer::OnMessageReceived: connection is not valid (null)");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_.Warning("MtServer::OnMessageReceived: Expert is not found with handle %d", command->getExpertHandle());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_.Warning("MtServer::OnMessageReceived: Failed to parse command from message: %s", msg.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (msg_type == MessageType::CLIENT_READY)
|
|
||||||
{
|
|
||||||
std::vector<int> expert_list;
|
|
||||||
for (const auto& e : experts_)
|
|
||||||
expert_list.push_back(e.first);
|
|
||||||
|
|
||||||
MtExpertListMsg msg(std::move(expert_list));
|
|
||||||
auto connection = con.lock();
|
|
||||||
if (connection)
|
|
||||||
connection->Send(msg.Serialize());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_.Warning("MtServer::OnMessageReceived: unsupported message type %d", msg_type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
pending_connections_.push_back(connection);
|
pending_connections_.push_back(connection);
|
||||||
connection->Accept();
|
connection->Accept();
|
||||||
@@ -227,39 +180,6 @@ void MtServer::OnAccept(boost::beast::error_code ec,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<MtCommand> MtServer::ParseCommand(const std::string& msg)
|
|
||||||
{
|
|
||||||
std::string::size_type pos = msg.find(';');
|
|
||||||
|
|
||||||
using namespace boost::spirit;
|
|
||||||
using rule_s = qi::rule<std::string::const_iterator, std::string()>;
|
|
||||||
using rule = qi::rule<std::string::const_iterator>;
|
|
||||||
|
|
||||||
std::string message_type;
|
|
||||||
std::string expert_handle;
|
|
||||||
std::string command_id;
|
|
||||||
std::string command_type;
|
|
||||||
std::string payload;
|
|
||||||
|
|
||||||
rule_s word_p = qi::as_string[+(qi::char_ - qi::char_(';'))];
|
|
||||||
rule message_type_p = word_p[boost::phoenix::ref(message_type) = qi::_1];
|
|
||||||
rule expert_handle_p = +qi::char_(';') >> word_p[boost::phoenix::ref(expert_handle) = qi::_1];
|
|
||||||
rule command_id_p = +qi::char_(';') >> word_p[boost::phoenix::ref(command_id) = qi::_1];
|
|
||||||
rule command_type_p = +qi::char_(';') >> word_p[boost::phoenix::ref(command_type) = qi::_1];
|
|
||||||
rule payload_p = +qi::char_(';') >> word_p[boost::phoenix::ref(payload) = qi::_1];
|
|
||||||
|
|
||||||
std::unique_ptr<MtCommand> command;
|
|
||||||
|
|
||||||
bool ok = qi::parse(msg.begin(), msg.end(), message_type_p >> -expert_handle_p >> -command_id_p >> -command_type_p >> -payload_p);
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
command = std::make_unique<MtCommand>(std::stoi(expert_handle),
|
|
||||||
std::stoi(command_id), std::stoi(command_type), std::move(payload));
|
|
||||||
}
|
|
||||||
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start accepting incoming connections
|
// Start accepting incoming connections
|
||||||
void MtServer::Start()
|
void MtServer::Start()
|
||||||
{
|
{
|
||||||
@@ -319,3 +239,63 @@ void MtServer::Send(const MtMessage& message)
|
|||||||
for (auto& c : connections_)
|
for (auto& c : connections_)
|
||||||
c->Send(msg);
|
c->Send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MtServer::ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection> con)
|
||||||
|
{
|
||||||
|
log_.Trace("%s: %s", __FUNCTION__, msg.c_str());
|
||||||
|
|
||||||
|
std::string::size_type pos = msg.find(';');
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
{
|
||||||
|
log_.Warning("%s: : invalid message type.", __FUNCTION__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string msg_type_str = msg.substr(0, pos);;
|
||||||
|
auto msg_type = std::atoi(msg_type_str.c_str());
|
||||||
|
if (msg_type == MessageType::COMMAND)
|
||||||
|
{
|
||||||
|
auto command = MtCommand::Parse(msg);
|
||||||
|
if (command)
|
||||||
|
{
|
||||||
|
auto expert_handle = command->getExpertHandle();
|
||||||
|
if (experts_.count(expert_handle) > 0)
|
||||||
|
{
|
||||||
|
experts_[expert_handle]->expert->Process(std::move(command), [con = con, this](const MtResponse& response) {
|
||||||
|
auto connection = con.lock();
|
||||||
|
if (connection)
|
||||||
|
connection->Send(response.Serialize());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_.Warning("%s: Expert is not found with handle %d", __FUNCTION__, command->getExpertHandle());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_.Warning("%s: Failed to parse command from message: %s", __FUNCTION__, msg.c_str());
|
||||||
|
}
|
||||||
|
else if (msg_type == MessageType::NOTIFICATION)
|
||||||
|
{
|
||||||
|
auto notification = MtNotification::Parse(msg);
|
||||||
|
if (notification)
|
||||||
|
{
|
||||||
|
if (notification->GetNotificationType() == NotificationType::CLIENT_READY)
|
||||||
|
{
|
||||||
|
std::vector<int> expert_list;
|
||||||
|
for (const auto& e : experts_)
|
||||||
|
expert_list.push_back(e.first);
|
||||||
|
|
||||||
|
MtExpertListMsg msg(std::move(expert_list));
|
||||||
|
auto connection = con.lock();
|
||||||
|
if (connection)
|
||||||
|
connection->Send(msg.Serialize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_.Warning("%s: Failed to parse notification from message: %s", __FUNCTION__, msg.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_.Warning("%s: unsupported message type %d", __FUNCTION__, msg_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,13 +48,13 @@ private:
|
|||||||
void OnAccept(boost::beast::error_code ec,
|
void OnAccept(boost::beast::error_code ec,
|
||||||
boost::asio::ip::tcp::socket socket);
|
boost::asio::ip::tcp::socket socket);
|
||||||
|
|
||||||
std::unique_ptr<MtCommand> ParseCommand(const std::string& msg);
|
|
||||||
|
|
||||||
void OnEvent(const MtEvent& event);
|
void OnEvent(const MtEvent& event);
|
||||||
void OnDeinitExpert(int handle);
|
void OnDeinitExpert(int handle);
|
||||||
|
|
||||||
void Send(const MtMessage& message);
|
void Send(const MtMessage& message);
|
||||||
|
|
||||||
|
void ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection> con);
|
||||||
|
|
||||||
Logger log_{ "MtServer" };
|
Logger log_{ "MtServer" };
|
||||||
boost::asio::io_context& context_;
|
boost::asio::io_context& context_;
|
||||||
unsigned short port_;
|
unsigned short port_;
|
||||||
|
|||||||
+17
-9
@@ -126,26 +126,30 @@ void MtServiceImpl::SendResponse(int handle, const std::string& payload)
|
|||||||
|
|
||||||
int MtServiceImpl::GetCommandType(int handle)
|
int MtServiceImpl::GetCommandType(int handle)
|
||||||
{
|
{
|
||||||
log_.Trace("%s: handle = %d", __FUNCTION__, handle);
|
|
||||||
|
|
||||||
std::packaged_task<int()> task([handle, this]() {
|
std::packaged_task<int()> task([handle, this]() {
|
||||||
return (experts_.count(handle) > 0) ? experts_[handle]->GetCommandType() : 0;
|
return (experts_.count(handle) > 0) ? experts_[handle]->GetCommandType() : 0;
|
||||||
});
|
});
|
||||||
auto f = task.get_future();
|
auto f = task.get_future();
|
||||||
boost::asio::post(context_, std::bind(std::move(task)));
|
boost::asio::post(context_, std::bind(std::move(task)));
|
||||||
return f.get();
|
|
||||||
|
auto command_type = f.get();
|
||||||
|
log_.Trace("%s: handle = %d, command_type = %d", __FUNCTION__, handle, command_type);
|
||||||
|
|
||||||
|
return command_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MtServiceImpl::GetCommandPayload(int handle)
|
std::string MtServiceImpl::GetCommandPayload(int handle)
|
||||||
{
|
{
|
||||||
log_.Trace("%s: handle = %d", __FUNCTION__, handle);
|
|
||||||
|
|
||||||
std::packaged_task<std::string()> task([handle, this]() {
|
std::packaged_task<std::string()> task([handle, this]() {
|
||||||
return (experts_.count(handle) > 0) ? experts_[handle]->GetCommandPayload() : 0;
|
return (experts_.count(handle) > 0) ? experts_[handle]->GetCommandPayload() : "";
|
||||||
});
|
});
|
||||||
auto f = task.get_future();
|
auto f = task.get_future();
|
||||||
boost::asio::post(context_, std::bind(std::move(task)));
|
boost::asio::post(context_, std::bind(std::move(task)));
|
||||||
return f.get();
|
|
||||||
|
auto payload = f.get();
|
||||||
|
log_.Trace("%s: handle = %d, payload = %s", __FUNCTION__, handle, payload.c_str());
|
||||||
|
|
||||||
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MtServiceImpl::LogError(const std::string& error)
|
void MtServiceImpl::LogError(const std::string& error)
|
||||||
@@ -163,9 +167,13 @@ void MtServiceImpl::OnServerStopped(unsigned short port)
|
|||||||
|
|
||||||
void MtServiceImpl::ThreadProc()
|
void MtServiceImpl::ThreadProc()
|
||||||
{
|
{
|
||||||
log_.Debug("%s: started", __FUNCTION__);
|
std::thread::id this_id = std::this_thread::get_id();
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << this_id;
|
||||||
|
|
||||||
|
log_.Debug("%s: thread %s started", __FUNCTION__, ss.str().c_str());
|
||||||
context_.run();
|
context_.run();
|
||||||
log_.Debug("%s: stopped", __FUNCTION__);
|
log_.Debug("%s: thread %s stopped", __FUNCTION__, ss.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -159,6 +159,7 @@
|
|||||||
<ClCompile Include="Logger.cpp" />
|
<ClCompile Include="Logger.cpp" />
|
||||||
<ClCompile Include="MtConnection.cpp" />
|
<ClCompile Include="MtConnection.cpp" />
|
||||||
<ClCompile Include="MtExpert.cpp" />
|
<ClCompile Include="MtExpert.cpp" />
|
||||||
|
<ClCompile Include="MtMessage.cpp" />
|
||||||
<ClCompile Include="MtServer.cpp" />
|
<ClCompile Include="MtServer.cpp" />
|
||||||
<ClCompile Include="MtService.cpp" />
|
<ClCompile Include="MtService.cpp" />
|
||||||
<ClCompile Include="pch.cpp">
|
<ClCompile Include="pch.cpp">
|
||||||
|
|||||||
@@ -74,5 +74,8 @@
|
|||||||
<ClCompile Include="Logger.cpp">
|
<ClCompile Include="Logger.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="MtMessage.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user