#pragma once #include "proto/cvmmap_streamer/recorder_control.pb.h" #include #include #include #include #include #include namespace cvmmap_streamer::protocol { enum class RpcErrorCode : std::uint8_t { InvalidRequest, Unsupported, Busy, Internal, }; struct RpcError { RpcErrorCode code{RpcErrorCode::Internal}; std::string message{}; }; struct NatsRequestReplyServerOptions { std::string nats_url{}; std::string instance_name{}; std::string namespace_name{}; std::string ipc_prefix{}; std::string base_name{}; std::string nats_target_key{}; std::string backend{"cvmmap-streamer"}; std::string recording_formats{}; }; class NatsRequestReplyServer { public: explicit NatsRequestReplyServer(NatsRequestReplyServerOptions options); ~NatsRequestReplyServer(); NatsRequestReplyServer(const NatsRequestReplyServer &) = delete; NatsRequestReplyServer &operator=(const NatsRequestReplyServer &) = delete; template void register_proto_endpoint( std::string endpoint_name, std::string subject, std::function(const Request &)> handler) { register_raw_endpoint( std::move(endpoint_name), std::move(subject), [handler = std::move(handler)](std::span payload) { Request request; Response response; if (!request.ParseFromArray( payload.data(), static_cast(payload.size()))) { response.set_code(cvmmap_streamer::proto::RPC_CODE_INVALID_REQUEST); response.set_error_message("failed to parse protobuf request"); return response.SerializeAsString(); } auto handled = handler(request); if (!handled) { response.set_code(to_proto_rpc_code(handled.error().code)); response.set_error_message(handled.error().message); return response.SerializeAsString(); } return handled->SerializeAsString(); }); } [[nodiscard]] bool start(); void stop(); private: struct Endpoint; struct Impl; void register_raw_endpoint( std::string endpoint_name, std::string subject, std::function)> handler); static cvmmap_streamer::proto::RpcCode to_proto_rpc_code(RpcErrorCode code); std::unique_ptr impl_; }; } // namespace cvmmap_streamer::protocol