@use crate::data::RPC; @use crate::generators::cpp_s::*; @(header_name: &str, rpc: &RPC) #include "@header_name" using json = nlohmann::json; namespace nlohmann @{ template struct adl_serializer> @{ static void to_json(json &j, const std::optional &v) @{ if (v.has_value()) j = v.value(); else j = nullptr; @} static void from_json(const json &j, std::optional &v) @{ if (j.is_null()) v.reset(); else v = j.get(); @} @}; @} 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 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>(&__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; @} @} @}