97 lines
3.3 KiB
C++
97 lines
3.3 KiB
C++
@use crate::data::RPC;
|
|
@use crate::generators::cpp_s::*;
|
|
|
|
@(header_name: &str, rpc: &RPC)
|
|
#include "@header_name"
|
|
using json = nlohmann::json;
|
|
|
|
namespace nlohmann @{
|
|
template <typename T>
|
|
struct adl_serializer<std::optional<T>> @{
|
|
static void to_json(json &j, const std::optional<T> &v) @{
|
|
if (v.has_value())
|
|
j = v.value();
|
|
else
|
|
j = nullptr;
|
|
@}
|
|
|
|
static void from_json(const json &j, std::optional<T> &v) @{
|
|
if (j.is_null())
|
|
v.reset();
|
|
else
|
|
v = j.get<T>();
|
|
@}
|
|
@};
|
|
@}
|
|
|
|
namespace mrpc @{
|
|
@for s in &rpc.structs {
|
|
void to_json(nlohmann::json &j, const @s.name &v) @{
|
|
@for f in &s.fields { j["@f.name"] = v.@f.name;
|
|
}
|
|
@}
|
|
void from_json(const nlohmann::json &j, @s.name &v) @{
|
|
@for f in &s.fields { j.at("@f.name").get_to(v.@f.name);
|
|
}
|
|
@}
|
|
}
|
|
|
|
template<class T>
|
|
void send_msg(crow::websocket::connection &c, uint64_t id, const T &v) @{
|
|
c.send_text(json@{@{"id", id@},@{"data", v@}@}.dump());
|
|
@}
|
|
|
|
void mrpc::MRPCStreamImpl::close() noexcept @{
|
|
if (conn != nullptr) @{
|
|
send_msg(*conn, id, nullptr);
|
|
conn = nullptr;
|
|
@}
|
|
@}
|
|
void mrpc::MRPCStreamImpl::abort() noexcept @{ conn = nullptr; @}
|
|
bool mrpc::MRPCStreamImpl::is_open() noexcept @{ return conn != nullptr; @}
|
|
|
|
void mrpc::MRPCServer::install(crow::SimpleApp &app, std::string &&route) @{
|
|
app.route_dynamic(std::move(route))
|
|
.websocket()
|
|
.onclose([&](crow::websocket::connection &c, const std::string&)@{
|
|
std::lock_guard guard@{__streams_mutex@};
|
|
auto range = __streams.equal_range(&c);
|
|
for (auto it = range.first; it != range.second; ++it)
|
|
it->second->abort();
|
|
__streams.erase(&c);
|
|
@})
|
|
.onmessage([this](auto &&a, auto &&b, auto &&c) @{
|
|
try @{ msg_handler(a, b, c); @}
|
|
catch (const std::exception &_) @{@}
|
|
@});
|
|
@}
|
|
void mrpc::MRPCServer::msg_handler(crow::websocket::connection &__c, const std::string &__msg, bool) @{
|
|
json __j = json::parse(__msg);
|
|
std::uint64_t __id = __j.at("id");
|
|
std::string __service = __j.at("service"), __method = __j.at("method");
|
|
try @{
|
|
json __data = __j.at("data");
|
|
@for (si, s) in rpc.services.iter().enumerate() {
|
|
@if si > 0 {else }if (__service == "@s.name") @{
|
|
@for (mi, m) in s.methods.iter().enumerate() {
|
|
@if mi > 0 {else }if (__method == "@m.name") @{
|
|
@if m.ret_stream {
|
|
auto __stream = std::make_shared<MRPCStream<@ty_to_str(m.ret.as_ref().unwrap())>>(&__c, __id);
|
|
@{ std::lock_guard guard@{__streams_mutex@}; __streams.emplace(&__c, __stream); @}
|
|
}
|
|
@for (name, ty) in m.args.iter().map(|a| (&a.name, ty_to_str(&a.ty))) { @ty @name = __data.at("@name");
|
|
}
|
|
@if m.ret_stream || m.ret.is_none() {@(s.name)_@(m.name)(@call_args(m));}
|
|
else {send_msg(__c, __id, @(s.name)_@(m.name)(@call_args(m)));}
|
|
@}
|
|
}
|
|
else @{ throw std::exception@{@}; @}
|
|
@}
|
|
}
|
|
else @{ throw std::exception@{@}; @}
|
|
@} catch (const std::exception &_) @{
|
|
std::cerr << "Got invalid request " << __id << " for " << __service << "::" << __method << std::endl;
|
|
@}
|
|
@}
|
|
@}
|