mrpc/templates/cpp_server.rs.cpp

97 lines
3.6 KiB
C++

@use crate::data::RPC;
@use crate::generators::cpp_s::*;
@use super::cpp_server_json_cpp;
@(header_name: &str, rpc: &RPC)
#include "@header_name"
#include <corvusoft/restbed/session.hpp>
#include <corvusoft/restbed/resource.hpp>
#include <corvusoft/restbed/request.hpp>
@:cpp_server_json_cpp(rpc)
template<typename T>
void send_msg(const std::shared_ptr<restbed::Session> &c, const T &v) @{
if (c->is_closed())
return;
rapidjson::StringBuffer s;
mrpc::MRPCJWriter writer@{s@};
v >> writer;
const auto body_ptr = s.GetString();
const auto body = restbed::Bytes@{body_ptr, body_ptr+s.GetLength()@};
c->yield(
200,
body,
std::multimap<std::string, std::string>@{
@{"Content-Type", "application/json"@},
@{"Content-Length", std::to_string(body.size())@}
@}
);
@}
template<typename T>
void send_sse_msg(const std::shared_ptr<restbed::Session> &c, const T &v) @{
if (c->is_closed())
return;
rapidjson::StringBuffer s;
std::memcpy(s.Push(5), "data:", 5);
mrpc::MRPCJWriter writer@{s@};
v >> writer;
std::memcpy(s.Push(2), "\n\n", 2);
const auto body_ptr = s.GetString();
const auto body = restbed::Bytes@{body_ptr, body_ptr+s.GetLength()@};
c->yield(body);
@}
mrpc::MRPCStreamImpl::MRPCStreamImpl(const std::shared_ptr<restbed::Session> &conn) : conn(conn) @{
conn->yield(
200,
std::multimap<std::string, std::string>@{
@{"Cache-Control", "no-cache"@},
@{"Content-Type", "text/event-stream"@}
@}
);
@}
void mrpc::MRPCStreamImpl::close() const noexcept @{ conn->close("data:null\n\n"); @}
bool mrpc::MRPCStreamImpl::is_open() const noexcept @{ return conn->is_open(); @}
@for s in streams_required(rpc) {template<> void MRPCStream<mrpc::@s>::send(const mrpc::@s &v) const noexcept @{ send_sse_msg(conn, v); @}
}
mrpc::MRPCServer::MRPCServer(std::shared_ptr<restbed::Resource> &r) @{
r->set_method_handler("POST", [this](const std::shared_ptr<restbed::Session>& s) @{
const auto req = s->get_request();
const auto body_len = req->get_header("Content-Length", 0);
s->fetch(body_len, [this](const std::shared_ptr<restbed::Session> &s, auto &&body) @{
try @{ msg_handler(s, body); @}
catch (const std::exception &_) @{ s->close(400); @}
@});
@});
@}
void mrpc::MRPCServer::msg_handler(const std::shared_ptr<restbed::Session> __c, const restbed::Bytes &__msg) @{
rapidjson::Document __j;
__j.Parse((const char*)__msg.data(), __msg.size());
if (__j.HasParseError())
throw std::exception@{@};
std::string __service, __method;
json_get(__j, "service", __service); json_get(__j, "method", __method);
auto __data_member = __j.FindMember("data");
if (__data_member == __j.MemberEnd() || !__data_member->value.IsObject())
throw std::exception@{@};
auto &__data = __data_member->value;
@for (si, s) in rpc.services.iter().enumerate() {@if si > 0 { else }else{ }if (__service == "@s.name") @{
@for (mi, m) in s.methods.iter().enumerate() {@if mi > 0 { else }else{ }if (__method == "@m.name") @{
@if m.ret_stream {auto __stream = MRPCStream<@ty_to_str(m.ret.as_ref().unwrap())>@{__c@};
}
@for (name, ty) in m.args.iter().map(|a| (&a.name, ty_to_str(&a.ty))) { @ty @name; json_get<@ty>(__data, "@name", @name);
}
@if m.ret_stream || m.ret.is_none() {@(s.name)_@(m.name)(@call_args(m));}
else {send_msg(__c, @(s.name)_@(m.name)(@call_args(m)));}
@}}
else @{ throw std::exception@{@}; @}
@}}
else @{ throw std::exception@{@}; @}
@}
@}