1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#include "rpc/dispatcher.h"
#include <boost/format.hpp>
#include "rpc/detail/client_error.h"
#include "rpc/this_handler.h"
namespace rpc {
namespace detail {
using detail::response;
void dispatcher::dispatch(RPCLIB_MSGPACK::sbuffer const &msg) {
RPCLIB_MSGPACK::unpacked unpacked;
RPCLIB_MSGPACK::unpack(&unpacked, msg.data(), msg.size());
dispatch(unpacked.get());
}
response dispatcher::dispatch(RPCLIB_MSGPACK::object const &msg,
bool suppress_exceptions) {
switch (msg.via.array.size) {
case 3:
return dispatch_notification(msg, suppress_exceptions);
case 4:
return dispatch_call(msg, suppress_exceptions);
default:
return response::empty();
}
}
response dispatcher::dispatch_call(RPCLIB_MSGPACK::object const &msg,
bool suppress_exceptions) {
call_t the_call;
msg.convert(&the_call);
// TODO: proper validation of protocol (and responding to it)
// auto &&type = std::get<0>(the_call);
// assert(type == 0);
auto &&id = std::get<1>(the_call);
auto &&name = std::get<2>(the_call);
auto &&args = std::get<3>(the_call);
auto it_func = funcs_.find(name);
if (it_func != end(funcs_)) {
LOG_DEBUG("Dispatching call to '{}'", name);
try {
auto result = (it_func->second)(args);
return response::make_result(id, std::move(result));
} catch (rpc::detail::client_error &e) {
return response::make_error(
id, str(boost::format("rpclib: %s") % e.what()));
} catch (std::exception &e) {
if (!suppress_exceptions) {
throw;
}
return response::make_error(
id,
str(boost::format("rpclib: function '%s' (called with %d "
"arg(s)) "
"threw an exception. The exception "
"contained this information: %s.") %
name % args.via.array.size % e.what()));
} catch (rpc::detail::handler_error &) {
// doing nothing, the exception was only thrown to
// return immediately
} catch (rpc::detail::handler_spec_response &) {
// doing nothing, the exception was only thrown to
// return immediately
} catch (...) {
if (!suppress_exceptions) {
throw;
}
return response::make_error(
id,
str(boost::format("rpclib: function '%s' (called with %d "
"arg(s)) threw an exception. The exception "
"is not derived from std::exception. No "
"further information available.") %
name % args.via.array.size));
}
}
return response::make_error(
id, str(boost::format("rpclib: server could not find "
"function '%s' with argument count %d.") %
name % args.via.array.size));
}
response dispatcher::dispatch_notification(RPCLIB_MSGPACK::object const &msg,
bool suppress_exceptions) {
notification_t the_call;
msg.convert(&the_call);
// TODO: proper validation of protocol (and responding to it)
// auto &&type = std::get<0>(the_call);
// assert(type == static_cast<uint8_t>(request_type::notification));
auto &&name = std::get<1>(the_call);
auto &&args = std::get<2>(the_call);
auto it_func = funcs_.find(name);
if (it_func != end(funcs_)) {
LOG_DEBUG("Dispatching call to '{}'", name);
try {
auto result = (it_func->second)(args);
} catch (rpc::detail::handler_error &) {
// doing nothing, the exception was only thrown to
// return immediately
} catch (rpc::detail::handler_spec_response &) {
// doing nothing, the exception was only thrown to
// return immediately
} catch (...) {
if (!suppress_exceptions) {
throw;
}
}
}
return response::empty();
}
void dispatcher::enforce_arg_count(std::string const &func, std::size_t found,
std::size_t expected) {
using detail::client_error;
if (found != expected) {
throw client_error(
client_error::code::wrong_arity,
str(boost::format(
"Function '%s' was called with an invalid number of "
"arguments. Expected: %d, got: %d") %
func % expected % found));
}
}
}
} /* rpc */
|