25 #ifndef _MESSAGEROUTER_HPP_ 26 #define _MESSAGEROUTER_HPP_ 28 #include "amps/ampscrc.hpp" 29 #include "amps/util.hpp" 38 template <
typename Func,
typename Object>
45 std::function<void(Object)> _callable;
50 static void noOpHandler(Object) {;}
52 typedef Func FunctionType;
56 , _callable(
Handler<Func, Object>::noOpHandler)
67 : _func(func_), _userData(userData_)
68 , _callable(noOpHandler)
76 : _func(orig_._func), _userData(orig_._userData)
77 , _callable(orig_._callable)
78 , _isValid(orig_._isValid)
85 : _func(NULL), _userData(NULL), _callable(callback_), _isValid(true)
88 void invoke(Object message)
92 _func(message, _userData);
105 _userData = rhs_._userData;
106 _callable = rhs_._callable;
107 _isValid = rhs_._isValid;
112 bool isValid(
void)
const 116 Func
function(void)
const 120 void* userData(
void)
const 128 typedef void(*MessageHandlerFunc)(
const Message&,
void* userData);
138 MessageHandler _emptyMessageHandler;
139 typedef amps_uint64_t (*CRCFunction)(
const char*, size_t, amps_uint64_t);
144 MessageHandler _messageHandler;
145 unsigned _requestedAcks, _systemAcks, _terminationAck;
147 MessageRoute() : _requestedAcks(0), _systemAcks(0), _terminationAck(0) {;}
148 MessageRoute(
const MessageRoute& rhs_) :
149 _messageHandler(rhs_._messageHandler),
150 _requestedAcks (rhs_._requestedAcks),
151 _systemAcks (rhs_._systemAcks),
152 _terminationAck(rhs_._terminationAck)
154 const MessageRoute& operator=(
const MessageRoute& rhs_)
156 _messageHandler = rhs_._messageHandler;
157 _requestedAcks = rhs_._requestedAcks;
158 _systemAcks = rhs_._systemAcks;
159 _terminationAck = rhs_._terminationAck;
162 MessageRoute(MessageHandler messageHandler_,
unsigned requestedAcks_,
163 unsigned systemAcks_, Message::Command::Type commandType_) :
164 _messageHandler(messageHandler_),
165 _requestedAcks(requestedAcks_),
166 _systemAcks(systemAcks_),
169 bool isSubscribeOrSOW = commandType_ & Message::Command::Subscribe
170 || commandType_ & Message::Command::DeltaSubscribe
171 || commandType_ & Message::Command::SOWAndSubscribe
172 || commandType_ & Message::Command::SOWAndDeltaSubscribe
173 || commandType_ & Message::Command::SOW;
174 if (!isSubscribeOrSOW)
178 unsigned bitCounter = (requestedAcks_ | systemAcks_) >> 1;
180 while (bitCounter > 0)
183 _terminationAck <<= 1;
186 else if (commandType_ == Message::Command::SOW)
188 if (requestedAcks_ >= Message::AckType::Completed)
192 unsigned bitCounter = (requestedAcks_ | systemAcks_) >> 1;
194 while (bitCounter > 0)
197 _terminationAck <<= 1;
202 _terminationAck = Message::AckType::Completed;
208 unsigned deliverAck(
const Message& message_,
unsigned ackType_)
210 if ( (_requestedAcks & ackType_) == 0)
216 _messageHandler.invoke(message_);
218 catch (std::exception& ex)
220 std::cerr << ex.what() << std::endl;
224 bool isTerminationAck(
unsigned ackType_)
const 226 return ackType_ == _terminationAck;
228 unsigned deliverData(
const Message& message_)
230 _messageHandler.invoke(message_);
233 const MessageHandler& getMessageHandler()
const 235 return _messageHandler;
237 MessageHandler& getMessageHandler()
239 return _messageHandler;
245 : _previousCommandId(0),
246 _lookupGenerationCount(0),
250 _crc = AMPS::CRC<0>::crcNoSSE;
252 if (AMPS::CRC<0>::isSSE42Enabled())
254 _crc = AMPS::CRC<0>::crc;
258 _crc = AMPS::CRC<0>::crcNoSSE;
264 unsigned requestedAcks_,
unsigned systemAcks_, Message::Command::Type commandType_)
266 Lock<Mutex> lock(_lock);
267 RouteMap::iterator i = _routes.find(commandId_);
268 if (i == _routes.end())
270 _routes[commandId_.
deepCopy()] = MessageRoute(messageHandler_, requestedAcks_, systemAcks_, commandType_);
275 bool isSubscribe = commandType_ & Message::Command::Subscribe
276 || commandType_ & Message::Command::DeltaSubscribe
277 || commandType_ & Message::Command::SOWAndSubscribe
278 || commandType_ & Message::Command::SOWAndDeltaSubscribe;
282 && !i->second.isTerminationAck(0))
284 void* routeData = i->second.getMessageHandler().userData();;
285 i->second = MessageRoute(messageHandler_, requestedAcks_, systemAcks_, commandType_);
288 Unlock<Mutex> u(_lock);
289 amps_invoke_remove_route_function(routeData);
298 bool removeRoute(
const Field& commandId_)
300 Lock<Mutex> lock(_lock);
301 RouteMap::iterator i = _routes.find(commandId_);
302 if (i == _routes.end())
306 return _removeRoute(i);
311 AMPS_FETCH_ADD(&_generationCount, 1);
312 std::vector<void*> removeData;
314 Lock<Mutex> lock(_lock);
315 for (RouteMap::iterator i = _routes.begin(); i != _routes.end(); ++i)
321 void* data = i->second.getMessageHandler().userData();
322 removeData.push_back(data);
327 for (
size_t i = 0; i < removeData.size(); ++i)
329 amps_invoke_remove_route_function(removeData[i]);
334 bool hasRoute(
const Field& commandId_)
const 336 Lock<Mutex> lock(_lock);
337 RouteMap::const_iterator it = _routes.find(commandId_);
338 return it != _routes.end();
342 bool getRoute(
const Field& commandId_, MessageHandler& result_)
const 344 Lock<Mutex> lock(_lock);
345 RouteMap::const_iterator it = _routes.find(commandId_);
346 if (it != _routes.end())
348 result_ = it->second.getMessageHandler();
353 result_ = _emptyMessageHandler;
365 MessageHandler handler;
367 class RouteCache :
public std::vector<RouteLookup>
369 RouteCache(
const RouteCache&);
370 void operator=(
const RouteCache&);
373 : _generationCount(0),
377 void invalidateCache(
void)
379 #if __cplusplus >= 201100L || _MSC_VER >= 1900 380 _generationCount.store(0);
382 _generationCount = 0;
387 #if __cplusplus >= 201100L || _MSC_VER >= 1900 388 void invalidateCache(
const std::atomic<uint_fast64_t>& generationCount_, amps_uint64_t hashVal_)
390 _generationCount.store(generationCount_);
395 void invalidateCache(
const AMPS_ATOMIC_TYPE& generationCount_, amps_uint64_t hashVal_)
397 _generationCount = generationCount_;
403 #if __cplusplus >= 201100L || _MSC_VER >= 1900 404 bool isCacheHit(
const std::atomic<uint_fast64_t>& generationCount_, amps_uint64_t hashVal_)
const 406 return _generationCount == generationCount_ && _hashVal == hashVal_;
409 bool isCacheHit(
const AMPS_ATOMIC_TYPE& generationCount_, amps_uint64_t hashVal_)
const 411 return _generationCount == generationCount_ && _hashVal == hashVal_;
416 #if __cplusplus >= 201100L || _MSC_VER >= 1900 417 std::atomic<uint_fast64_t> _generationCount;
419 AMPS_ATOMIC_TYPE _generationCount;
421 amps_uint64_t _hashVal;
427 size_t parseRoutes(
const Field& commandIdList_, RouteCache& result_)
432 amps_uint64_t listHash = _crc(commandIdList_.
data(), commandIdList_.
len(), 0);
433 if (result_.isCacheHit(_generationCount, listHash))
435 return result_.size();
437 result_.invalidateCache(_generationCount, listHash);
440 Lock<Mutex> lockGuard(_lock);
441 size_t resultCount = 0;
442 const char* pStart = commandIdList_.
data();
443 for (
const char* p = pStart, *e = commandIdList_.
len() + pStart; p < e;
446 const char* delimiter = p;
447 while (delimiter != e && *delimiter !=
',')
452 result_.emplace_back(RouteLookup());
455 RouteLookup& result = result_[resultCount];
456 result.idOffset = (size_t)(p - pStart);
457 result.idLength = (size_t)(delimiter - p);
459 RouteMap::const_iterator it = _routes.find(subId);
460 if (it != _routes.end())
462 result.handler = it->second.getMessageHandler();
466 result.handler = _emptyMessageHandler;
472 unsigned deliverAck(
const Message& ackMessage_,
unsigned ackType_)
475 unsigned messagesDelivered = 0;
482 messagesDelivered += _deliverAck(ackMessage_, ackType_, key);
485 !key.
empty() && messagesDelivered == 0)
487 messagesDelivered += _deliverAck(ackMessage_, ackType_, key);
490 !key.
empty() && messagesDelivered == 0)
492 messagesDelivered += _deliverAck(ackMessage_, ackType_, key);
494 return messagesDelivered;
498 unsigned deliverData(
const Message& dataMessage_,
const Field& commandId_)
500 unsigned messagesDelivered = 0;
501 amps_uint64_t hval = _crc(commandId_.
data(), commandId_.
len(), 0);
502 if (_previousCommandId == hval &&
503 _lookupGenerationCount == _generationCount)
505 messagesDelivered += _previousHandler.deliverData(dataMessage_);
509 Lock<Mutex> lock(_lock);
510 RouteMap::iterator it = _routes.find(commandId_);
511 if (it != _routes.end())
513 _previousCommandId = hval;
514 #if __cplusplus >= 201100L || _MSC_VER >= 1900 515 _lookupGenerationCount.store(_generationCount);
517 _lookupGenerationCount = _generationCount;
519 _previousHandler = it->second;
520 messagesDelivered += it->second.deliverData(dataMessage_);
523 return messagesDelivered;
526 void invalidateCache(
void)
528 _previousCommandId = 0;
531 void unsubscribeAll(
void)
533 AMPS_FETCH_ADD(&_generationCount, 1);
534 std::vector<Field> removeIds;
535 std::vector<void*> removeData;
536 Lock<Mutex> lock(_lock);
537 for (RouteMap::iterator it = _routes.begin(); it != _routes.end(); ++it)
539 if (it->second.isTerminationAck(0))
541 removeIds.push_back(it->first);
542 removeData.push_back(it->second.getMessageHandler().userData());
545 for (
size_t i = 0; i < removeIds.size(); ++i)
548 RouteMap::iterator it = _routes.find(removeIds[i]);
554 Unlock<Mutex> u(_lock);
555 for (
size_t i = 0; i < removeData.size(); ++i)
557 amps_invoke_remove_route_function(removeData[i]);
562 typedef std::map<Field, MessageRoute> RouteMap;
566 MessageRoute _previousHandler;
567 amps_uint64_t _previousCommandId;
568 #if __cplusplus >= 201100L || _MSC_VER >= 1900 569 mutable std::atomic<uint_fast64_t> _lookupGenerationCount;
570 mutable std::atomic<uint_fast64_t> _generationCount;
572 mutable AMPS_ATOMIC_TYPE _lookupGenerationCount;
573 mutable AMPS_ATOMIC_TYPE _generationCount;
579 unsigned _deliverAck(
const Message& ackMessage_,
unsigned ackType_,
Field& commandId_)
581 Lock<Mutex> lock(_lock);
582 unsigned messagesDelivered = 0;
583 RouteMap::iterator it = _routes.find(commandId_);
584 if (it != _routes.end())
586 MessageRoute& route = it->second;
587 messagesDelivered += route.deliverAck(ackMessage_, ackType_);
588 if (route.isTerminationAck(ackType_))
594 return messagesDelivered;
596 unsigned _processAckForRemoval(
unsigned ackType_,
Field& commandId_)
598 Lock<Mutex> lock(_lock);
599 RouteMap::iterator it = _routes.find(commandId_);
600 if (it != _routes.end())
602 MessageRoute& route = it->second;
603 if (route.isTerminationAck(ackType_))
613 bool _removeRoute(RouteMap::iterator& it_)
616 AMPS_FETCH_ADD(&_generationCount, 1);
618 Field f = it_->first;
619 void* routeData = it_->second.getMessageHandler().userData();
624 Unlock<Mutex> u(_lock);
625 amps_invoke_remove_route_function(routeData);
Defines the AMPS::Message class and related classes.
Field getSubscriptionId() const
Retrieves the value of the SubscriptionId header of the Message as a Field which references the under...
Definition: Message.hpp:1469
Message encapsulates a single message sent to or received from an AMPS server, and provides methods f...
Definition: Message.hpp:519
void clear()
Deletes the data associated with this Field, should only be used on Fields that were created as deepC...
Definition: Field.hpp:266
const char * data() const
Returns the (non-null-terminated) data underlying this field.
Definition: Field.hpp:279
Handler(const T &callback_)
Constructor for use with a standard c++ library function object.
Definition: MessageRouter.hpp:84
Field getCommand() const
Retrieves the value of the Command header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1237
Field getCommandId() const
Retrieves the value of the CommandId header of the Message as a Field which references the underlying...
Definition: Message.hpp:1344
bool empty() const
Returns 'true' if empty, 'false' otherwise.
Definition: Field.hpp:129
size_t len() const
Returns the length of the data underlying this field.
Definition: Field.hpp:286
This class multiplexes messages from AMPS to multiple subscribers and uses the stream of acks from AM...
Definition: MessageRouter.hpp:135
Field represents the value of a single field in a Message.
Definition: Field.hpp:87
Handler(Func func_, void *userData_)
Constructor for use with a bare function pointer.
Definition: MessageRouter.hpp:66
Wrapper for callback functions in AMPS.
Definition: MessageRouter.hpp:39
An iterable object representing the results of an AMPS subscription and/or query. ...
Definition: ampsplusplus.hpp:5207
Handler()
Null constructor – no function is wrapped.
Definition: MessageRouter.hpp:55
Field getQueryID() const
Retrieves the value of the QueryID header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1459
void deepCopy(const Field &orig_)
Makes self a deep copy of the original field.
Definition: Field.hpp:219
Handler(const Handler &orig_)
Copy constructor.
Definition: MessageRouter.hpp:75
Definition: AMPSException.hpp:32