CARLA
Loading...
Searching...
No Matches
rpc/Server.h
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#pragma once
8
9#include "carla/MoveHandler.h"
10#include "carla/Time.h"
11#include "carla/rpc/Metadata.h"
12#include "carla/rpc/Response.h"
13
14#include <boost/asio/io_context.hpp>
15#include <boost/asio/post.hpp>
16
17#include <rpc/server.h>
18
19#include <chrono>
20#include <atomic>
21#include <future>
22#include <stdexcept>
23
24namespace carla {
25namespace rpc {
26
27 // ===========================================================================
28 // -- Server -----------------------------------------------------------------
29 // ===========================================================================
30
31 /// An RPC server in which functions can be bind to run synchronously or
32 /// asynchronously.
33 ///
34 /// Use `AsyncRun` to start the worker threads, and use `SyncRunFor` to
35 /// run a slice of work in the caller's thread.
36 ///
37 /// Functions that are bind using `BindAsync` will run asynchronously in the
38 /// worker threads. Functions that are bind using `BindSync` will run within
39 /// `SyncRunFor` function.
40 class Server {
41 public:
42
43 template <typename... Args>
44 explicit Server(Args &&... args);
45
46 template <typename FunctorT>
47 void BindSync(const std::string &name, FunctorT &&functor);
48
49 template <typename FunctorT>
50 void BindAsync(const std::string &name, FunctorT &&functor);
51
52 void AsyncRun(size_t worker_threads) {
53 _server.async_run(worker_threads);
54 }
55
56 void SyncRunFor(time_duration duration) {
57 #ifdef LIBCARLA_INCLUDED_FROM_UE4
59 TRACE_CPUPROFILER_EVENT_SCOPE_STR(__FUNCTION__);
61 #endif // LIBCARLA_INCLUDED_FROM_UE4
62 _sync_io_context.restart();
63 _sync_io_context.run_for(duration.to_chrono());
64 }
65
66 /// @warning does not stop the game thread.
67 void Stop() {
69 _server.stop();
70 }
71
72 private:
73
74 boost::asio::io_context _sync_io_context;
75
76 ::rpc::server _server;
77 std::atomic_bool _shutdown_in_progress{false};
78 };
79
80 // ===========================================================================
81 // -- Server implementation --------------------------------------------------
82 // ===========================================================================
83
84namespace detail {
85
86 template <typename T>
87 struct FunctionWrapper : FunctionWrapper<decltype(&T::operator())> {};
88
89 template <typename C, typename R, typename... Args>
90 struct FunctionWrapper<R (C::*)(Args...)> : FunctionWrapper<R (*)(Args...)> {};
91
92 template <typename C, typename R, typename... Args>
93 struct FunctionWrapper<R (C::*)(Args...) const> : FunctionWrapper<R (*)(Args...)> {};
94
95 template<class T>
96 struct FunctionWrapper<T &> : public FunctionWrapper<T> {};
97
98 template<class T>
99 struct FunctionWrapper<T &&> : public FunctionWrapper<T> {};
100
101 template <typename R, typename... Args>
102 struct FunctionWrapper<R (*)(Args...)> {
103
104 /// Wraps @a functor into a function type with equivalent signature. The
105 /// wrap function returned. When called, posts @a functor into the
106 /// io_context; if the client called this method synchronously, waits for
107 /// the posted task to finish, otherwise returns immediately.
108 ///
109 /// This way, no matter from which thread the wrap function is called, the
110 /// @a functor provided is always called from the context of the io_context.
111 /// I.e., we can use the io_context to run tasks on a specific thread (e.g.
112 /// game thread).
113 template <typename FuncT>
114 static auto WrapSyncCall(std::atomic_bool &shutdown_in_progress, boost::asio::io_context &io, FuncT &&functor) {
115 return [&shutdown_in_progress, &io, functor=std::forward<FuncT>(functor)](Metadata metadata, Args... args) -> R {
116 auto task = std::packaged_task<R()>([functor=std::move(functor), args...]() {
117 return functor(args...);
118 });
119 if (metadata.IsResponseIgnored()) {
120 // Post task and ignore result.
121 boost::asio::post(io, MoveHandler(task));
122 return R();
123 } else {
124 // Post task and wait for result.
125 auto result = task.get_future();
126 boost::asio::post(io, MoveHandler(task));
127 std::future_status status;
128 do {
129 status = result.wait_for(std::chrono::milliseconds(100));
130 } while (!shutdown_in_progress && (status != std::future_status::ready));
131 if (status == std::future_status::ready) {
132 return result.get();
133 } else {
134 throw std::runtime_error("RPC server is shutting down");
135 }
136 }
137 };
138 }
139
140 /// Wraps @a functor into a function type with equivalent signature that
141 /// handles the metadata sent by the client. If the client called this
142 /// method asynchronously, the result is ignored.
143 template <typename FuncT>
144 static auto WrapAsyncCall(FuncT &&functor) {
145 return [functor=std::forward<FuncT>(functor)](::carla::rpc::Metadata metadata, Args... args) -> R {
146 if (metadata.IsResponseIgnored()) {
147 functor(args...);
148 return R();
149 } else {
150 return functor(args...);
151 }
152 };
153 }
154 };
155
156} // namespace detail
157
158 template <typename ... Args>
159 inline Server::Server(Args && ... args)
160 : _server(std::forward<Args>(args) ...) {
161 _server.suppress_exceptions(true);
162 }
163
164 template <typename FunctorT>
165 inline void Server::BindSync(const std::string &name, FunctorT &&functor) {
166 using Wrapper = detail::FunctionWrapper<FunctorT>;
167 _server.bind(
168 name,
169 Wrapper::WrapSyncCall(_shutdown_in_progress, _sync_io_context, std::forward<FunctorT>(functor)));
170 }
171
172 template <typename FunctorT>
173 inline void Server::BindAsync(const std::string &name, FunctorT &&functor) {
174 using Wrapper = detail::FunctionWrapper<FunctorT>;
175 _server.bind(
176 name,
177 Wrapper::WrapAsyncCall(std::forward<FunctorT>(functor)));
178 }
179
180} // namespace rpc
181} // namespace carla
carla::rpc::Response< T > R
Metadata of an RPC function call.
Definition Metadata.h:15
An RPC server in which functions can be bind to run synchronously or asynchronously.
Definition rpc/Server.h:40
::rpc::server _server
Definition rpc/Server.h:76
Server(Args &&... args)
Definition rpc/Server.h:159
std::atomic_bool _shutdown_in_progress
Definition rpc/Server.h:77
void SyncRunFor(time_duration duration)
Definition rpc/Server.h:56
void AsyncRun(size_t worker_threads)
Definition rpc/Server.h:52
boost::asio::io_context _sync_io_context
Definition rpc/Server.h:74
void BindSync(const std::string &name, FunctorT &&functor)
Definition rpc/Server.h:165
void BindAsync(const std::string &name, FunctorT &&functor)
Definition rpc/Server.h:173
Positive time duration up to milliseconds resolution.
Definition Time.h:20
constexpr auto to_chrono() const
Definition Time.h:54
This file contains definitions of common data structures used in traffic manager.
auto MoveHandler(FunctorT &&func)
Hack to trick asio into accepting move-only handlers, if the handler were actually copied it would re...
Definition MoveHandler.h:33
static auto WrapSyncCall(std::atomic_bool &shutdown_in_progress, boost::asio::io_context &io, FuncT &&functor)
Wraps functor into a function type with equivalent signature.
Definition rpc/Server.h:114
static auto WrapAsyncCall(FuncT &&functor)
Wraps functor into a function type with equivalent signature that handles the metadata sent by the cl...
Definition rpc/Server.h:144