7 #ifndef CPPWAMP_INTERNAL_WAMPMESSAGE_HPP
8 #define CPPWAMP_INTERNAL_WAMPMESSAGE_HPP
12 #include <type_traits>
14 #include "../error.hpp"
15 #include "../variant.hpp"
16 #include "../wampdefs.hpp"
17 #include "messagetraits.hpp"
31 using RequestKey = std::pair<WampMsgType, RequestId>;
33 static WampMessage parse(
Array&& fields, std::error_code& ec)
36 WampMsgType type = parseMsgType(fields);
37 if (type == WampMsgType::none)
43 auto traits = MessageTraits::lookup(type);
44 if ( fields.size() < traits.minSize ||
45 fields.size() > traits.maxSize )
51 assert(fields.size() <=
52 std::extent<decltype(traits.fieldTypes)>::value);
53 for (
size_t i=0; i<fields.size(); ++i)
55 if (fields[i].typeId() != traits.fieldTypes[i])
63 ec = make_error_code(errc);
64 return WampMessage(type, std::move(fields));
67 WampMessage() : type_(WampMsgType::none) {}
69 WampMessage(WampMsgType type,
Array&& messageFields)
70 : type_(type), fields_(std::move(messageFields))
73 fields_.push_back(
static_cast<Int>(type));
75 fields_.at(0) =
static_cast<Int>(type);
78 void setType(WampMsgType t)
81 fields_.at(0) =
Int(t);
86 auto idPos = traits().idPosition;
88 fields_.at(idPos) = reqId;
91 WampMsgType type()
const {
return type_;}
93 const MessageTraits& traits()
const {
return MessageTraits::lookup(type_);}
95 const char* name()
const
98 auto t = parseMsgType(fields_);
99 return MessageTraits::lookup(t).name;
102 const char* nameOr(
const char* fallback)
const
105 return n ==
nullptr ? fallback : n;
108 size_t size()
const {
return fields_.size();}
110 const Array& fields()
const {
return fields_;}
112 Variant& at(
size_t index) {
return fields_.at(index);}
114 const Variant& at(
size_t index)
const {
return fields_.at(index);}
116 template <
typename T>
117 T& as(
size_t index) {
return fields_.at(index).as<T>();}
119 template <
typename T>
120 const T& as(
size_t index)
const {
return fields_.at(index).as<T>();}
122 template <
typename T>
123 T to(
size_t index)
const {
return fields_.at(index).to<T>();}
125 bool hasRequestId()
const {
return traits().idPosition != 0;}
130 if (type_ != WampMsgType::error)
132 auto idPos = traits().idPosition;
141 RequestKey requestKey()
const
143 WampMsgType reqType = (type_ != WampMsgType::error) ? type_ :
144 static_cast<WampMsgType
>(fields_.at(1).as<
Int>());
145 return std::make_pair(reqType, requestId());
148 WampMsgType repliesTo()
const {
return traits().repliesTo;}
150 bool isProgressiveResponse()
const
152 if (type_ != WampMsgType::result || fields_.size() < 3)
155 const auto& optionsField = fields_.at(2);
156 if (!optionsField.is<
Object>())
159 const auto& optionsMap = optionsField.as<
Object>();
160 auto found = optionsMap.find(
"progress");
161 if (found == optionsMap.end())
164 return found->second.valueOr<
bool>(
false);
169 mutable Array fields_;
172 static WampMsgType parseMsgType(
const Array& fields)
174 auto result = WampMsgType::none;
178 const auto& first = fields.front();
181 using T = std::underlying_type<WampMsgType>::type;
182 static constexpr
auto max = std::numeric_limits<T>::max();
183 auto n = first.to<
Int>();
184 if (n >= 0 && n <= max)
186 result =
static_cast<WampMsgType
>(n);
187 if (!MessageTraits::lookup(result).isValid())
188 result = WampMsgType::none;
197 template <WampMsgType Kind,
unsigned I>
198 struct MessageWithOptions :
public WampMessage
200 static constexpr WampMsgType kind = Kind;
202 static constexpr
unsigned optionsPos = I;
204 const Object& options()
const
206 return fields_.at(optionsPos).template as<Object>();
211 return fields_.at(optionsPos).template as<Object>();
215 explicit MessageWithOptions(
Array&& fields)
216 : WampMessage(kind, std::move(fields))
221 template <WampMsgType Kind,
unsigned I,
unsigned J>
222 struct MessageWithPayload :
public MessageWithOptions<Kind, I>
224 static constexpr
unsigned argsPos = J;
225 static constexpr
unsigned kwargsPos = J + 1;
227 const Array& args() const &
229 if (this->fields_.size() <= argsPos)
230 this->fields_.emplace_back(
Array{});
231 return this->fields_[argsPos].template as<Array>();
236 if (this->fields_.size() <= argsPos)
237 this->fields_.emplace_back(
Array{});
238 return this->fields_[argsPos].template as<Array>();
241 const Object& kwargs()
const
243 if (this->fields_.size() <= kwargsPos)
245 if (this->fields_.size() <= argsPos)
246 this->fields_.emplace_back(
Array{});
247 this->fields_.emplace_back(
Object{});
249 return this->fields_[kwargsPos].template as<Object>();
254 if (this->fields_.size() <= kwargsPos)
256 if (this->fields_.size() <= argsPos)
257 this->fields_.emplace_back(
Array{});
258 this->fields_.emplace_back(
Object{});
260 return this->fields_[kwargsPos].template as<Object>();
264 explicit MessageWithPayload(
Array&& fields)
265 : MessageWithOptions<Kind, I>(std::move(fields))
270 struct HelloMessage :
public MessageWithOptions<WampMsgType::hello, 2>
272 explicit HelloMessage(
String realmUri)
273 : Base({0, std::move(realmUri),
Object{}})
276 const String& realmUri()
const {
return fields_.at(1).as<
String>();}
279 using Base = MessageWithOptions<WampMsgType::hello, 2>;
283 struct ChallengeMessage :
public MessageWithOptions<WampMsgType::challenge, 2>
285 ChallengeMessage() : Base({0,
String{}}) {}
287 const String& authMethod()
const {
return fields_.at(1).as<
String>();}
290 using Base = MessageWithOptions<WampMsgType::challenge, 2>;
294 struct AuthenticateMessage
295 :
public MessageWithOptions<WampMsgType::authenticate, 2>
297 explicit AuthenticateMessage(
String sig,
Object opts = {})
298 : Base({0, std::move(sig), std::move(opts)})
301 const String& signature()
const {
return fields_.at(1).as<
String>();}
304 using Base = MessageWithOptions<WampMsgType::authenticate, 2>;
308 struct WelcomeMessage :
public MessageWithOptions<WampMsgType::welcome, 2>
310 WelcomeMessage() : Base({0, 0,
Object{}}) {}
315 using Base = MessageWithOptions<WampMsgType::welcome, 2>;
319 struct AbortMessage :
public MessageWithOptions<WampMsgType::abort, 1>
322 : Base({0, std::move(opts), std::move(reason)}) {}
324 const String& reasonUri()
const {
return fields_.at(2).as<
String>();}
327 using Base = MessageWithOptions<WampMsgType::abort, 1>;
331 struct GoodbyeMessage :
public MessageWithOptions<WampMsgType::goodbye, 1>
333 explicit GoodbyeMessage(
String reason =
"",
Object opts = {})
334 : Base({0, std::move(opts), std::move(reason)})
336 if (reasonUri().empty())
337 fields_[2] =
String(
"wamp.error.close_realm");
340 const String& reasonUri()
const {
return fields_.at(2).as<
String>();}
343 using Base = MessageWithOptions<WampMsgType::goodbye, 1>;
347 struct ErrorMessage :
public MessageWithPayload<WampMsgType::error, 3, 5>
349 explicit ErrorMessage(
String reason =
"",
Object opts = {})
350 : Base({0, 0, 0, std::move(opts), std::move(reason)})
353 void setRequestInfo(WampMsgType reqType,
RequestId reqId)
const
355 fields_.at(1) =
Int(reqType);
356 fields_.at(2) = reqId;
359 WampMsgType requestType()
const
361 using N = std::underlying_type<WampMsgType>::type;
362 auto n = fields_.at(1).to<N>();
363 return static_cast<WampMsgType
>(n);
368 const String& reasonUri()
const {
return fields_.at(4).as<
String>();}
371 using Base = MessageWithPayload<WampMsgType::error, 3, 5>;
375 struct PublishMessage :
public MessageWithPayload<WampMsgType::publish, 2, 4>
378 : Base({0, 0, std::move(opts), std::move(topic)})
383 const String& topicUri()
const {
return fields_.at(3).as<
String>();}
386 using Base = MessageWithPayload<WampMsgType::publish, 2, 4>;
390 struct PublishedMessage :
public WampMessage
392 static constexpr
auto kind = WampMsgType::published;
394 PublishedMessage() : WampMessage(kind, {0, 0, 0}) {}
405 struct SubscribeMessage :
public MessageWithOptions<WampMsgType::subscribe, 2>
407 explicit SubscribeMessage(
String topic)
408 : Base({0, 0,
Object{}, std::move(topic)})
413 const String& topicUri()
const {
return fields_.at(3).as<
String>();}
416 using Base = MessageWithOptions<WampMsgType::subscribe, 2>;
420 struct SubscribedMessage :
public WampMessage
422 static constexpr
auto kind = WampMsgType::subscribed;
424 SubscribedMessage() : WampMessage(kind, {0, 0, 0}) {}
435 struct UnsubscribeMessage :
public WampMessage
437 static constexpr
auto kind = WampMsgType::unsubscribe;
440 : WampMessage(kind, {0, 0, subId})
452 struct UnsubscribedMessage :
public WampMessage
454 static constexpr
auto kind = WampMsgType::unsubscribed;
456 UnsubscribedMessage() : WampMessage(kind, {0, 0}) {}
462 struct EventMessage :
public MessageWithPayload<WampMsgType::event, 3, 4>
464 EventMessage() : Base({0, 0, 0,
Object{}}) {}
477 using Base = MessageWithPayload<WampMsgType::event, 3, 4>;
481 struct CallMessage :
public MessageWithPayload<WampMsgType::call, 2, 4>
484 : Base({0, 0, std::move(opts), std::move(uri)})
489 const String& procedureUri()
const {
return fields_.at(3).as<
String>();}
492 using Base = MessageWithPayload<WampMsgType::call, 2, 4>;
496 struct RegisterMessage :
public MessageWithOptions<WampMsgType::enroll, 2>
499 : Base({0, 0, std::move(opts), std::move(uri)})
504 const String& procedureUri()
const {
return fields_.at(3).as<
String>();}
507 using Base = MessageWithOptions<WampMsgType::enroll, 2>;
511 struct RegisteredMessage :
public WampMessage
513 static constexpr
auto kind = WampMsgType::registered;
515 RegisteredMessage() : WampMessage(kind, {0, 0, 0}) {}
526 struct UnregisterMessage :
public WampMessage
528 static constexpr
auto kind = WampMsgType::unregister;
531 : WampMessage(kind, {0, 0, regId})
543 struct UnregisteredMessage :
public WampMessage
545 static constexpr
auto kind = WampMsgType::unregistered;
547 UnregisteredMessage() : WampMessage(kind, {0, 0}) {}
553 struct InvocationMessage :
554 public MessageWithPayload<WampMsgType::invocation, 3, 4>
556 InvocationMessage() : Base({0, 0, 0,
Object{}}) {}
566 using Base = MessageWithPayload<WampMsgType::invocation, 3, 4>;
570 struct YieldMessage :
public MessageWithPayload<WampMsgType::yield, 2, 3>
573 : Base({0, reqId, std::move(opts)})
579 using Base = MessageWithPayload<WampMsgType::yield, 2, 3>;
583 struct ResultMessage :
public MessageWithPayload<WampMsgType::result, 2, 3>
585 explicit ResultMessage(
Object opts = {}) : Base({0, 0, std::move(opts)}) {}
589 YieldMessage& transformToYield()
591 setType(WampMsgType::yield);
592 auto& base =
static_cast<WampMessage&
>(*this);
593 return static_cast<YieldMessage&
>(base);
597 using Base = MessageWithPayload<WampMsgType::result, 2, 3>;
601 struct CancelMessage :
public MessageWithOptions<WampMsgType::cancel, 2>
604 : Base({0, reqId, std::move(opts)})
610 using Base = MessageWithOptions<WampMsgType::cancel, 2>;
614 struct InterruptMessage :
public MessageWithOptions<WampMsgType::interrupt, 2>
617 : Base({0, reqId, std::move(opts)})
623 using Base = MessageWithOptions<WampMsgType::interrupt, 2>;
627 template <
typename TDerived>
628 TDerived& message_cast(WampMessage& msg)
630 assert(msg.type() == TDerived::kind);
631 return static_cast<TDerived&
>(msg);
635 template <
typename TDerived>
636 const TDerived& message_cast(
const WampMessage& msg)
638 assert(msg.type() == TDerived::kind);
639 return static_cast<const TDerived&
>(msg);
646 #endif // CPPWAMP_INTERNAL_WAMPMESSAGE_HPP