@use crate::data::RPC; @use crate::generators::cpp_s::*; @use super::cpp_server_json_cxx; @(header_name: &str, rpc: &RPC) #include "@header_name" #include #include #include using namespace mrpc; @:cpp_server_json_cxx(rpc) template void send_msg(const std::shared_ptr &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@{ @{"Content-Type", "application/json"@}, @{"Content-Length", std::to_string(body.size())@} @} ); @} template void send_sse_msg(const std::shared_ptr &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 &conn) : conn(conn) @{ conn->yield( 200, std::multimap@{ @{"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<@s>::send(const @s &v) const noexcept @{ send_sse_msg(conn, v); @} } mrpc::MRPCServer::MRPCServer(std::shared_ptr &r) @{ r->set_method_handler("POST", [this](const std::shared_ptr& 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 &s, auto &&body) @{ try @{ msg_handler(s, body); @} catch (const std::exception &_) @{ s->close(400); @} @}); @}); @} void mrpc::MRPCServer::msg_handler(const std::shared_ptr __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; __service << json_get(__j, "service"); __method << json_get(__j, "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; @name << json_get(__data, "@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@{@}; @} @} @}