25 #ifndef _AMPSPLUSPLUS_H_
26 #define _AMPSPLUSPLUS_H_
28 #include "amps/ampsver.h"
47 #include <sys/atomic.h>
49 #include "amps/BookmarkStore.hpp"
50 #include "amps/MessageRouter.hpp"
51 #include "amps/util.hpp"
52 #include "amps/ampscrc.hpp"
53 #if __cplusplus >= 201100L || _MSC_VER >= 1900
57 #ifndef AMPS_TESTING_SLOW_MESSAGE_STREAM
58 #define AMPS_TESTING_SLOW_MESSAGE_STREAM
86 #define AMPS_MEMORYBUFFER_DEFAULT_BUFFERS 10
87 #define AMPS_MEMORYBUFFER_DEFAULT_LENGTH 40960
88 #define AMPS_SUBSCRIPTION_MANAGER_DEFAULT_TIMEOUT 0
89 #define AMPS_HACLIENT_TIMEOUT_DEFAULT 10000
90 #define AMPS_HACLIENT_RECONNECT_DEFAULT 200
91 #define AMPS_DEFAULT_COMMAND_TIMEOUT 5000
92 #define AMPS_DEFAULT_TOP_N -1
93 #define AMPS_DEFAULT_BATCH_SIZE 10
94 #define AMPS_NUMBER_BUFFER_LEN 20
95 #define AMPS_DEFAULT_QUEUE_ACK_TIMEOUT 1000
97 #if defined(_M_X64) || defined(__x86_64) || defined(_WIN64)
106 typedef std::map<std::string, std::string> ConnectionInfo;
109 inline std::string asString(Type x_)
111 std::ostringstream os;
117 size_t convertToCharArray(
char* buf_, amps_uint64_t seqNo_)
119 size_t pos = AMPS_NUMBER_BUFFER_LEN;
120 for (
int i = 0; i < AMPS_NUMBER_BUFFER_LEN; ++i)
124 buf_[--pos] = (char)(seqNo_ % 10 +
'0');
133 size_t convertToCharArray(
char* buf_,
unsigned long seqNo_)
135 size_t pos = AMPS_NUMBER_BUFFER_LEN;
136 for (
int i = 0; i < AMPS_NUMBER_BUFFER_LEN; ++i)
140 buf_[--pos] = (char)(seqNo_ % 10 +
'0');
154 static const char* duplicate()
158 static const char* badFilter()
162 static const char* badRegexTopic()
164 return "bad regex topic";
166 static const char* subscriptionAlreadyExists()
168 return "subscription already exists";
170 static const char* nameInUse()
172 return "name in use";
174 static const char* authFailure()
176 return "auth failure";
178 static const char* notEntitled()
180 return "not entitled";
182 static const char* authDisabled()
184 return "authentication disabled";
186 static const char* subidInUse()
188 return "subid in use";
190 static const char* noTopic()
208 virtual void exceptionThrown(
const std::exception&)
const {;}
214 #define AMPS_CALL_EXCEPTION_WRAPPER(x) \
219 catch (std::exception& stdEx_)\
223 _exceptionListener->exceptionThrown(stdEx_);\
247 #define AMPS_CALL_EXCEPTION_WRAPPER_2(me,x) \
250 while(me->_connected)\
257 catch(MessageStreamFullException&)\
261 me->checkAndSendHeartbeat(false);\
263 catch (std::exception& stdEx_)\
267 me->_exceptionListener->exceptionThrown(stdEx_);\
278 catch (std::exception& stdEx_)\
282 me->_exceptionListener->exceptionThrown(stdEx_);\
306 #define AMPS_CALL_EXCEPTION_WRAPPER_STREAM_FULL_2(me, x)\
307 while(me->_connected)\
314 catch(MessageStreamFullException&)\
318 me->checkAndSendHeartbeat(false);\
320 catch (std::exception& stdEx_)\
324 me->_exceptionListener->exceptionThrown(stdEx_);\
335 #define AMPS_CALL_EXCEPTION_WRAPPER_2(me,x) \
338 while(me->_connected)\
345 catch(MessageStreamFullException& msfEx_)\
349 me->checkAndSendHeartbeat(false);\
351 catch (std::exception& stdEx_)\
355 me->_exceptionListener->exceptionThrown(stdEx_);\
366 catch (std::exception& stdEx_)\
370 me->_exceptionListener->exceptionThrown(stdEx_);\
394 #define AMPS_CALL_EXCEPTION_WRAPPER_STREAM_FULL_2(me, x)\
395 while(me->_connected)\
402 catch(MessageStreamFullException& msfEx_)\
406 me->checkAndSendHeartbeat(false);\
408 catch (std::exception& stdEx_)\
412 me->_exceptionListener->exceptionThrown(stdEx_);\
424 #define AMPS_UNHANDLED_EXCEPTION(ex) \
427 _exceptionListener->exceptionThrown(ex);\
434 #define AMPS_UNHANDLED_EXCEPTION_2(me,ex) \
437 me->_exceptionListener->exceptionThrown(ex);\
478 static const unsigned Subscribe = 1;
479 static const unsigned SOW = 2;
480 static const unsigned NeedsSequenceNumber = 4;
481 static const unsigned ProcessedAck = 8;
482 static const unsigned StatsAck = 16;
483 void init(Message::Command::Type command_)
492 void init(
const std::string& command_)
501 void init(
const char* command_,
size_t commandLen_)
513 if (!(command & Message::Command::NoDataCommands))
516 if (command == Message::Command::Subscribe ||
517 command == Message::Command::SOWAndSubscribe ||
518 command == Message::Command::DeltaSubscribe ||
519 command == Message::Command::SOWAndDeltaSubscribe)
524 if (command == Message::Command::SOW
525 || command == Message::Command::SOWAndSubscribe
526 || command == Message::Command::SOWAndDeltaSubscribe)
533 if (command == Message::Command::SOW)
538 _flags |= ProcessedAck;
540 else if (command == Message::Command::SOWDelete)
543 _flags |= ProcessedAck;
544 _flags |= NeedsSequenceNumber;
546 else if (command == Message::Command::Publish
547 || command == Message::Command::DeltaPublish)
549 _flags |= NeedsSequenceNumber;
551 else if (command == Message::Command::StopTimer)
568 Command(
const char* command_,
size_t commandLen_)
570 init(command_, commandLen_);
594 init(command_, commandLen_);
688 _message.
setTopic(topic_, topicLen_);
818 std::ostringstream os;
823 amps_uint64_t getSequence()
const
839 _message.
setData(data_, dataLen_);
859 if (topN_ != (
unsigned)AMPS_DEFAULT_TOP_N)
876 _batchSize = batchSize_;
898 if (ackType_ ==
"processed")
900 _flags |= ProcessedAck;
902 else if (ackType_ ==
"stats")
912 if (ackType_.find(
"processed") != std::string::npos)
914 _flags |= ProcessedAck;
918 _flags &= ~ProcessedAck;
920 if (ackType_.find(
"stats") != std::string::npos)
934 if (ackType_ & Message::AckType::Processed)
936 _flags |= ProcessedAck;
940 _flags &= ~ProcessedAck;
942 if (ackType_ & Message::AckType::Stats)
967 unsigned getTimeout(
void)
const
971 unsigned getBatchSize(
void)
const
975 bool isSubscribe(
void)
const
977 return _flags & Subscribe;
979 bool isSow(
void)
const
981 return (_flags & SOW) != 0;
983 bool hasProcessedAck(
void)
const
985 return (_flags & ProcessedAck) != 0;
987 bool hasStatsAck(
void)
const
989 return (_flags & StatsAck) != 0;
991 bool needsSequenceNumber(
void)
const
993 return (_flags & NeedsSequenceNumber) != 0;
999 typedef void(*DisconnectHandlerFunc)(
Client&,
void* userData);
1016 virtual std::string
authenticate(
const std::string& userName_,
const std::string& password_) = 0;
1024 virtual std::string
retry(
const std::string& userName_,
const std::string& password_) = 0;
1031 virtual void completed(
const std::string& userName_,
const std::string& password_,
const std::string& reason_) = 0;
1043 std::string
authenticate(
const std::string& ,
const std::string& password_)
1050 std::string
retry(
const std::string& ,
const std::string& )
1052 throw AuthenticationException(
"retry not implemented by DefaultAuthenticator.");
1055 void completed(
const std::string& ,
const std::string& ,
const std::string& ) {;}
1091 typedef bool (*PublishStoreResizeHandler)(
Store store_,
1106 : _resizeHandler(NULL)
1107 , _resizeHandlerData(NULL)
1108 , _errorOnPublishGap(errorOnPublishGap_)
1162 return AMPS_UNSET_INDEX;
1169 return AMPS_UNSET_SEQUENCE;
1194 _resizeHandler = handler_;
1195 _resizeHandlerData = userData_;
1200 return _resizeHandler;
1203 bool callResizeHandler(
size_t newSize_);
1205 inline virtual void setErrorOnPublishGap(
bool errorOnPublishGap_)
1207 _errorOnPublishGap = errorOnPublishGap_;
1210 inline virtual bool getErrorOnPublishGap()
const
1212 return _errorOnPublishGap;
1217 void* _resizeHandlerData;
1218 bool _errorOnPublishGap;
1225 RefHandle<StoreImpl> _body;
1229 Store(
const Store& rhs) : _body(rhs._body) {;}
1241 return _body.get().store(message_);
1252 _body.get().discardUpTo(index_);
1261 _body.get().replay(replayer_);
1273 return _body.get().replaySingle(replayer_, index_);
1282 return _body.get().unpersistedCount();
1290 return _body.isValid();
1303 return _body.get().flush(timeout_);
1311 return _body.get().getLowestUnpersisted();
1319 return _body.get().getLastPersisted();
1334 _body.get().setResizeHandler(handler_, userData_);
1339 return _body.get().getResizeHandler();
1348 _body.get().setErrorOnPublishGap(errorOnPublishGap_);
1357 return _body.get().getErrorOnPublishGap();
1365 if (_body.isValid())
1367 return &_body.get();
1392 const char* reason_,
size_t reasonLength_) = 0;
1396 inline bool StoreImpl::callResizeHandler(
size_t newSize_)
1400 return _resizeHandler(
Store(
this), newSize_, _resizeHandlerData);
1414 long* timeoutp = (
long*)data_;
1422 store_.
flush(*timeoutp);
1425 catch (
const TimedOutException&)
1427 catch (
const TimedOutException& e)
1454 unsigned requestedAckTypes_,
1455 const AMPSException& exception_) = 0;
1473 unsigned requestedAckTypes_) = 0;
1491 _failedResubscribeHandler = handler_;
1494 std::shared_ptr<FailedResubscribeHandler> _failedResubscribeHandler;
1505 typedef enum { Disconnected = 0,
1509 PublishReplayed = 8,
1510 HeartbeatInitiated = 16,
1529 class MessageStreamImpl;
1530 class MessageStream;
1532 typedef void(*DeferredExecutionFunc)(
void*);
1534 class ClientImpl :
public RefBody
1540 AMPS_SOCKET _socket;
1546 socklen_t _valueLen;
1550 : _socket(AMPS_INVALID_SOCKET), _noDelay(0), _valueLen(sizeof(int))
1552 _valuePtr = (
char*)&_noDelay;
1554 if (_socket != AMPS_INVALID_SOCKET)
1556 getsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, _valuePtr, &_valueLen);
1560 setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, _valuePtr, _valueLen);
1564 _socket = AMPS_INVALID_SOCKET;
1571 if (_socket != AMPS_INVALID_SOCKET)
1574 setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, _valuePtr, _valueLen);
1579 friend class Client;
1582 DisconnectHandler _disconnectHandler;
1583 enum GlobalCommandTypeHandlers :
size_t
1593 DuplicateMessage = 8,
1596 std::vector<MessageHandler> _globalCommandTypeHandlers;
1597 Message _message, _readMessage, _publishMessage, _deltaMessage, _beatMessage;
1598 MessageRouter _routes;
1599 MessageRouter::RouteCache _routeCache;
1600 mutable Mutex _lock;
1601 std::string _name, _nameHash, _lastUri, _logonCorrelationData, _preflightMessage;
1602 std::vector<std::string> _httpPreflightHeaders;
1603 amps_uint64_t _nameHashValue;
1604 BookmarkStore _bookmarkStore;
1605 Store _publishStore;
1606 bool _isRetryOnDisconnect;
1607 amps_unique_ptr<FailedWriteHandler> _failedWriteHandler;
1608 #if __cplusplus >= 201100L || _MSC_VER >= 1900
1609 std::atomic<amps_uint64_t> _lastSentHaSequenceNumber;
1611 volatile amps_uint64_t _lastSentHaSequenceNumber;
1613 AMPS_ATOMIC_TYPE_8 _logonInProgress;
1614 AMPS_ATOMIC_TYPE_8 _badTimeToHASubscribe;
1615 VersionInfo _serverVersion;
1616 Timer _heartbeatTimer;
1617 amps_unique_ptr<MessageStream> _pEmptyMessageStream;
1620 int _queueAckTimeout;
1621 bool _isAutoAckEnabled;
1622 unsigned _ackBatchSize;
1623 unsigned _queuedAckCount;
1624 unsigned _defaultMaxDepth;
1625 struct QueueBookmarks
1627 QueueBookmarks(
const std::string& topic_)
1634 amps_uint64_t _oldestTime;
1635 unsigned _bookmarkCount;
1637 typedef amps_uint64_t topic_hash;
1638 typedef std::map<topic_hash, QueueBookmarks> TopicHashMap;
1639 TopicHashMap _topicHashMap;
1641 class ClientStoreReplayer :
public StoreReplayer
1643 ClientImpl* _client;
1648 ClientStoreReplayer()
1649 : _client(NULL), _version(0), _res(
AMPS_E_OK)
1652 ClientStoreReplayer(ClientImpl* client_)
1653 : _client(client_), _version(0), _res(
AMPS_E_OK)
1656 void setClient(ClientImpl* client_)
1661 void execute(Message& message_)
1665 throw CommandException(
"Can't replay without a client.");
1669 if (index > _client->_lastSentHaSequenceNumber)
1671 _client->_lastSentHaSequenceNumber = index;
1678 if (!message_.getCommand().empty() &&
1679 (!_client->_logonInProgress ||
1680 message_.getOptions().len() < 6))
1683 message_.getMessage(),
1688 throw DisconnectedException(
"AMPS Server disconnected during replay");
1694 ClientStoreReplayer _replayer;
1696 class FailedWriteStoreReplayer :
public StoreReplayer
1698 ClientImpl* _parent;
1699 const char* _reason;
1700 size_t _reasonLength;
1701 size_t _replayCount;
1703 FailedWriteStoreReplayer(ClientImpl* parent,
const char* reason_,
size_t reasonLength_)
1706 _reasonLength(reasonLength_),
1709 void execute(Message& message_)
1711 if (_parent->_failedWriteHandler)
1714 _parent->_failedWriteHandler->failedWrite(message_,
1715 _reason, _reasonLength);
1718 size_t replayCount(
void)
const
1720 return _replayCount;
1724 struct AckResponseImpl :
public RefBody
1726 std::string username, password, reason, status, bookmark, options;
1727 amps_uint64_t sequenceNo;
1728 amps_uint64_t nameHashValue;
1729 VersionInfo serverVersion;
1730 #if __cplusplus >= 201100L || _MSC_VER >= 1900
1731 std::atomic<bool> responded;
1732 std::atomic<bool> abandoned;
1734 volatile bool responded;
1735 volatile bool abandoned;
1737 unsigned connectionVersion;
1740 username(), password(), reason(), status(), bookmark(), options(),
1741 sequenceNo((amps_uint64_t)0),
1745 connectionVersion(UINT_MAX)
1752 RefHandle<AckResponseImpl> _body;
1754 AckResponse() : _body(NULL) {;}
1755 AckResponse(
const AckResponse& rhs) : _body(rhs._body) {;}
1756 static AckResponse create()
1759 r._body =
new AckResponseImpl();
1763 const std::string& username()
1765 return _body.get().username;
1767 void setUsername(
const char* data_,
size_t len_)
1771 _body.get().username.assign(data_, len_);
1775 _body.get().username.clear();
1778 const std::string& password()
1780 return _body.get().password;
1782 void setPassword(
const char* data_,
size_t len_)
1786 _body.get().password.assign(data_, len_);
1790 _body.get().password.clear();
1793 const std::string& reason()
1795 return _body.get().reason;
1797 void setReason(
const char* data_,
size_t len_)
1801 _body.get().reason.assign(data_, len_);
1805 _body.get().reason.clear();
1808 const std::string& status()
1810 return _body.get().status;
1812 void setStatus(
const char* data_,
size_t len_)
1816 _body.get().status.assign(data_, len_);
1820 _body.get().status.clear();
1823 const std::string& bookmark()
1825 return _body.get().bookmark;
1827 void setBookmark(
const Field& bookmark_)
1829 if (!bookmark_.empty())
1831 _body.get().bookmark.assign(bookmark_.data(), bookmark_.len());
1832 Field::parseBookmark(bookmark_, _body.get().nameHashValue,
1833 _body.get().sequenceNo);
1837 _body.get().bookmark.clear();
1838 _body.get().sequenceNo = (amps_uint64_t)0;
1839 _body.get().nameHashValue = (amps_uint64_t)0;
1842 amps_uint64_t sequenceNo()
const
1844 return _body.get().sequenceNo;
1846 amps_uint64_t nameHashValue()
const
1848 return _body.get().nameHashValue;
1850 void setSequenceNo(
const char* data_,
size_t len_)
1852 amps_uint64_t result = (amps_uint64_t)0;
1855 for (
size_t i = 0; i < len_; ++i)
1857 result *= (amps_uint64_t)10;
1858 result += (amps_uint64_t)(data_[i] -
'0');
1861 _body.get().sequenceNo = result;
1863 VersionInfo serverVersion()
const
1865 return _body.get().serverVersion;
1867 void setServerVersion(
const char* data_,
size_t len_)
1871 _body.get().serverVersion.setVersion(std::string(data_, len_));
1876 return _body.get().responded;
1880 _body.get().responded =
true;
1884 return _body.get().abandoned;
1888 if (_body.isValid())
1890 _body.get().abandoned =
true;
1894 void setConnectionVersion(
unsigned connectionVersion)
1896 _body.get().connectionVersion = connectionVersion;
1899 unsigned getConnectionVersion()
1901 return _body.get().connectionVersion;
1903 void setOptions(
const char* data_,
size_t len_)
1907 _body.get().options.assign(data_, len_);
1911 _body.get().options.clear();
1915 const std::string& options()
1917 return _body.get().options;
1920 AckResponse& operator=(
const AckResponse& rhs)
1928 typedef std::map<std::string, AckResponse> AckMap;
1931 DefaultExceptionListener _defaultExceptionListener;
1934 struct DeferredExecutionRequest
1936 DeferredExecutionRequest(DeferredExecutionFunc func_,
1939 _userData(userData_)
1942 DeferredExecutionFunc _func;
1945 const ExceptionListener* _exceptionListener;
1946 std::shared_ptr<const ExceptionListener> _pExceptionListener;
1947 amps_unique_ptr<SubscriptionManager> _subscriptionManager;
1948 volatile bool _connected;
1949 std::string _username;
1950 typedef std::set<ConnectionStateListener*> ConnectionStateListeners;
1951 ConnectionStateListeners _connectionStateListeners;
1952 typedef std::vector<DeferredExecutionRequest> DeferredExecutionList;
1953 Mutex _deferredExecutionLock;
1954 DeferredExecutionList _deferredExecutionList;
1955 unsigned _heartbeatInterval;
1956 unsigned _readTimeout;
1964 if (!_connected && newState_ > ConnectionStateListener::Connected)
1968 for (ConnectionStateListeners::iterator it = _connectionStateListeners.begin(); it != _connectionStateListeners.end(); ++it)
1970 AMPS_CALL_EXCEPTION_WRAPPER(
1971 (*it)->connectionStateChanged(newState_));
1974 unsigned processedAck(Message& message);
1975 unsigned persistedAck(Message& meesage);
1976 void lastChance(Message& message);
1977 void checkAndSendHeartbeat(
bool force =
false);
1978 virtual ConnectionInfo getConnectionInfo()
const;
1980 ClientImplMessageHandler(
amps_handle message,
void* userData);
1982 ClientImplPreDisconnectHandler(
amps_handle client,
unsigned failedConnectionVersion,
void* userData);
1984 ClientImplDisconnectHandler(
amps_handle client,
void* userData);
1986 ClientImplGetHttpPreflightMessage(
void* userData);
1988 void unsubscribeInternal(
const std::string&
id)
1995 Message::Field subId;
1996 subId.assign(
id.data(),
id.length());
1997 _routes.removeRoute(subId);
1999 if (_subscriptionManager)
2002 Unlock<Mutex> unlock(_lock);
2003 _subscriptionManager->unsubscribe(subId);
2006 _message.setCommandEnum(Message::Command::Unsubscribe);
2007 _message.newCommandId();
2008 _message.setSubscriptionId(
id);
2009 _sendWithoutRetry(_message);
2010 deferredExecution(&s_noOpFn, NULL);
2013 AckResponse syncAckProcessing(
long timeout_, Message& message_,
2014 bool isHASubscribe_)
2016 return syncAckProcessing(timeout_, message_,
2017 (amps_uint64_t)0, isHASubscribe_);
2020 AckResponse syncAckProcessing(
long timeout_, Message& message_,
2021 amps_uint64_t haSeq = (amps_uint64_t)0,
2022 bool isHASubscribe_ =
false)
2025 AckResponse ack = AckResponse::create();
2028 Lock<Mutex> guard(_ackMapLock);
2029 _ackMap[message_.getCommandId()] = ack;
2031 ack.setConnectionVersion((
unsigned)_send(message_, haSeq, isHASubscribe_));
2032 if (ack.getConnectionVersion() == 0)
2035 throw DisconnectedException(
"Connection closed while waiting for response.");
2037 bool timedOut =
false;
2038 AMPS_START_TIMER(timeout_)
2039 while (!timedOut && !ack.responded() && !ack.abandoned())
2043 timedOut = !_lock.wait(timeout_);
2047 AMPS_RESET_TIMER(timedOut, timeout_);
2054 Unlock<Mutex> unlck(_lock);
2055 amps_invoke_waiting_function();
2058 if (ack.responded())
2060 if (ack.status() !=
"failure")
2062 if (message_.getCommand() ==
"logon")
2064 amps_uint64_t ackSequence = ack.sequenceNo();
2065 if (_lastSentHaSequenceNumber < ackSequence)
2067 _lastSentHaSequenceNumber = ackSequence;
2069 if (_publishStore.isValid())
2074 _publishStore.discardUpTo(ackSequence);
2075 if (_lastSentHaSequenceNumber < _publishStore.getLastPersisted())
2077 _lastSentHaSequenceNumber = _publishStore.getLastPersisted();
2080 _nameHash = ack.bookmark().substr(0, ack.bookmark().find(
'|'));
2081 _nameHashValue = ack.nameHashValue();
2082 _serverVersion = ack.serverVersion();
2083 if (_bookmarkStore.isValid())
2085 _bookmarkStore.setServerVersion(_serverVersion);
2090 const std::string& options = ack.options();
2091 size_t index = options.find_first_of(
"max_backlog=");
2092 if (index != std::string::npos)
2095 const char* c = options.c_str() + index + 12;
2096 while (*c && *c !=
',')
2098 data = (data * 10) + (
unsigned)(*c++ -48);
2100 if (_ackBatchSize > data)
2102 _ackBatchSize = data;
2108 const size_t NotEntitled = 12;
2109 std::string ackReason = ack.reason();
2110 if (ackReason.length() == 0)
2114 if (ackReason.length() == NotEntitled &&
2115 ackReason[0] ==
'n' &&
2116 message_.getUserId().len() == 0)
2118 message_.assignUserId(_username);
2120 message_.throwFor(_client, ackReason);
2124 if (!ack.abandoned())
2126 throw TimedOutException(
"timed out waiting for operation.");
2130 throw DisconnectedException(
"Connection closed while waiting for response.");
2144 AMPS_CALL_EXCEPTION_WRAPPER(ClientImpl::disconnect());
2145 _pEmptyMessageStream.reset(NULL);
2152 ClientImpl(
const std::string& clientName)
2153 : _client(NULL), _name(clientName)
2154 , _isRetryOnDisconnect(true)
2155 , _lastSentHaSequenceNumber((amps_uint64_t)0), _logonInProgress(0)
2156 , _badTimeToHASubscribe(0), _serverVersion()
2157 , _queueAckTimeout(AMPS_DEFAULT_QUEUE_ACK_TIMEOUT)
2158 , _isAutoAckEnabled(false)
2160 , _queuedAckCount(0)
2161 , _defaultMaxDepth(0)
2163 , _heartbeatInterval(0)
2166 _replayer.setClient(
this);
2169 (amps_handler)ClientImpl::ClientImplMessageHandler,
2172 (amps_predisconnect_handler)ClientImpl::ClientImplPreDisconnectHandler,
2175 (amps_handler)ClientImpl::ClientImplDisconnectHandler,
2178 ClientImpl::ClientImplGetHttpPreflightMessage,
2180 _exceptionListener = &_defaultExceptionListener;
2181 for (
size_t i = 0; i < GlobalCommandTypeHandlers::COUNT; ++i)
2183 #ifdef AMPS_USE_EMPLACE
2184 _globalCommandTypeHandlers.emplace_back(MessageHandler());
2186 _globalCommandTypeHandlers.push_back(MessageHandler());
2191 virtual ~ClientImpl()
2196 const std::string& getName()
const
2201 const std::string& getNameHash()
const
2206 const amps_uint64_t getNameHashValue()
const
2208 return _nameHashValue;
2211 void setName(
const std::string& name)
2218 AMPSException::throwFor(_client, result);
2223 const std::string& getLogonCorrelationData()
const
2225 return _logonCorrelationData;
2228 void setLogonCorrelationData(
const std::string& logonCorrelationData_)
2230 _logonCorrelationData = logonCorrelationData_;
2233 size_t getServerVersion()
const
2235 return _serverVersion.getOldStyleVersion();
2238 VersionInfo getServerVersionInfo()
const
2240 return _serverVersion;
2243 const std::string& getURI()
const
2248 virtual void connect(
const std::string& uri)
2250 Lock<Mutex> l(_lock);
2254 virtual void _connect(
const std::string& uri)
2260 AMPSException::throwFor(_client, result);
2263 _deltaMessage.setCommandEnum(Message::Command::DeltaPublish);
2264 _publishMessage.setCommandEnum(Message::Command::Publish);
2265 _beatMessage.setCommandEnum(Message::Command::Heartbeat);
2266 _beatMessage.setOptions(
"beat");
2267 _readMessage.setClientImpl(
this);
2268 if (_queueAckTimeout)
2273 AMPSException::throwFor(_client, result);
2277 broadcastConnectionStateChanged(ConnectionStateListener::Connected);
2280 void addHttpPreflightHeader(
const std::string& header_)
2282 _httpPreflightHeaders.push_back(header_);
2285 void addHttpPreflightHeader(
const std::string& key_,
const std::string& value_)
2287 _httpPreflightHeaders.push_back(key_ + std::string(
": ") + value_);
2290 void clearHttpPreflightHeaders()
2292 _httpPreflightHeaders.clear();
2296 void setHttpPreflightHeaders(
const T& headers_)
2298 _httpPreflightHeaders.clear();
2299 for (
typename T::const_iterator i = headers_.begin(); i != headers_.end(); ++i)
2301 _httpPreflightHeaders.push_back(*i);
2305 void setDisconnected()
2308 Lock<Mutex> l(_lock);
2311 AMPS_CALL_EXCEPTION_WRAPPER(broadcastConnectionStateChanged(ConnectionStateListener::Disconnected));
2314 _heartbeatTimer.setTimeout(0.0);
2317 clearAcks(UINT_MAX-1);
2323 virtual void disconnect()
2325 AMPS_CALL_EXCEPTION_WRAPPER(flushAcks());
2328 clearAcks(UINT_MAX);
2329 AMPS_CALL_EXCEPTION_WRAPPER(processDeferredExecutions());
2330 Lock<Mutex> l(_lock);
2331 broadcastConnectionStateChanged(ConnectionStateListener::Shutdown);
2334 void clearAcks(
unsigned failedVersion)
2337 Lock<Mutex> guard(_ackMapLock);
2340 std::vector<std::string> worklist;
2341 for (AckMap::iterator i = _ackMap.begin(), e = _ackMap.end(); i != e; ++i)
2343 if (i->second.getConnectionVersion() <= failedVersion)
2345 i->second.setAbandoned();
2346 worklist.push_back(i->first);
2350 for (std::vector<std::string>::iterator j = worklist.begin(), e = worklist.end(); j != e; ++j)
2359 int send(
const Message& message)
2361 Lock<Mutex> l(_lock);
2362 return _send(message);
2365 void sendWithoutRetry(
const Message& message_)
2367 Lock<Mutex> l(_lock);
2370 if (_logonInProgress)
2372 throw DisconnectedException(
"The client has been disconnected.");
2374 _sendWithoutRetry(message_);
2377 void _sendWithoutRetry(
const Message& message_)
2382 AMPSException::throwFor(_client, result);
2386 int _send(
const Message& message, amps_uint64_t haSeq = (amps_uint64_t)0,
2387 bool isHASubscribe_ =
false,
int isBatch_ = 0)
2394 Message localMessage = message;
2395 unsigned version = 0;
2399 if (haSeq && _logonInProgress)
2403 if (!_isRetryOnDisconnect)
2407 if (!_lock.wait(1000))
2409 amps_invoke_waiting_function();
2414 if ((haSeq && haSeq <= _lastSentHaSequenceNumber) ||
2415 (isHASubscribe_ && _badTimeToHASubscribe))
2417 return (
int)version;
2421 if (haSeq > _lastSentHaSequenceNumber)
2423 while (haSeq > _lastSentHaSequenceNumber + 1)
2428 if (!_publishStore.replaySingle(_replayer,
2429 _lastSentHaSequenceNumber + 1))
2435 version = _replayer._version;
2438 catch (
const DisconnectedException&)
2440 catch (
const DisconnectedException& e)
2443 if (!_isRetryOnDisconnect)
2447 result = _replayer._res;
2452 localMessage.getMessage(),
2455 ++_lastSentHaSequenceNumber;
2459 if (_logonInProgress && localMessage.getCommand().data()[0] !=
'l')
2461 while (_logonInProgress)
2463 if (!_lock.wait(1000))
2465 amps_invoke_waiting_function();
2466 if (!_isRetryOnDisconnect)
2469 AMPSException::throwFor(_client, result);
2475 localMessage.getMessage(),
2481 if (!isHASubscribe_ && !haSeq &&
2482 localMessage.getMessage() == message.getMessage())
2484 localMessage = message.deepCopy();
2486 if (_isRetryOnDisconnect)
2488 Unlock<Mutex> u(_lock);
2493 if ((isHASubscribe_ || haSeq) &&
2496 return (
int)version;
2503 AMPSException::throwFor(_client, result);
2509 amps_invoke_waiting_function();
2515 AMPSException::throwFor(_client, result);
2517 return (
int)version;
2520 void addMessageHandler(
const Field& commandId_,
2522 unsigned requestedAcks_, Message::Command::Type commandType_)
2524 Lock<Mutex> lock(_lock);
2525 _routes.addRoute(commandId_, messageHandler_, requestedAcks_,
2529 bool removeMessageHandler(
const Field& commandId_)
2531 Lock<Mutex> lock(_lock);
2532 return _routes.removeRoute(commandId_);
2535 std::string send(
const MessageHandler& messageHandler_, Message& message_,
int timeout_ = 0)
2537 Field
id = message_.getCommandId();
2538 Field subId = message_.getSubscriptionId();
2539 Field qid = message_.getQueryId();
2540 bool isSubscribeOnly =
false;
2541 bool replace =
false;
2542 unsigned requestedAcks = message_.getAckTypeEnum();
2543 unsigned systemAddedAcks = Message::AckType::None;
2544 Message::Command::Type commandType = message_.getCommandEnum();
2546 switch (commandType)
2548 case Message::Command::Subscribe:
2549 case Message::Command::DeltaSubscribe:
2550 replace = message_.getOptions().operator std::string().find(AMPS_OPTIONS_REPLACE, 0, strlen(AMPS_OPTIONS_REPLACE) - 1) != std::string::npos;
2551 isSubscribeOnly =
true;
2553 case Message::Command::SOWAndSubscribe:
2554 case Message::Command::SOWAndDeltaSubscribe:
2557 id = message_.newCommandId().getCommandId();
2561 while (!replace &&
id != subId && _routes.hasRoute(
id))
2563 id = message_.newCommandId().getCommandId();
2568 message_.setSubscriptionId(
id);
2571 if (!message_.getBookmark().empty() && _bookmarkStore.isValid())
2573 systemAddedAcks |= Message::AckType::Persisted;
2576 case Message::Command::SOW:
2579 id = message_.newCommandId().getCommandId();
2583 while (!replace &&
id != subId && _routes.hasRoute(
id))
2585 message_.newCommandId();
2588 qid = message_.getCommandId();
2589 message_.setQueryId(qid);
2591 id = message_.getCommandId();
2594 if (!isSubscribeOnly)
2598 message_.setQueryID(
id);
2603 while (!replace && qid != subId && qid !=
id
2604 && _routes.hasRoute(qid))
2606 qid = message_.newQueryId().getQueryId();
2610 systemAddedAcks |= Message::AckType::Processed;
2611 message_.setAckTypeEnum(requestedAcks | systemAddedAcks);
2613 int routesAdded = 0;
2614 Lock<Mutex> l(_lock);
2615 if (!subId.empty() && messageHandler_.isValid())
2617 if (!_routes.hasRoute(subId))
2623 _routes.addRoute(subId, messageHandler_, requestedAcks,
2624 systemAddedAcks, commandType);
2626 if (!isSubscribeOnly && !qid.empty()
2627 && messageHandler_.isValid() && qid != subId)
2629 if (routesAdded == 0)
2631 _routes.addRoute(qid, messageHandler_,
2632 requestedAcks, systemAddedAcks, commandType);
2638 Unlock<Mutex> u(_lock);
2639 data = amps_invoke_copy_route_function(
2640 messageHandler_.userData());
2644 _routes.addRoute(qid, messageHandler_, requestedAcks,
2645 systemAddedAcks, commandType);
2649 _routes.addRoute(qid,
2650 MessageHandler(messageHandler_.function(),
2652 requestedAcks, systemAddedAcks, commandType);
2657 if (!
id.empty() && messageHandler_.isValid()
2658 && requestedAcks & ~Message::AckType::Persisted
2659 &&
id != subId &&
id != qid)
2661 if (routesAdded == 0)
2663 _routes.addRoute(
id, messageHandler_, requestedAcks,
2664 systemAddedAcks, commandType);
2670 Unlock<Mutex> u(_lock);
2671 data = amps_invoke_copy_route_function(
2672 messageHandler_.userData());
2676 _routes.addRoute(
id, messageHandler_, requestedAcks,
2677 systemAddedAcks, commandType);
2681 _routes.addRoute(
id,
2682 MessageHandler(messageHandler_.function(),
2685 systemAddedAcks, commandType);
2694 syncAckProcessing(timeout_, message_, 0,
false);
2695 message_.setAckTypeEnum(requestedAcks);
2699 _routes.removeRoute(message_.getQueryID());
2700 _routes.removeRoute(message_.getSubscriptionId());
2701 _routes.removeRoute(
id);
2702 message_.setAckTypeEnum(requestedAcks);
2708 case Message::Command::Unsubscribe:
2709 case Message::Command::Heartbeat:
2710 case Message::Command::Logon:
2711 case Message::Command::StartTimer:
2712 case Message::Command::StopTimer:
2713 case Message::Command::SOWDelete:
2715 Lock<Mutex> l(_lock);
2717 if (message_.getAckTypeEnum() != Message::AckType::None)
2721 message_.newCommandId();
2722 id = message_.getCommandId();
2724 if (messageHandler_.isValid())
2726 _routes.addRoute(
id, messageHandler_, requestedAcks,
2727 Message::AckType::None, commandType);
2733 case Message::Command::DeltaPublish:
2734 case Message::Command::Publish:
2736 bool useSync = message_.getFilter().len() > 0;
2737 Lock<Mutex> l(_lock);
2739 unsigned ackType = message_.getAckTypeEnum();
2740 if (ackType != Message::AckType::None
2745 message_.newCommandId();
2746 id = message_.getCommandId();
2748 if (messageHandler_.isValid())
2750 _routes.addRoute(
id, messageHandler_, requestedAcks,
2751 Message::AckType::None, commandType);
2756 message_.setAckTypeEnum(ackType | Message::AckType::Processed);
2757 syncAckProcessing(timeout_, message_, 0,
false);
2761 _send(message_, 0,
false, 1);
2766 case Message::Command::GroupBegin:
2767 case Message::Command::GroupEnd:
2768 case Message::Command::OOF:
2769 case Message::Command::Ack:
2770 case Message::Command::Unknown:
2772 throw CommandException(
"Command type " + message_.getCommand() +
" can not be sent directly to AMPS");
2774 message_.setAckTypeEnum(requestedAcks);
2778 void setDisconnectHandler(
const DisconnectHandler& disconnectHandler)
2780 Lock<Mutex> l(_lock);
2781 _disconnectHandler = disconnectHandler;
2784 void setGlobalCommandTypeMessageHandler(
const std::string& command_,
const MessageHandler& handler_)
2786 switch (command_[0])
2790 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Publish] = handler_;
2793 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::SOW] = handler_;
2797 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Heartbeat] = handler_;
2801 if (command_[6] ==
'b')
2803 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupBegin] = handler_;
2805 else if (command_[6] ==
'e')
2807 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupEnd] = handler_;
2811 std::ostringstream os;
2812 os <<
"Invalid command '" << command_ <<
"' passed to setGlobalCommandTypeHandler";
2813 throw CommandException(os.str());
2817 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::OOF] = handler_;
2821 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Ack] = handler_;
2825 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::LastChance] = handler_;
2829 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage] = handler_;
2832 std::ostringstream os;
2833 os <<
"Invalid command '" << command_ <<
"' passed to setGlobalCommandTypeHandler";
2834 throw CommandException(os.str());
2839 void setGlobalCommandTypeMessageHandler(
const Message::Command::Type command_,
const MessageHandler& handler_)
2844 case Message::Command::Publish:
2845 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Publish] = handler_;
2847 case Message::Command::SOW:
2848 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::SOW] = handler_;
2851 case Message::Command::Heartbeat:
2852 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Heartbeat] = handler_;
2855 case Message::Command::GroupBegin:
2856 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupBegin] = handler_;
2858 case Message::Command::GroupEnd:
2859 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupEnd] = handler_;
2861 case Message::Command::OOF:
2862 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::OOF] = handler_;
2865 case Message::Command::Ack:
2866 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Ack] = handler_;
2870 unsigned command = command_;
2877 AMPS_snprintf(errBuf,
sizeof(errBuf),
2878 "Invalid command '%.*s' passed to setGlobalCommandTypeHandler",
2879 CommandConstants<0>::Lengths[bits],
2880 CommandConstants<0>::Values[bits]);
2881 throw CommandException(errBuf);
2886 void setGlobalCommandTypeMessageHandler(
const GlobalCommandTypeHandlers handlerType_,
const MessageHandler& handler_)
2888 _globalCommandTypeHandlers[handlerType_] = handler_;
2891 void setFailedWriteHandler(FailedWriteHandler* handler_)
2893 Lock<Mutex> l(_lock);
2894 _failedWriteHandler.reset(handler_);
2897 void setPublishStore(
const Store& publishStore_)
2899 Lock<Mutex> l(_lock);
2902 throw AlreadyConnectedException(
"Setting a publish store on a connected client is undefined behavior");
2904 _publishStore = publishStore_;
2907 void setBookmarkStore(
const BookmarkStore& bookmarkStore_)
2909 Lock<Mutex> l(_lock);
2912 throw AlreadyConnectedException(
"Setting a bookmark store on a connected client is undefined behavior");
2914 _bookmarkStore = bookmarkStore_;
2917 void setSubscriptionManager(SubscriptionManager* subscriptionManager_)
2919 Lock<Mutex> l(_lock);
2920 _subscriptionManager.reset(subscriptionManager_);
2923 SubscriptionManager* getSubscriptionManager()
const
2925 return const_cast<SubscriptionManager*
>(_subscriptionManager.get());
2928 DisconnectHandler getDisconnectHandler()
const
2930 return _disconnectHandler;
2933 MessageHandler getDuplicateMessageHandler()
const
2935 return _globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage];
2938 FailedWriteHandler* getFailedWriteHandler()
const
2940 return const_cast<FailedWriteHandler*
>(_failedWriteHandler.get());
2943 Store getPublishStore()
const
2945 return _publishStore;
2948 BookmarkStore getBookmarkStore()
const
2950 return _bookmarkStore;
2953 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
const char* data_,
size_t dataLen_)
2955 if (!_publishStore.isValid())
2957 Lock<Mutex> l(_lock);
2958 _publishMessage.assignTopic(topic_, topicLen_);
2959 _publishMessage.assignData(data_, dataLen_);
2960 _send(_publishMessage, 0,
false, 1);
2965 publishStoreMessage.reset();
2967 return _publish(topic_, topicLen_, data_, dataLen_);
2971 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
const char* data_,
2972 size_t dataLen_,
unsigned long expiration_)
2974 if (!_publishStore.isValid())
2976 Lock<Mutex> l(_lock);
2977 _publishMessage.assignTopic(topic_, topicLen_);
2978 _publishMessage.assignData(data_, dataLen_);
2979 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
2980 size_t pos = convertToCharArray(exprBuf, expiration_);
2981 _publishMessage.assignExpiration(exprBuf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
2982 _send(_publishMessage, 0,
false, 1);
2983 _publishMessage.assignExpiration(NULL, 0);
2988 publishStoreMessage.reset();
2989 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
2990 size_t exprPos = convertToCharArray(exprBuf, expiration_);
2993 AMPS_NUMBER_BUFFER_LEN - exprPos);
2994 return _publish(topic_, topicLen_, data_, dataLen_);
2998 class FlushAckHandler : ConnectionStateListener
3001 ClientImpl* _pClient;
3003 #if __cplusplus >= 201100L || _MSC_VER >= 1900
3004 std::atomic<bool> _acked;
3005 std::atomic<bool> _disconnected;
3007 volatile bool _acked;
3008 volatile bool _disconnected;
3011 FlushAckHandler(ClientImpl* pClient_)
3012 : _pClient(pClient_), _cmdId(), _acked(false), _disconnected(false)
3014 pClient_->addConnectionStateListener(
this);
3018 _pClient->removeConnectionStateListener(
this);
3019 _pClient->removeMessageHandler(_cmdId);
3022 void setCommandId(
const Field& cmdId_)
3024 _cmdId.deepCopy(cmdId_);
3026 void invoke(
const Message&)
3030 void connectionStateChanged(State state_)
3032 if (state_ <= Shutdown)
3034 _disconnected =
true;
3043 return _acked || _disconnected;
3047 void publishFlush(
long timeout_,
unsigned ackType_)
3049 static const char* processed =
"processed";
3050 static const size_t processedLen = strlen(processed);
3051 static const char* persisted =
"persisted";
3052 static const size_t persistedLen = strlen(persisted);
3053 static const char* flush =
"flush";
3054 static const size_t flushLen = strlen(flush);
3055 static VersionInfo minPersisted(
"5.3.3.0");
3056 static VersionInfo minFlush(
"4");
3057 if (ackType_ != Message::AckType::Processed
3058 && ackType_ != Message::AckType::Persisted)
3060 throw CommandException(
"Flush can only be used with processed or persisted acks.");
3062 FlushAckHandler flushHandler(
this);
3063 if (_serverVersion >= minFlush)
3065 Lock<Mutex> l(_lock);
3068 throw DisconnectedException(
"Not connected trying to flush");
3071 _message.newCommandId();
3072 _message.assignCommand(flush, flushLen);
3073 if (_serverVersion < minPersisted
3074 || ackType_ == Message::AckType::Processed)
3076 _message.assignAckType(processed, processedLen);
3080 _message.assignAckType(persisted, persistedLen);
3082 flushHandler.setCommandId(_message.getCommandId());
3083 addMessageHandler(_message.getCommandId(),
3084 std::bind(&FlushAckHandler::invoke,
3085 std::ref(flushHandler),
3086 std::placeholders::_1),
3087 ackType_, _message.getCommandEnum());
3088 NoDelay noDelay(_client);
3089 if (_send(_message) == -1)
3091 throw DisconnectedException(
"Disconnected trying to flush");
3094 if (_publishStore.isValid())
3098 _publishStore.flush(timeout_);
3100 catch (
const AMPSException& ex)
3102 AMPS_UNHANDLED_EXCEPTION(ex);
3106 else if (_serverVersion < minFlush)
3110 AMPS_USLEEP(timeout_ * 1000);
3114 AMPS_USLEEP(1000 * 1000);
3120 Timer timer((
double)timeout_);
3122 while (!timer.check() && !flushHandler.done())
3125 amps_invoke_waiting_function();
3130 while (!flushHandler.done())
3133 amps_invoke_waiting_function();
3137 if (!flushHandler.done())
3139 throw TimedOutException(
"Timed out waiting for flush");
3142 if (!flushHandler.acked() && !_publishStore.isValid())
3144 throw DisconnectedException(
"Disconnected waiting for flush");
3148 amps_uint64_t deltaPublish(
const char* topic_,
size_t topicLength_,
3149 const char* data_,
size_t dataLength_)
3151 if (!_publishStore.isValid())
3153 Lock<Mutex> l(_lock);
3154 _deltaMessage.assignTopic(topic_, topicLength_);
3155 _deltaMessage.assignData(data_, dataLength_);
3156 _send(_deltaMessage, 0,
false, 1);
3161 publishStoreMessage.reset();
3162 publishStoreMessage.
setCommandEnum(Message::Command::DeltaPublish);
3163 return _publish(topic_, topicLength_, data_, dataLength_);
3167 amps_uint64_t deltaPublish(
const char* topic_,
size_t topicLength_,
3168 const char* data_,
size_t dataLength_,
3169 unsigned long expiration_)
3171 if (!_publishStore.isValid())
3173 Lock<Mutex> l(_lock);
3174 _deltaMessage.assignTopic(topic_, topicLength_);
3175 _deltaMessage.assignData(data_, dataLength_);
3176 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
3177 size_t pos = convertToCharArray(exprBuf, expiration_);
3178 _deltaMessage.assignExpiration(exprBuf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
3179 _send(_deltaMessage, 0,
false, 1);
3180 _deltaMessage.assignExpiration(NULL, 0);
3185 publishStoreMessage.reset();
3186 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
3187 size_t exprPos = convertToCharArray(exprBuf, expiration_);
3188 publishStoreMessage.
setCommandEnum(Message::Command::DeltaPublish)
3190 AMPS_NUMBER_BUFFER_LEN - exprPos);
3191 return _publish(topic_, topicLength_, data_, dataLength_);
3195 amps_uint64_t _publish(
const char* topic_,
size_t topicLength_,
3196 const char* data_,
size_t dataLength_)
3198 publishStoreMessage.
assignTopic(topic_, topicLength_)
3200 .assignData(data_, dataLength_);
3201 amps_uint64_t haSequenceNumber = _publishStore.store(publishStoreMessage);
3202 char buf[AMPS_NUMBER_BUFFER_LEN];
3203 size_t pos = convertToCharArray(buf, haSequenceNumber);
3204 publishStoreMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
3206 Lock<Mutex> l(_lock);
3207 _send(publishStoreMessage, haSequenceNumber,
false, 1);
3209 return haSequenceNumber;
3212 virtual std::string logon(
long timeout_, Authenticator& authenticator_,
3213 const char* options_ = NULL)
3215 Lock<Mutex> l(_lock);
3216 return _logon(timeout_, authenticator_, options_);
3219 virtual std::string _logon(
long timeout_, Authenticator& authenticator_,
3220 const char* options_ = NULL)
3223 _message.newCommandId();
3224 std::string newCommandId = _message.getCommandId();
3225 _message.setCommandEnum(Message::Command::Logon);
3226 _message.setClientName(_name);
3227 #ifdef AMPS_CLIENT_VERSION_WITH_LANGUAGE
3228 _message.assignVersion(AMPS_CLIENT_VERSION_WITH_LANGUAGE,
3229 strlen(AMPS_CLIENT_VERSION_WITH_LANGUAGE));
3232 if (uri.user().size())
3234 _message.setUserId(uri.user());
3236 if (uri.password().size())
3238 _message.setPassword(uri.password());
3240 if (uri.protocol() ==
"amps" && uri.messageType().size())
3242 _message.setMessageType(uri.messageType());
3244 if (uri.isTrue(
"pretty"))
3246 _message.setOptions(
"pretty");
3249 _message.setPassword(authenticator_.authenticate(_message.getUserId(), _message.getPassword()));
3250 if (!_logonCorrelationData.empty())
3252 _message.assignCorrelationId(_logonCorrelationData);
3256 _message.setOptions(options_);
3258 _username = _message.getUserId();
3261 AtomicFlagFlip pubFlip(&_logonInProgress);
3262 NoDelay noDelay(_client);
3265 _message.setAckTypeEnum(Message::AckType::Processed);
3266 AckResponse ack = syncAckProcessing(timeout_, _message);
3267 if (ack.status() ==
"retry")
3269 _message.setPassword(authenticator_.retry(ack.username(), ack.password()));
3270 _username = ack.username();
3271 _message.setUserId(_username);
3275 authenticator_.completed(ack.username(), ack.password(), ack.reason());
3279 broadcastConnectionStateChanged(ConnectionStateListener::LoggedOn);
3286 catch (
const AMPSException& ex)
3289 Unlock<Mutex> u(_lock);
3293 AMPS_UNHANDLED_EXCEPTION(ex);
3299 Unlock<Mutex> u(_lock);
3306 if (_publishStore.isValid())
3310 _publishStore.replay(_replayer);
3311 broadcastConnectionStateChanged(ConnectionStateListener::PublishReplayed);
3313 catch (
const PublishStoreGapException& ex)
3316 Unlock<Mutex> u(_lock);
3320 AMPS_UNHANDLED_EXCEPTION(ex);
3323 catch (
const StoreException& ex)
3326 Unlock<Mutex> u(_lock);
3330 std::ostringstream os;
3331 os <<
"A local store exception occurred while logging on."
3333 throw ConnectionException(os.str());
3335 catch (
const AMPSException& ex)
3338 Unlock<Mutex> u(_lock);
3342 AMPS_UNHANDLED_EXCEPTION(ex);
3345 catch (
const std::exception& ex)
3348 Unlock<Mutex> u(_lock);
3352 AMPS_UNHANDLED_EXCEPTION(ex);
3358 Unlock<Mutex> u(_lock);
3366 return newCommandId;
3369 std::string subscribe(
const MessageHandler& messageHandler_,
3370 const std::string& topic_,
3372 const std::string& filter_,
3373 const std::string& bookmark_,
3374 const std::string& options_,
3375 const std::string& subId_,
3376 bool isHASubscribe_ =
true)
3378 isHASubscribe_ &= (bool)_subscriptionManager;
3379 Lock<Mutex> l(_lock);
3381 _message.setCommandEnum(Message::Command::Subscribe);
3382 _message.newCommandId();
3383 std::string subId(subId_);
3386 if (options_.find(AMPS_OPTIONS_REPLACE, 0, strlen(AMPS_OPTIONS_REPLACE) - 1) != std::string::npos)
3388 throw ConnectionException(
"Cannot issue a replacement subscription; a valid subscription id is required.");
3391 subId = _message.getCommandId();
3393 _message.setSubscriptionId(subId);
3398 unsigned ackTypes = Message::AckType::Processed;
3400 if (!bookmark_.empty() && _bookmarkStore.isValid())
3402 ackTypes |= Message::AckType::Persisted;
3404 _message.setTopic(topic_);
3406 if (filter_.length())
3408 _message.setFilter(filter_);
3410 if (bookmark_.length())
3415 Message::Field mostRecent = _bookmarkStore.getMostRecent(subIdField);
3416 _message.assignOwnershipBookmark(mostRecent);
3420 _message.setBookmark(bookmark_);
3421 if (_bookmarkStore.isValid())
3426 _bookmarkStore.log(_message);
3427 _bookmarkStore.discard(_message);
3428 _bookmarkStore.persisted(subIdField, _message.getBookmark());
3433 if (options_.length())
3435 _message.setOptions(options_);
3438 Message message = _message;
3441 message = _message.deepCopy();
3442 Unlock<Mutex> u(_lock);
3443 _subscriptionManager->subscribe(messageHandler_, message,
3444 Message::AckType::None);
3445 if (_badTimeToHASubscribe)
3450 if (!_routes.hasRoute(message.getSubscriptionId()))
3452 _routes.addRoute(message.getSubscriptionId(), messageHandler_,
3453 Message::AckType::None, ackTypes, message.getCommandEnum());
3455 message.setAckTypeEnum(ackTypes);
3456 if (!options_.empty())
3458 message.setOptions(options_);
3462 syncAckProcessing(timeout_, message, isHASubscribe_);
3464 catch (
const DisconnectedException&)
3466 if (!isHASubscribe_)
3468 _routes.removeRoute(subIdField);
3473 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subIdField));
3477 catch (
const TimedOutException&)
3479 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subIdField));
3487 Unlock<Mutex> unlock(_lock);
3488 _subscriptionManager->unsubscribe(subIdField);
3490 _routes.removeRoute(subIdField);
3496 std::string deltaSubscribe(
const MessageHandler& messageHandler_,
3497 const std::string& topic_,
3499 const std::string& filter_,
3500 const std::string& bookmark_,
3501 const std::string& options_,
3502 const std::string& subId_ =
"",
3503 bool isHASubscribe_ =
true)
3505 isHASubscribe_ &= (bool)_subscriptionManager;
3506 Lock<Mutex> l(_lock);
3508 _message.setCommandEnum(Message::Command::DeltaSubscribe);
3509 _message.newCommandId();
3510 std::string subId(subId_);
3513 subId = _message.getCommandId();
3515 _message.setSubscriptionId(subId);
3520 unsigned ackTypes = Message::AckType::Processed;
3522 if (!bookmark_.empty() && _bookmarkStore.isValid())
3524 ackTypes |= Message::AckType::Persisted;
3526 _message.setTopic(topic_);
3527 if (filter_.length())
3529 _message.setFilter(filter_);
3531 if (bookmark_.length())
3536 Message::Field mostRecent = _bookmarkStore.getMostRecent(subIdField);
3537 _message.assignOwnershipBookmark(mostRecent);
3541 _message.setBookmark(bookmark_);
3542 if (_bookmarkStore.isValid())
3547 _bookmarkStore.log(_message);
3548 _bookmarkStore.discard(_message);
3549 _bookmarkStore.persisted(subIdField, _message.getBookmark());
3554 if (options_.length())
3556 _message.setOptions(options_);
3558 Message message = _message;
3561 message = _message.deepCopy();
3562 Unlock<Mutex> u(_lock);
3563 _subscriptionManager->subscribe(messageHandler_, message,
3564 Message::AckType::None);
3565 if (_badTimeToHASubscribe)
3570 if (!_routes.hasRoute(message.getSubscriptionId()))
3572 _routes.addRoute(message.getSubscriptionId(), messageHandler_,
3573 Message::AckType::None, ackTypes, message.getCommandEnum());
3575 message.setAckTypeEnum(ackTypes);
3576 if (!options_.empty())
3578 message.setOptions(options_);
3582 syncAckProcessing(timeout_, message, isHASubscribe_);
3584 catch (
const DisconnectedException&)
3586 if (!isHASubscribe_)
3588 _routes.removeRoute(subIdField);
3592 catch (
const TimedOutException&)
3594 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subIdField));
3602 Unlock<Mutex> unlock(_lock);
3603 _subscriptionManager->unsubscribe(subIdField);
3605 _routes.removeRoute(subIdField);
3611 void unsubscribe(
const std::string&
id)
3613 Lock<Mutex> l(_lock);
3614 unsubscribeInternal(
id);
3617 void unsubscribe(
void)
3619 if (_subscriptionManager)
3621 _subscriptionManager->clear();
3624 _routes.unsubscribeAll();
3625 Lock<Mutex> l(_lock);
3627 _message.setCommandEnum(Message::Command::Unsubscribe);
3628 _message.newCommandId();
3629 _message.setSubscriptionId(
"all");
3630 _sendWithoutRetry(_message);
3632 deferredExecution(&s_noOpFn, NULL);
3635 std::string sow(
const MessageHandler& messageHandler_,
3636 const std::string& topic_,
3637 const std::string& filter_ =
"",
3638 const std::string& orderBy_ =
"",
3639 const std::string& bookmark_ =
"",
3640 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
3641 int topN_ = AMPS_DEFAULT_TOP_N,
3642 const std::string& options_ =
"",
3643 long timeout_ = AMPS_DEFAULT_COMMAND_TIMEOUT)
3645 Lock<Mutex> l(_lock);
3647 _message.setCommandEnum(Message::Command::SOW);
3648 _message.newCommandId();
3650 std::string commandId = _message.getCommandId();
3651 _message.setQueryID(_message.getCommandId());
3652 unsigned ackTypes = Message::AckType::Processed | Message::AckType::Completed;
3653 _message.setAckTypeEnum(ackTypes);
3654 _message.setTopic(topic_);
3655 if (filter_.length())
3657 _message.setFilter(filter_);
3659 if (orderBy_.length())
3661 _message.setOrderBy(orderBy_);
3663 if (bookmark_.length())
3665 _message.setBookmark(bookmark_);
3667 _message.setBatchSize(AMPS::asString(batchSize_));
3668 if (topN_ != AMPS_DEFAULT_TOP_N)
3670 _message.setTopNRecordsReturned(AMPS::asString(topN_));
3672 if (options_.length())
3674 _message.setOptions(options_);
3677 _routes.addRoute(_message.getQueryID(), messageHandler_,
3678 Message::AckType::None, ackTypes, _message.getCommandEnum());
3682 syncAckProcessing(timeout_, _message);
3686 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId));
3693 std::string sow(
const MessageHandler& messageHandler_,
3694 const std::string& topic_,
3696 const std::string& filter_ =
"",
3697 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
3698 int topN_ = AMPS_DEFAULT_TOP_N)
3701 return sow(messageHandler_,
3712 std::string sowAndSubscribe(
const MessageHandler& messageHandler_,
3713 const std::string& topic_,
3714 const std::string& filter_ =
"",
3715 const std::string& orderBy_ =
"",
3716 const std::string& bookmark_ =
"",
3717 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
3718 int topN_ = AMPS_DEFAULT_TOP_N,
3719 const std::string& options_ =
"",
3720 long timeout_ = AMPS_DEFAULT_COMMAND_TIMEOUT,
3721 bool isHASubscribe_ =
true)
3723 isHASubscribe_ &= (bool)_subscriptionManager;
3724 unsigned ackTypes = Message::AckType::Processed;
3725 Lock<Mutex> l(_lock);
3727 _message.setCommandEnum(Message::Command::SOWAndSubscribe);
3728 _message.newCommandId();
3729 Field cid = _message.getCommandId();
3730 std::string subId = cid;
3731 _message.setQueryID(cid).setSubscriptionId(cid).setTopic(topic_);
3732 if (filter_.length())
3734 _message.setFilter(filter_);
3736 if (orderBy_.length())
3738 _message.setOrderBy(orderBy_);
3740 if (bookmark_.length())
3742 _message.setBookmark(bookmark_);
3743 Message::Field bookmark = _message.getBookmark();
3744 if (_bookmarkStore.isValid())
3746 ackTypes |= Message::AckType::Persisted;
3749 _message.assignOwnershipBookmark(_bookmarkStore.getMostRecent(_message.getSubscriptionId()));
3754 _bookmarkStore.log(_message);
3755 if (!BookmarkRange::isRange(bookmark))
3757 _bookmarkStore.discard(_message);
3758 _bookmarkStore.persisted(_message.getSubscriptionId(),
3768 _message.setBatchSize(AMPS::asString(batchSize_));
3769 if (topN_ != AMPS_DEFAULT_TOP_N)
3771 _message.setTopNRecordsReturned(AMPS::asString(topN_));
3773 if (options_.length())
3775 _message.setOptions(options_);
3778 Message message = _message;
3781 message = _message.deepCopy();
3782 Unlock<Mutex> u(_lock);
3783 _subscriptionManager->subscribe(messageHandler_, message,
3784 Message::AckType::None);
3785 if (_badTimeToHASubscribe)
3790 _routes.addRoute(cid, messageHandler_,
3791 Message::AckType::None, ackTypes, message.getCommandEnum());
3792 message.setAckTypeEnum(ackTypes);
3793 if (!options_.empty())
3795 message.setOptions(options_);
3799 syncAckProcessing(timeout_, message, isHASubscribe_);
3801 catch (
const DisconnectedException&)
3803 if (!isHASubscribe_)
3805 _routes.removeRoute(subId);
3809 catch (
const TimedOutException&)
3811 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subId));
3819 Unlock<Mutex> unlock(_lock);
3820 _subscriptionManager->unsubscribe(cid);
3822 _routes.removeRoute(subId);
3828 std::string sowAndSubscribe(
const MessageHandler& messageHandler_,
3829 const std::string& topic_,
3831 const std::string& filter_ =
"",
3832 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
3833 bool oofEnabled_ =
false,
3834 int topN_ = AMPS_DEFAULT_TOP_N,
3835 bool isHASubscribe_ =
true)
3838 return sowAndSubscribe(messageHandler_,
3845 (oofEnabled_ ?
"oof" :
""),
3850 std::string sowAndDeltaSubscribe(
const MessageHandler& messageHandler_,
3851 const std::string& topic_,
3852 const std::string& filter_ =
"",
3853 const std::string& orderBy_ =
"",
3854 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
3855 int topN_ = AMPS_DEFAULT_TOP_N,
3856 const std::string& options_ =
"",
3857 long timeout_ = AMPS_DEFAULT_COMMAND_TIMEOUT,
3858 bool isHASubscribe_ =
true)
3860 isHASubscribe_ &= (bool)_subscriptionManager;
3861 Lock<Mutex> l(_lock);
3863 _message.setCommandEnum(Message::Command::SOWAndDeltaSubscribe);
3864 _message.newCommandId();
3865 _message.setQueryID(_message.getCommandId());
3866 _message.setSubscriptionId(_message.getCommandId());
3867 std::string subId = _message.getSubscriptionId();
3868 _message.setTopic(topic_);
3869 if (filter_.length())
3871 _message.setFilter(filter_);
3873 if (orderBy_.length())
3875 _message.setOrderBy(orderBy_);
3877 _message.setBatchSize(AMPS::asString(batchSize_));
3878 if (topN_ != AMPS_DEFAULT_TOP_N)
3880 _message.setTopNRecordsReturned(AMPS::asString(topN_));
3882 if (options_.length())
3884 _message.setOptions(options_);
3886 Message message = _message;
3889 message = _message.deepCopy();
3890 Unlock<Mutex> u(_lock);
3891 _subscriptionManager->subscribe(messageHandler_, message,
3892 Message::AckType::None);
3893 if (_badTimeToHASubscribe)
3898 _routes.addRoute(message.getQueryID(), messageHandler_,
3899 Message::AckType::None, Message::AckType::Processed, message.getCommandEnum());
3900 message.setAckTypeEnum(Message::AckType::Processed);
3901 if (!options_.empty())
3903 message.setOptions(options_);
3907 syncAckProcessing(timeout_, message, isHASubscribe_);
3909 catch (
const DisconnectedException&)
3911 if (!isHASubscribe_)
3913 _routes.removeRoute(subId);
3917 catch (
const TimedOutException&)
3919 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subId));
3927 Unlock<Mutex> unlock(_lock);
3928 _subscriptionManager->unsubscribe(Field(subId));
3930 _routes.removeRoute(subId);
3936 std::string sowAndDeltaSubscribe(
const MessageHandler& messageHandler_,
3937 const std::string& topic_,
3939 const std::string& filter_ =
"",
3940 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
3941 bool oofEnabled_ =
false,
3942 bool sendEmpties_ =
false,
3943 int topN_ = AMPS_DEFAULT_TOP_N,
3944 bool isHASubscribe_ =
true)
3947 Message::Options options;
3952 if (sendEmpties_ ==
false)
3954 options.setNoEmpties();
3956 return sowAndDeltaSubscribe(messageHandler_,
3967 std::string sowDelete(
const MessageHandler& messageHandler_,
3968 const std::string& topic_,
3969 const std::string& filter_,
3971 Message::Field commandId_ = Message::Field())
3973 if (_publishStore.isValid())
3975 unsigned ackType = Message::AckType::Processed |
3976 Message::AckType::Stats |
3977 Message::AckType::Persisted;
3978 publishStoreMessage.reset();
3979 if (commandId_.empty())
3986 publishStoreMessage.
setCommandId(commandId_.data(), commandId_.len());
3994 amps_uint64_t haSequenceNumber = _publishStore.store(publishStoreMessage);
3995 char buf[AMPS_NUMBER_BUFFER_LEN];
3996 size_t pos = convertToCharArray(buf, haSequenceNumber);
3997 publishStoreMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
4001 Lock<Mutex> l(_lock);
4002 _routes.addRoute(commandId_, messageHandler_,
4003 Message::AckType::Stats,
4004 Message::AckType::Processed | Message::AckType::Persisted,
4006 syncAckProcessing(timeout_, publishStoreMessage,
4009 catch (
const DisconnectedException&)
4016 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4020 return (std::string)commandId_;
4024 Lock<Mutex> l(_lock);
4026 if (commandId_.empty())
4028 _message.newCommandId();
4029 commandId_ = _message.getCommandId();
4033 _message.setCommandId(commandId_.data(), commandId_.len());
4035 _message.setCommandEnum(Message::Command::SOWDelete)
4036 .assignSubscriptionId(commandId_.data(), commandId_.len())
4037 .assignQueryID(commandId_.data(), commandId_.len())
4038 .setAckTypeEnum(Message::AckType::Processed |
4039 Message::AckType::Stats)
4040 .assignTopic(topic_.c_str(), topic_.length())
4041 .assignFilter(filter_.c_str(), filter_.length());
4042 _routes.addRoute(commandId_, messageHandler_,
4043 Message::AckType::Stats,
4044 Message::AckType::Processed,
4045 _message.getCommandEnum());
4048 syncAckProcessing(timeout_, _message);
4052 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4055 return (std::string)commandId_;
4059 std::string sowDeleteByData(
const MessageHandler& messageHandler_,
4060 const std::string& topic_,
4061 const std::string& data_,
4063 Message::Field commandId_ = Message::Field())
4065 if (_publishStore.isValid())
4067 unsigned ackType = Message::AckType::Processed |
4068 Message::AckType::Stats |
4069 Message::AckType::Persisted;
4070 publishStoreMessage.reset();
4071 if (commandId_.empty())
4078 publishStoreMessage.
setCommandId(commandId_.data(), commandId_.len());
4085 .assignData(data_.c_str(), data_.length());
4086 amps_uint64_t haSequenceNumber = _publishStore.store(publishStoreMessage);
4087 char buf[AMPS_NUMBER_BUFFER_LEN];
4088 size_t pos = convertToCharArray(buf, haSequenceNumber);
4089 publishStoreMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
4093 Lock<Mutex> l(_lock);
4094 _routes.addRoute(commandId_, messageHandler_,
4095 Message::AckType::Stats,
4096 Message::AckType::Processed | Message::AckType::Persisted,
4098 syncAckProcessing(timeout_, publishStoreMessage,
4101 catch (
const DisconnectedException&)
4108 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4112 return (std::string)commandId_;
4116 Lock<Mutex> l(_lock);
4118 if (commandId_.empty())
4120 _message.newCommandId();
4121 commandId_ = _message.getCommandId();
4125 _message.setCommandId(commandId_.data(), commandId_.len());
4127 _message.setCommandEnum(Message::Command::SOWDelete)
4128 .assignSubscriptionId(commandId_.data(), commandId_.len())
4129 .assignQueryID(commandId_.data(), commandId_.len())
4130 .setAckTypeEnum(Message::AckType::Processed |
4131 Message::AckType::Stats)
4132 .assignTopic(topic_.c_str(), topic_.length())
4133 .assignData(data_.c_str(), data_.length());
4134 _routes.addRoute(commandId_, messageHandler_,
4135 Message::AckType::Stats,
4136 Message::AckType::Processed,
4137 _message.getCommandEnum());
4140 syncAckProcessing(timeout_, _message);
4144 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4147 return (std::string)commandId_;
4151 std::string sowDeleteByKeys(
const MessageHandler& messageHandler_,
4152 const std::string& topic_,
4153 const std::string& keys_,
4155 Message::Field commandId_ = Message::Field())
4157 if (_publishStore.isValid())
4159 unsigned ackType = Message::AckType::Processed |
4160 Message::AckType::Stats |
4161 Message::AckType::Persisted;
4162 publishStoreMessage.reset();
4163 if (commandId_.empty())
4170 publishStoreMessage.
setCommandId(commandId_.data(), commandId_.len());
4178 amps_uint64_t haSequenceNumber = _publishStore.store(publishStoreMessage);
4179 char buf[AMPS_NUMBER_BUFFER_LEN];
4180 size_t pos = convertToCharArray(buf, haSequenceNumber);
4181 publishStoreMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
4185 Lock<Mutex> l(_lock);
4186 _routes.addRoute(commandId_, messageHandler_,
4187 Message::AckType::Stats,
4188 Message::AckType::Processed | Message::AckType::Persisted,
4190 syncAckProcessing(timeout_, publishStoreMessage,
4193 catch (
const DisconnectedException&)
4200 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4204 return (std::string)commandId_;
4208 Lock<Mutex> l(_lock);
4210 if (commandId_.empty())
4212 _message.newCommandId();
4213 commandId_ = _message.getCommandId();
4217 _message.setCommandId(commandId_.data(), commandId_.len());
4219 _message.setCommandEnum(Message::Command::SOWDelete)
4220 .assignSubscriptionId(commandId_.data(), commandId_.len())
4221 .assignQueryID(commandId_.data(), commandId_.len())
4222 .setAckTypeEnum(Message::AckType::Processed |
4223 Message::AckType::Stats)
4224 .assignTopic(topic_.c_str(), topic_.length())
4225 .assignSowKeys(keys_.c_str(), keys_.length());
4226 _routes.addRoute(commandId_, messageHandler_,
4227 Message::AckType::Stats,
4228 Message::AckType::Processed,
4229 _message.getCommandEnum());
4232 syncAckProcessing(timeout_, _message);
4236 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4239 return (std::string)commandId_;
4243 void startTimer(
void)
4245 if (_serverVersion >=
"5.3.2.0")
4247 throw CommandException(
"The start_timer command is deprecated.");
4249 Lock<Mutex> l(_lock);
4251 _message.setCommandEnum(Message::Command::StartTimer);
4256 std::string stopTimer(MessageHandler messageHandler_)
4258 if (_serverVersion >=
"5.3.2.0")
4260 throw CommandException(
"The stop_timer command is deprecated.");
4262 return executeAsync(Command(
"stop_timer").addAckType(
"completed"), messageHandler_);
4277 void setExceptionListener(
const std::shared_ptr<const ExceptionListener>& pListener_)
4279 _pExceptionListener = pListener_;
4280 _exceptionListener = _pExceptionListener.get();
4283 void setExceptionListener(
const ExceptionListener& listener_)
4285 _exceptionListener = &listener_;
4288 const ExceptionListener& getExceptionListener(
void)
const
4290 return *_exceptionListener;
4293 void setHeartbeat(
unsigned heartbeatInterval_,
unsigned readTimeout_)
4295 if (readTimeout_ < heartbeatInterval_)
4297 throw UsageException(
"The socket read timeout must be >= the heartbeat interval.");
4299 Lock<Mutex> l(_lock);
4300 if (_heartbeatInterval != heartbeatInterval_ ||
4301 _readTimeout != readTimeout_)
4303 _heartbeatInterval = heartbeatInterval_;
4304 _readTimeout = readTimeout_;
4309 void _sendHeartbeat(
void)
4311 if (_connected && _heartbeatInterval != 0)
4313 std::ostringstream options;
4314 options <<
"start," << _heartbeatInterval;
4315 _beatMessage.setOptions(options.str());
4317 _heartbeatTimer.setTimeout(_heartbeatInterval * 1000.0);
4318 _heartbeatTimer.start();
4321 _sendWithoutRetry(_beatMessage);
4322 broadcastConnectionStateChanged(ConnectionStateListener::HeartbeatInitiated);
4324 catch (ConnectionException& ex_)
4328 AMPS_UNHANDLED_EXCEPTION(ex_);
4330 _beatMessage.setOptions(
"beat");
4333 if (_readTimeout && _connected)
4338 AMPSException::throwFor(_client, result);
4340 if (!_queueAckTimeout)
4343 (
int)(_heartbeatInterval * 1000));
4346 AMPSException::throwFor(_client, result);
4352 void addConnectionStateListener(ConnectionStateListener* listener_)
4354 Lock<Mutex> lock(_lock);
4355 _connectionStateListeners.insert(listener_);
4358 void removeConnectionStateListener(ConnectionStateListener* listener_)
4360 Lock<Mutex> lock(_lock);
4361 _connectionStateListeners.erase(listener_);
4364 void clearConnectionStateListeners()
4366 Lock<Mutex> lock(_lock);
4367 _connectionStateListeners.clear();
4370 void _registerHandler(Command& command_, Message::Field& cid_,
4371 MessageHandler& handler_,
unsigned requestedAcks_,
4372 unsigned systemAddedAcks_, Message::Command::Type commandType_)
4374 Message message = command_.getMessage();
4375 Message::Command::Type commandType = message.getCommandEnum();
4376 Message::Field subid = message.getSubscriptionId();
4377 Message::Field qid = message.getQueryID();
4379 bool added = qid.len() || subid.len() || cid_.len();
4380 bool cidIsQid = cid_ == qid;
4381 bool cidUnique = !cidIsQid && cid_.len() > 0 && cid_ != subid;
4383 if (subid.len() > 0)
4387 addedCount += _routes.addRoute(subid, handler_, requestedAcks_,
4388 systemAddedAcks_, commandType_);
4390 && (commandType == Message::Command::Subscribe
4391 || commandType == Message::Command::DeltaSubscribe))
4398 if (qid.len() > 0 && qid != subid
4399 && (commandType == Message::Command::SOW
4400 || commandType == Message::Command::SOWDelete
4401 || commandType == Message::Command::SOWAndSubscribe
4402 || commandType == Message::Command::SOWAndDeltaSubscribe))
4404 while (_routes.hasRoute(qid))
4406 message.newQueryId();
4409 cid_ = message.getQueryId();
4411 qid = message.getQueryId();
4413 if (addedCount == 0)
4415 _routes.addRoute(qid, handler_, requestedAcks_,
4416 systemAddedAcks_, commandType_);
4422 Unlock<Mutex> u(_lock);
4423 data = amps_invoke_copy_route_function(handler_.userData());
4427 _routes.addRoute(qid, handler_, requestedAcks_,
4428 systemAddedAcks_, commandType_);
4432 _routes.addRoute(qid,
4433 MessageHandler(handler_.function(),
4436 systemAddedAcks_, commandType_);
4441 if (cidUnique && requestedAcks_ & ~Message::AckType::Persisted)
4443 while (_routes.hasRoute(cid_))
4445 cid_ = message.newCommandId().getCommandId();
4447 if (addedCount == 0)
4449 _routes.addRoute(cid_, handler_, requestedAcks_,
4450 systemAddedAcks_, commandType_);
4456 Unlock<Mutex> u(_lock);
4457 data = amps_invoke_copy_route_function(handler_.userData());
4461 _routes.addRoute(cid_, handler_, requestedAcks_,
4462 systemAddedAcks_, commandType_);
4466 _routes.addRoute(cid_,
4467 MessageHandler(handler_.function(),
4470 systemAddedAcks_, commandType_);
4474 else if ((commandType == Message::Command::Publish ||
4475 commandType == Message::Command::DeltaPublish)
4476 && requestedAcks_ & ~Message::AckType::Persisted)
4478 cid_ = command_.getMessage().newCommandId().getCommandId();
4479 _routes.addRoute(cid_, handler_, requestedAcks_,
4480 systemAddedAcks_, commandType_);
4485 throw UsageException(
"To use a messagehandler, you must also supply a command or subscription ID.");
4489 std::string executeAsyncNoLock(Command& command_, MessageHandler& handler_,
4490 bool isHASubscribe_ =
true)
4492 isHASubscribe_ &= (bool)_subscriptionManager;
4493 Message& message = command_.getMessage();
4494 unsigned systemAddedAcks = (handler_.isValid() || command_.hasProcessedAck()) ?
4495 Message::AckType::Processed : Message::AckType::None;
4496 unsigned requestedAcks = message.getAckTypeEnum();
4497 bool isPublishStore = _publishStore.isValid() && command_.needsSequenceNumber();
4498 Message::Command::Type commandType = message.getCommandEnum();
4499 if (commandType == Message::Command::StopTimer)
4501 systemAddedAcks |= Message::AckType::Completed;
4503 else if (commandType == Message::Command::Unsubscribe)
4506 const std::string subId = message.getSubscriptionId();
4509 _routes.unsubscribeAll();
4510 if (_subscriptionManager)
4512 Unlock<Mutex> unlock(_lock);
4513 _subscriptionManager->clear();
4518 _routes.removeRoute(subId);
4520 if (_subscriptionManager)
4523 Unlock<Mutex> unlock(_lock);
4524 _subscriptionManager->unsubscribe(subId);
4528 deferredExecution(&s_noOpFn, NULL);
4530 Message::Field cid = message.getCommandId();
4531 if (handler_.isValid() && cid.empty())
4533 cid = message.newCommandId().getCommandId();
4535 if (message.getBookmark().len() > 0)
4537 if (command_.isSubscribe())
4539 Message::Field bookmark = message.getBookmark();
4540 if (_bookmarkStore.isValid())
4542 systemAddedAcks |= Message::AckType::Persisted;
4545 message.assignOwnershipBookmark(_bookmarkStore.getMostRecent(message.getSubscriptionId()));
4550 _bookmarkStore.log(message);
4551 if (!BookmarkRange::isRange(bookmark))
4553 _bookmarkStore.discard(message);
4554 _bookmarkStore.persisted(message.getSubscriptionId(),
4567 systemAddedAcks |= Message::AckType::Persisted;
4569 bool isSubscribe = command_.isSubscribe();
4570 if (handler_.isValid() && !isSubscribe)
4572 _registerHandler(command_, cid, handler_,
4573 requestedAcks, systemAddedAcks, commandType);
4577 bool useSyncSend = cid.len() > 0 && command_.hasProcessedAck();
4578 amps_uint64_t haSequenceNumber = (amps_uint64_t)0;
4579 message.setAckTypeEnum(requestedAcks | systemAddedAcks);
4581 Unlock<Mutex> u(_lock);
4582 haSequenceNumber = _publishStore.store(message);
4584 message.setSequence(haSequenceNumber);
4589 syncAckProcessing((
long)command_.getTimeout(), message,
4594 _send(message, haSequenceNumber,
false,
4595 commandType & (Message::Command::Publish
4596 | Message::Command::DeltaPublish));
4599 catch (
const DisconnectedException&)
4605 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
4613 const Message::Field& subId = message.getSubscriptionId();
4616 Unlock<Mutex> u(_lock);
4617 _subscriptionManager->subscribe(handler_,
4620 if (_badTimeToHASubscribe)
4622 message.setAckTypeEnum(requestedAcks);
4623 return std::string(subId.data(), subId.len());
4626 if (handler_.isValid())
4628 _registerHandler(command_, cid, handler_,
4629 requestedAcks, systemAddedAcks, commandType);
4631 message.setAckTypeEnum(requestedAcks | systemAddedAcks);
4634 syncAckProcessing((
long)command_.getTimeout(), message,
4637 catch (
const DisconnectedException&)
4639 if (!isHASubscribe_)
4641 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
4642 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(subId));
4643 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(message.getQueryId()));
4644 message.setAckTypeEnum(requestedAcks);
4648 catch (
const TimedOutException&)
4650 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(cid));
4651 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subId));
4652 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(message.getQueryId()));
4653 message.setAckTypeEnum(requestedAcks);
4661 Unlock<Mutex> unlock(_lock);
4662 _subscriptionManager->unsubscribe(subId);
4664 if (message.getQueryID().len() > 0)
4666 _routes.removeRoute(message.getQueryID());
4668 _routes.removeRoute(cid);
4669 _routes.removeRoute(subId);
4670 message.setAckTypeEnum(requestedAcks);
4673 if (subId.len() > 0)
4675 message.setAckTypeEnum(requestedAcks);
4676 return std::string(subId.data(), subId.len());
4682 bool useSyncSend = commandType & ~Message::Command::NoDataCommands
4683 || (cid.len() > 0 && command_.hasProcessedAck());
4684 message.setAckTypeEnum(requestedAcks | systemAddedAcks);
4689 syncAckProcessing((
long)(command_.getTimeout()), message);
4693 _send(message, 0,
false,
4694 commandType & (Message::Command::Publish
4695 | Message::Command::DeltaPublish));
4698 catch (
const TimedOutException&)
4700 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(cid));
4701 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(message.getQueryId()));
4702 message.setAckTypeEnum(requestedAcks);
4705 catch (
const DisconnectedException&)
4707 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
4708 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(message.getQueryId()));
4709 message.setAckTypeEnum(requestedAcks);
4714 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
4715 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(message.getQueryId()));
4716 message.setAckTypeEnum(requestedAcks);
4721 message.setAckTypeEnum(requestedAcks);
4725 MessageStream getEmptyMessageStream(
void);
4727 std::string executeAsync(Command& command_, MessageHandler& handler_,
4728 bool isHASubscribe_ =
true)
4730 Lock<Mutex> lock(_lock);
4731 return executeAsyncNoLock(command_, handler_, isHASubscribe_);
4735 void setAutoAck(
bool isAutoAckEnabled_)
4737 _isAutoAckEnabled = isAutoAckEnabled_;
4739 bool getAutoAck(
void)
const
4741 return _isAutoAckEnabled;
4743 void setAckBatchSize(
const unsigned batchSize_)
4745 _ackBatchSize = batchSize_;
4746 if (!_queueAckTimeout)
4748 _queueAckTimeout = AMPS_DEFAULT_QUEUE_ACK_TIMEOUT;
4752 unsigned getAckBatchSize(
void)
const
4754 return _ackBatchSize;
4756 int getAckTimeout(
void)
const
4758 return _queueAckTimeout;
4760 void setAckTimeout(
const int ackTimeout_)
4763 _queueAckTimeout = ackTimeout_;
4765 size_t _ack(QueueBookmarks& queueBookmarks_)
4767 if (queueBookmarks_._bookmarkCount)
4769 publishStoreMessage.reset();
4774 amps_uint64_t haSequenceNumber = 0;
4775 if (_publishStore.isValid())
4777 haSequenceNumber = _publishStore.store(publishStoreMessage);
4780 queueBookmarks_._data.erase();
4781 queueBookmarks_._bookmarkCount = 0;
4783 _send(publishStoreMessage, haSequenceNumber);
4784 if (!_publishStore.isValid())
4786 queueBookmarks_._data.erase();
4787 queueBookmarks_._bookmarkCount = 0;
4793 void ack(
const Field& topic_,
const Field& bookmark_,
const char* options_ = NULL)
4795 if (_isAutoAckEnabled)
4799 _ack(topic_, bookmark_, options_);
4801 void _ack(
const Field& topic_,
const Field& bookmark_,
const char* options_ = NULL)
4803 if (bookmark_.len() == 0)
4807 Lock<Mutex> lock(_lock);
4808 if (_ackBatchSize < 2 || options_ != NULL)
4810 publishStoreMessage.reset();
4818 amps_uint64_t haSequenceNumber = 0;
4819 if (_publishStore.isValid())
4821 haSequenceNumber = _publishStore.store(publishStoreMessage);
4825 _send(publishStoreMessage, haSequenceNumber);
4829 topic_hash hash = CRC<0>::crcNoSSE(topic_.data(), topic_.len());
4830 TopicHashMap::iterator it = _topicHashMap.find(hash);
4831 if (it == _topicHashMap.end())
4834 #ifdef AMPS_USE_EMPLACE
4835 it = _topicHashMap.emplace(TopicHashMap::value_type(hash, QueueBookmarks(topic_))).first;
4837 it = _topicHashMap.insert(TopicHashMap::value_type(hash, QueueBookmarks(topic_))).first;
4840 QueueBookmarks& queueBookmarks = it->second;
4841 if (queueBookmarks._data.length())
4843 queueBookmarks._data.append(
",");
4847 queueBookmarks._oldestTime = amps_now();
4849 queueBookmarks._data.append(bookmark_);
4850 if (++queueBookmarks._bookmarkCount >= _ackBatchSize)
4852 _ack(queueBookmarks);
4855 void flushAcks(
void)
4857 size_t sendCount = 0;
4864 Lock<Mutex> lock(_lock);
4865 typedef TopicHashMap::iterator iterator;
4866 for (iterator it = _topicHashMap.begin(), end = _topicHashMap.end(); it != end; ++it)
4868 QueueBookmarks& queueBookmarks = it->second;
4869 sendCount += _ack(queueBookmarks);
4872 if (sendCount && _connected)
4874 publishFlush(0, Message::AckType::Processed);
4878 void checkQueueAcks(
void)
4880 if (!_topicHashMap.size())
4884 Lock<Mutex> lock(_lock);
4887 amps_uint64_t threshold = amps_now()
4888 - (amps_uint64_t)_queueAckTimeout;
4889 typedef TopicHashMap::iterator iterator;
4890 for (iterator it = _topicHashMap.begin(), end = _topicHashMap.end(); it != end; ++it)
4892 QueueBookmarks& queueBookmarks = it->second;
4893 if (queueBookmarks._bookmarkCount && queueBookmarks._oldestTime < threshold)
4895 _ack(queueBookmarks);
4899 catch (std::exception& ex)
4901 AMPS_UNHANDLED_EXCEPTION(ex);
4905 void deferredExecution(DeferredExecutionFunc func_,
void* userData_)
4907 Lock<Mutex> lock(_deferredExecutionLock);
4908 #ifdef AMPS_USE_EMPLACE
4909 _deferredExecutionList.emplace_back(
4910 DeferredExecutionRequest(func_, userData_));
4912 _deferredExecutionList.push_back(
4913 DeferredExecutionRequest(func_, userData_));
4917 inline void processDeferredExecutions(
void)
4919 if (_deferredExecutionList.size())
4921 Lock<Mutex> lock(_deferredExecutionLock);
4922 DeferredExecutionList::iterator it = _deferredExecutionList.begin();
4923 DeferredExecutionList::iterator end = _deferredExecutionList.end();
4924 for (; it != end; ++it)
4928 it->_func(it->_userData);
4936 _deferredExecutionList.clear();
4937 _routes.invalidateCache();
4938 _routeCache.invalidateCache();
4942 bool getRetryOnDisconnect(
void)
const
4944 return _isRetryOnDisconnect;
4947 void setRetryOnDisconnect(
bool isRetryOnDisconnect_)
4949 _isRetryOnDisconnect = isRetryOnDisconnect_;
4952 void setDefaultMaxDepth(
unsigned maxDepth_)
4954 _defaultMaxDepth = maxDepth_;
4957 unsigned getDefaultMaxDepth(
void)
const
4959 return _defaultMaxDepth;
4974 void setPublishBatching(amps_uint64_t batchSizeBytes_, amps_uint64_t batchTimeoutMillis_)
5057 RefHandle<MessageStreamImpl> _body;
5067 inline void advance(
void);
5074 : _pStream(pStream_)
5079 bool operator==(
const iterator& rhs)
const
5081 return _pStream == rhs._pStream;
5083 bool operator!=(
const iterator& rhs)
const
5085 return _pStream != rhs._pStream;
5087 void operator++(
void)
5103 return _body.isValid();
5110 if (!_body.isValid())
5112 throw UsageException(
"This MessageStream is not valid and cannot be iterated.");
5152 inline void setSOWOnly(
const std::string& commandId_,
5153 const std::string& queryId_ =
"");
5154 inline void setSubscription(
const std::string& subId_,
5155 const std::string& commandId_ =
"",
5156 const std::string& queryId_ =
"");
5157 inline void setStatsOnly(
const std::string& commandId_,
5158 const std::string& queryId_ =
"");
5159 inline void setAcksOnly(
const std::string& commandId_,
unsigned acks_);
5166 friend class ClientImpl;
5192 BorrowRefHandle<ClientImpl> _body;
5194 static const int DEFAULT_COMMAND_TIMEOUT = AMPS_DEFAULT_COMMAND_TIMEOUT;
5195 static const int DEFAULT_BATCH_SIZE = AMPS_DEFAULT_BATCH_SIZE;
5196 static const int DEFAULT_TOP_N = AMPS_DEFAULT_TOP_N;
5207 : _body(new ClientImpl(clientName), true)
5210 Client(ClientImpl* existingClient)
5211 : _body(existingClient, true)
5214 Client(ClientImpl* existingClient,
bool isRef)
5215 : _body(existingClient, isRef)
5219 virtual ~
Client(
void) {;}
5229 return _body.isValid();
5246 _body.get().setName(name);
5253 return _body.get().getName();
5261 return _body.get().getNameHash();
5269 return _body.get().getNameHashValue();
5280 _body.get().setLogonCorrelationData(logonCorrelationData_);
5287 return _body.get().getLogonCorrelationData();
5295 _body.get().addHttpPreflightHeader(header_);
5304 _body.get().addHttpPreflightHeader(key_, value_);
5310 _body.get().clearHttpPreflightHeaders();
5319 _body.get().setHttpPreflightHeaders(headers_);
5332 return _body.get().getServerVersion();
5343 return _body.get().getServerVersionInfo();
5357 return AMPS::convertVersionToNumber(version_.c_str(), version_.length());
5372 return AMPS::convertVersionToNumber(data_, len_);
5379 return _body.get().getURI();
5403 _body.get().connect(uri);
5410 _body.get().disconnect();
5428 _body.get().send(message);
5441 unsigned requestedAcks_,
bool isSubscribe_)
5443 Message::Command::Type commandType = isSubscribe_ ? Message::Command::Subscribe : Message::Command::SOW;
5444 _body.get().addMessageHandler(commandId_, messageHandler_,
5445 requestedAcks_, commandType);
5458 unsigned requestedAcks_, Message::Command::Type commandType_)
5460 _body.get().addMessageHandler(commandId_, messageHandler_,
5461 requestedAcks_, commandType_);
5469 return _body.get().removeMessageHandler(commandId_);
5497 return _body.get().send(messageHandler, message, timeout);
5513 #if defined(_WIN32) || __cplusplus >= 201402L
5514 [[deprecated(
"Use HAClient for automatic reconnection and a ConnectionStateListener to monitor connection state.")]]
5518 _body.get().setDisconnectHandler(disconnectHandler);
5527 #if defined(_WIN32) || __cplusplus >= 201402L
5528 [[deprecated(
"Use HAClient for automatic reconnection and a ConnectionStateListener to monitor connection state.")]]
5532 return _body.get().getDisconnectHandler();
5541 return _body.get().getConnectionInfo();
5554 _body.get().setBookmarkStore(bookmarkStore_);
5562 return _body.
get().getBookmarkStore();
5570 return _body.get().getSubscriptionManager();
5582 _body.get().setSubscriptionManager(subscriptionManager_);
5606 _body.get().setPublishStore(publishStore_);
5614 return _body.
get().getPublishStore();
5622 _body.get().setGlobalCommandTypeMessageHandler(ClientImpl::GlobalCommandTypeHandlers::DuplicateMessage,
5623 duplicateMessageHandler_);
5637 return _body.get().getDuplicateMessageHandler();
5651 _body.get().setFailedWriteHandler(handler_);
5659 return _body.get().getFailedWriteHandler();
5680 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_)
5682 return _body.get().publish(topic_.c_str(), topic_.length(),
5683 data_.c_str(), data_.length());
5705 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
5706 const char* data_,
size_t dataLength_)
5708 return _body.get().publish(topic_, topicLength_, data_, dataLength_);
5729 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_,
5730 unsigned long expiration_)
5732 return _body.get().publish(topic_.c_str(), topic_.length(),
5733 data_.c_str(), data_.length(), expiration_);
5756 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
5757 const char* data_,
size_t dataLength_,
5758 unsigned long expiration_)
5760 return _body.get().publish(topic_, topicLength_,
5761 data_, dataLength_, expiration_);
5802 void publishFlush(
long timeout_ = 0,
unsigned ackType_ = Message::AckType::Processed)
5804 _body.get().publishFlush(timeout_, ackType_);
5823 amps_uint64_t
deltaPublish(
const std::string& topic_,
const std::string& data_)
5825 return _body.get().deltaPublish(topic_.c_str(), topic_.length(),
5826 data_.c_str(), data_.length());
5847 const char* data_,
size_t dataLength_)
5849 return _body.get().deltaPublish(topic_, topicLength_,
5850 data_, dataLength_);
5869 amps_uint64_t
deltaPublish(
const std::string& topic_,
const std::string& data_,
5870 unsigned long expiration_)
5872 return _body.get().deltaPublish(topic_.c_str(), topic_.length(),
5873 data_.c_str(), data_.length(),
5896 const char* data_,
size_t dataLength_,
5897 unsigned long expiration_)
5899 return _body.get().deltaPublish(topic_, topicLength_,
5900 data_, dataLength_, expiration_);
5920 const char* options_ = NULL)
5922 return _body.get().logon(timeout_, authenticator_, options_);
5937 std::string
logon(
const char* options_,
int timeout_ = 0)
5956 std::string
logon(
const std::string& options_,
int timeout_ = 0)
5982 const std::string& topic_,
5984 const std::string& filter_ =
"",
5985 const std::string& options_ =
"",
5986 const std::string& subId_ =
"")
5988 return _body.get().subscribe(messageHandler_, topic_, timeout_,
5989 filter_,
"", options_, subId_);
6008 long timeout_ = 0,
const std::string& filter_ =
"",
6009 const std::string& options_ =
"",
6010 const std::string& subId_ =
"")
6013 if (_body.get().getDefaultMaxDepth())
6015 result.
maxDepth(_body.get().getDefaultMaxDepth());
6017 result.setSubscription(_body.get().subscribe(
6019 topic_, timeout_, filter_,
"",
6020 options_, subId_,
false));
6040 long timeout_ = 0,
const std::string& filter_ =
"",
6041 const std::string& options_ =
"",
6042 const std::string& subId_ =
"")
6045 if (_body.get().getDefaultMaxDepth())
6047 result.
maxDepth(_body.get().getDefaultMaxDepth());
6049 result.setSubscription(_body.get().subscribe(
6051 topic_, timeout_, filter_,
"",
6052 options_, subId_,
false));
6069 const std::string& topic_,
6071 const std::string& filter_ =
"",
6072 const std::string& options_ =
"",
6073 const std::string& subId_ =
"")
6075 return _body.get().deltaSubscribe(messageHandler_, topic_, timeout_,
6076 filter_,
"", options_, subId_);
6087 long timeout_,
const std::string& filter_ =
"",
6088 const std::string& options_ =
"",
6089 const std::string& subId_ =
"")
6092 if (_body.get().getDefaultMaxDepth())
6094 result.
maxDepth(_body.get().getDefaultMaxDepth());
6096 result.setSubscription(_body.get().deltaSubscribe(
6098 topic_, timeout_, filter_,
"",
6099 options_, subId_,
false));
6105 long timeout_,
const std::string& filter_ =
"",
6106 const std::string& options_ =
"",
6107 const std::string& subId_ =
"")
6110 if (_body.get().getDefaultMaxDepth())
6112 result.
maxDepth(_body.get().getDefaultMaxDepth());
6114 result.setSubscription(_body.get().deltaSubscribe(
6116 topic_, timeout_, filter_,
"",
6117 options_, subId_,
false));
6147 const std::string& topic_,
6149 const std::string& bookmark_,
6150 const std::string& filter_ =
"",
6151 const std::string& options_ =
"",
6152 const std::string& subId_ =
"")
6154 return _body.get().subscribe(messageHandler_, topic_, timeout_,
6155 filter_, bookmark_, options_, subId_);
6176 const std::string& bookmark_,
6177 const std::string& filter_ =
"",
6178 const std::string& options_ =
"",
6179 const std::string& subId_ =
"")
6182 if (_body.get().getDefaultMaxDepth())
6184 result.
maxDepth(_body.get().getDefaultMaxDepth());
6186 result.setSubscription(_body.get().subscribe(
6188 topic_, timeout_, filter_,
6189 bookmark_, options_,
6197 const std::string& bookmark_,
6198 const std::string& filter_ =
"",
6199 const std::string& options_ =
"",
6200 const std::string& subId_ =
"")
6203 if (_body.get().getDefaultMaxDepth())
6205 result.
maxDepth(_body.get().getDefaultMaxDepth());
6207 result.setSubscription(_body.get().subscribe(
6209 topic_, timeout_, filter_,
6210 bookmark_, options_,
6225 return _body.get().unsubscribe(commandId);
6237 return _body.get().unsubscribe();
6271 const std::string& topic_,
6272 const std::string& filter_ =
"",
6273 const std::string& orderBy_ =
"",
6274 const std::string& bookmark_ =
"",
6275 int batchSize_ = DEFAULT_BATCH_SIZE,
6276 int topN_ = DEFAULT_TOP_N,
6277 const std::string& options_ =
"",
6278 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6280 return _body.get().sow(messageHandler_, topic_, filter_, orderBy_,
6281 bookmark_, batchSize_, topN_, options_,
6309 const std::string& filter_ =
"",
6310 const std::string& orderBy_ =
"",
6311 const std::string& bookmark_ =
"",
6312 int batchSize_ = DEFAULT_BATCH_SIZE,
6313 int topN_ = DEFAULT_TOP_N,
6314 const std::string& options_ =
"",
6315 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6318 if (_body.get().getDefaultMaxDepth())
6320 result.
maxDepth(_body.get().getDefaultMaxDepth());
6322 result.setSOWOnly(_body.get().sow(result.operator
MessageHandler(),
6323 topic_, filter_, orderBy_, bookmark_,
6324 batchSize_, topN_, options_, timeout_));
6330 const std::string& filter_ =
"",
6331 const std::string& orderBy_ =
"",
6332 const std::string& bookmark_ =
"",
6333 int batchSize_ = DEFAULT_BATCH_SIZE,
6334 int topN_ = DEFAULT_TOP_N,
6335 const std::string& options_ =
"",
6336 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6339 if (_body.get().getDefaultMaxDepth())
6341 result.
maxDepth(_body.get().getDefaultMaxDepth());
6343 result.setSOWOnly(_body.get().sow(result.operator
MessageHandler(),
6344 topic_, filter_, orderBy_, bookmark_,
6345 batchSize_, topN_, options_, timeout_));
6371 const std::string& topic_,
6373 const std::string& filter_ =
"",
6374 int batchSize_ = DEFAULT_BATCH_SIZE,
6375 int topN_ = DEFAULT_TOP_N)
6377 return _body.get().sow(messageHandler_, topic_, timeout_, filter_,
6403 const std::string& topic_,
6405 const std::string& filter_ =
"",
6406 int batchSize_ = DEFAULT_BATCH_SIZE,
6407 bool oofEnabled_ =
false,
6408 int topN_ = DEFAULT_TOP_N)
6410 return _body.get().sowAndSubscribe(messageHandler_, topic_, timeout_,
6411 filter_, batchSize_, oofEnabled_,
6436 const std::string& filter_ =
"",
6437 int batchSize_ = DEFAULT_BATCH_SIZE,
6438 bool oofEnabled_ =
false,
6439 int topN_ = DEFAULT_TOP_N)
6442 if (_body.get().getDefaultMaxDepth())
6444 result.
maxDepth(_body.get().getDefaultMaxDepth());
6446 result.setSubscription(_body.get().sowAndSubscribe(
6448 topic_, timeout_, filter_,
6449 batchSize_, oofEnabled_,
6474 const std::string& filter_ =
"",
6475 int batchSize_ = DEFAULT_BATCH_SIZE,
6476 bool oofEnabled_ =
false,
6477 int topN_ = DEFAULT_TOP_N)
6480 if (_body.get().getDefaultMaxDepth())
6482 result.
maxDepth(_body.get().getDefaultMaxDepth());
6484 result.setSubscription(_body.get().sowAndSubscribe(
6486 topic_, timeout_, filter_,
6487 batchSize_, oofEnabled_,
6521 const std::string& topic_,
6522 const std::string& filter_ =
"",
6523 const std::string& orderBy_ =
"",
6524 const std::string& bookmark_ =
"",
6525 int batchSize_ = DEFAULT_BATCH_SIZE,
6526 int topN_ = DEFAULT_TOP_N,
6527 const std::string& options_ =
"",
6528 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6530 return _body.get().sowAndSubscribe(messageHandler_, topic_, filter_,
6531 orderBy_, bookmark_, batchSize_,
6532 topN_, options_, timeout_);
6560 const std::string& filter_ =
"",
6561 const std::string& orderBy_ =
"",
6562 const std::string& bookmark_ =
"",
6563 int batchSize_ = DEFAULT_BATCH_SIZE,
6564 int topN_ = DEFAULT_TOP_N,
6565 const std::string& options_ =
"",
6566 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6569 if (_body.get().getDefaultMaxDepth())
6571 result.
maxDepth(_body.get().getDefaultMaxDepth());
6573 result.setSubscription(_body.get().sowAndSubscribe(
6575 topic_, filter_, orderBy_,
6576 bookmark_, batchSize_, topN_,
6577 options_, timeout_,
false));
6583 const std::string& filter_ =
"",
6584 const std::string& orderBy_ =
"",
6585 const std::string& bookmark_ =
"",
6586 int batchSize_ = DEFAULT_BATCH_SIZE,
6587 int topN_ = DEFAULT_TOP_N,
6588 const std::string& options_ =
"",
6589 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6592 if (_body.get().getDefaultMaxDepth())
6594 result.
maxDepth(_body.get().getDefaultMaxDepth());
6596 result.setSubscription(_body.get().sowAndSubscribe(
6598 topic_, filter_, orderBy_,
6599 bookmark_, batchSize_, topN_,
6600 options_, timeout_,
false));
6629 const std::string& topic_,
6630 const std::string& filter_ =
"",
6631 const std::string& orderBy_ =
"",
6632 int batchSize_ = DEFAULT_BATCH_SIZE,
6633 int topN_ = DEFAULT_TOP_N,
6634 const std::string& options_ =
"",
6635 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6637 return _body.get().sowAndDeltaSubscribe(messageHandler_, topic_,
6638 filter_, orderBy_, batchSize_,
6639 topN_, options_, timeout_);
6662 const std::string& filter_ =
"",
6663 const std::string& orderBy_ =
"",
6664 int batchSize_ = DEFAULT_BATCH_SIZE,
6665 int topN_ = DEFAULT_TOP_N,
6666 const std::string& options_ =
"",
6667 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6670 if (_body.get().getDefaultMaxDepth())
6672 result.
maxDepth(_body.get().getDefaultMaxDepth());
6674 result.setSubscription(_body.get().sowAndDeltaSubscribe(
6676 topic_, filter_, orderBy_,
6677 batchSize_, topN_, options_,
6684 const std::string& filter_ =
"",
6685 const std::string& orderBy_ =
"",
6686 int batchSize_ = DEFAULT_BATCH_SIZE,
6687 int topN_ = DEFAULT_TOP_N,
6688 const std::string& options_ =
"",
6689 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6692 if (_body.get().getDefaultMaxDepth())
6694 result.
maxDepth(_body.get().getDefaultMaxDepth());
6696 result.setSubscription(_body.get().sowAndDeltaSubscribe(
6698 topic_, filter_, orderBy_,
6699 batchSize_, topN_, options_,
6729 const std::string& topic_,
6731 const std::string& filter_ =
"",
6732 int batchSize_ = DEFAULT_BATCH_SIZE,
6733 bool oofEnabled_ =
false,
6734 bool sendEmpties_ =
false,
6735 int topN_ = DEFAULT_TOP_N)
6737 return _body.get().sowAndDeltaSubscribe(messageHandler_, topic_,
6738 timeout_, filter_, batchSize_,
6739 oofEnabled_, sendEmpties_,
6766 const std::string& filter_ =
"",
6767 int batchSize_ = DEFAULT_BATCH_SIZE,
6768 bool oofEnabled_ =
false,
6769 bool sendEmpties_ =
false,
6770 int topN_ = DEFAULT_TOP_N)
6773 if (_body.get().getDefaultMaxDepth())
6775 result.
maxDepth(_body.get().getDefaultMaxDepth());
6777 result.setSubscription(_body.get().sowAndDeltaSubscribe(
6779 topic_, timeout_, filter_,
6780 batchSize_, oofEnabled_,
6781 sendEmpties_, topN_,
false));
6807 const std::string& filter_ =
"",
6808 int batchSize_ = DEFAULT_BATCH_SIZE,
6809 bool oofEnabled_ =
false,
6810 bool sendEmpties_ =
false,
6811 int topN_ = DEFAULT_TOP_N)
6814 if (_body.get().getDefaultMaxDepth())
6816 result.
maxDepth(_body.get().getDefaultMaxDepth());
6818 result.setSubscription(_body.get().sowAndDeltaSubscribe(
6820 topic_, timeout_, filter_,
6821 batchSize_, oofEnabled_,
6822 sendEmpties_, topN_,
false));
6845 const std::string& topic,
6846 const std::string& filter,
6849 return _body.get().sowDelete(messageHandler, topic, filter, timeout);
6871 stream.
timeout((
unsigned int)timeout_);
6878 stream.setStatsOnly(cid);
6879 _body.get().sowDelete(stream.operator
MessageHandler(), topic_, filter_, timeout_, cid);
6880 return *(stream.
begin());
6882 catch (
const DisconnectedException&)
6887 catch (
const TimedOutException&)
6900 _body.get().startTimer();
6911 return _body.get().stopTimer(messageHandler);
6936 const std::string& topic_,
6937 const std::string& keys_,
6940 return _body.get().sowDeleteByKeys(messageHandler_, topic_, keys_, timeout_);
6966 stream.
timeout((
unsigned int)timeout_);
6973 stream.setStatsOnly(cid);
6974 _body.get().sowDeleteByKeys(stream.operator
MessageHandler(), topic_, keys_, timeout_, cid);
6975 return *(stream.
begin());
6977 catch (
const DisconnectedException&)
6982 catch (
const TimedOutException&)
7004 const std::string& topic_,
const std::string& data_,
7007 return _body.get().sowDeleteByData(messageHandler_, topic_, data_, timeout_);
7028 stream.
timeout((
unsigned int)timeout_);
7035 stream.setStatsOnly(cid);
7036 _body.get().sowDeleteByData(stream.operator
MessageHandler(), topic_, data_, timeout_, cid);
7037 return *(stream.
begin());
7039 catch (
const DisconnectedException&)
7044 catch (
const TimedOutException&)
7056 return _body.get().getHandle();
7069 _body.get().setExceptionListener(pListener_);
7080 #if defined(_WIN32) || __cplusplus >= 201402L
7081 [[deprecated(
"Use setExceptionListener(std::shared_ptr<const ExceptionListener>&)")]]
7085 _body.get().setExceptionListener(listener_);
7092 return _body.get().getExceptionListener();
7118 _body.get().setHeartbeat(heartbeatTime_, readTimeout_);
7142 _body.get().setHeartbeat(heartbeatTime_, 2 * heartbeatTime_);
7146 #if defined(_WIN32) || __cplusplus >= 201402L
7147 [[deprecated(
"Use setLastChanceMessageHandler.")]]
7158 _body.get().setGlobalCommandTypeMessageHandler(ClientImpl::GlobalCommandTypeHandlers::LastChance,
7184 _body.get().setGlobalCommandTypeMessageHandler(command_, handler_);
7209 _body.get().setGlobalCommandTypeMessageHandler(command_, handler_);
7292 _body.get().addConnectionStateListener(listener);
7300 _body.get().removeConnectionStateListener(listener);
7307 _body.get().clearConnectionStateListeners();
7337 return _body.get().executeAsync(command_, handler_);
7375 if (command_.isSubscribe())
7377 Message& message = command_.getMessage();
7380 if (useExistingHandler)
7383 if (_body.get()._routes.getRoute(subId, existingHandler))
7386 _body.get().executeAsync(command_, existingHandler,
false);
7391 id = _body.get().executeAsync(command_, handler_,
false);
7393 catch (
const DisconnectedException&)
7396 if (command_.isSubscribe())
7400 if (command_.isSow())
7433 _body.get().ack(topic_, bookmark_, options_);
7455 void ack(
const std::string& topic_,
const std::string& bookmark_,
7456 const char* options_ = NULL)
7458 _body.get().ack(
Field(topic_.data(), topic_.length()),
Field(bookmark_.data(), bookmark_.length()), options_);
7466 void ackDeferredAutoAck(
Field& topic_,
Field& bookmark_,
const char* options_ = NULL)
7468 _body.get()._ack(topic_, bookmark_, options_);
7481 _body.get().flushAcks();
7490 return _body.get().getAutoAck();
7500 _body.get().setAutoAck(isAutoAckEnabled_);
7508 return _body.get().getAckBatchSize();
7518 _body.get().setAckBatchSize(ackBatchSize_);
7529 return _body.get().getAckTimeout();
7541 if (!ackTimeout_ && _body.get().getAckBatchSize() > 1)
7543 throw UsageException(
"Ack timeout must be > 0 when ack batch size > 1");
7545 _body.get().setAckTimeout(ackTimeout_);
7559 _body.get().setRetryOnDisconnect(isRetryOnDisconnect_);
7568 return _body.get().getRetryOnDisconnect();
7577 _body.get().setDefaultMaxDepth(maxDepth_);
7586 return _body.get().getDefaultMaxDepth();
7598 return _body.get().setTransportFilterFunction(filter_, userData_);
7612 return _body.get().setThreadCreatedCallback(callback_, userData_);
7623 return _body.get().setPublishBatching(batchSize_, batchTimeoutMillis_);
7631 void deferredExecution(DeferredExecutionFunc func_,
void* userData_)
7633 _body.get().deferredExecution(func_, userData_);
7643 AMPS_CALL_EXCEPTION_WRAPPER(_globalCommandTypeHandlers[GlobalCommandTypeHandlers::LastChance].invoke(message));
7649 unsigned deliveries = 0;
7661 const char* data = NULL;
7663 const char* status = NULL;
7664 size_t statusLen = 0;
7666 const size_t NotEntitled = 12, Duplicate = 9, Failure = 7;
7669 if (len == NotEntitled || len == Duplicate ||
7670 (statusLen == Failure && status[0] ==
'f'))
7672 if (_failedWriteHandler)
7674 if (_publishStore.isValid())
7676 amps_uint64_t sequence =
7678 FailedWriteStoreReplayer replayer(
this, data, len);
7679 AMPS_CALL_EXCEPTION_WRAPPER(_publishStore.replaySingle(
7680 replayer, sequence));
7684 static Message emptyMessage;
7686 AMPS_CALL_EXCEPTION_WRAPPER(
7687 _failedWriteHandler->failedWrite(emptyMessage,
7693 if (_publishStore.isValid())
7702 AMPS_CALL_EXCEPTION_WRAPPER(_publishStore.discardUpTo(seq));
7706 if (!deliveries && _bookmarkStore.isValid())
7712 Message::Field subId(data, len);
7713 const char* bookmarkData = NULL;
7714 size_t bookmarkLen = 0;
7720 if (bookmarkLen > 0 && _routes.hasRoute(subId))
7723 _bookmarkStore.persisted(subId, Message::Field(bookmarkData, bookmarkLen));
7728 catch (std::exception& ex)
7730 AMPS_UNHANDLED_EXCEPTION(ex);
7736 ClientImpl::processedAck(Message& message)
7738 unsigned deliveries = 0;
7740 const char* data = NULL;
7744 Lock<Mutex> l(_lock);
7747 Lock<Mutex> guard(_ackMapLock);
7748 AckMap::iterator i = _ackMap.find(std::string(data, len));
7749 if (i != _ackMap.end())
7759 ack.setStatus(data, len);
7761 ack.setReason(data, len);
7763 ack.setUsername(data, len);
7765 ack.setPassword(data, len);
7767 ack.setServerVersion(data, len);
7769 ack.setOptions(data, len);
7771 ack.setBookmark(message.getBookmark());
7779 ClientImpl::checkAndSendHeartbeat(
bool force)
7781 if (force || _heartbeatTimer.check())
7783 _heartbeatTimer.start();
7786 sendWithoutRetry(_beatMessage);
7788 catch (
const AMPSException&)
7795 inline ConnectionInfo ClientImpl::getConnectionInfo()
const
7797 ConnectionInfo info;
7798 std::ostringstream writer;
7800 info[
"client.uri"] = _lastUri;
7801 info[
"client.name"] = _name;
7802 info[
"client.username"] = _username;
7803 if (_publishStore.isValid())
7805 writer << _publishStore.unpersistedCount();
7806 info[
"publishStore.unpersistedCount"] = writer.str();
7815 ClientImpl::ClientImplMessageHandler(
amps_handle messageHandle_,
void* userData_)
7817 const unsigned SOWMask = Message::Command::SOW | Message::Command::GroupBegin | Message::Command::GroupEnd;
7818 const unsigned PublishMask = Message::Command::OOF | Message::Command::Publish | Message::Command::DeltaPublish;
7819 ClientImpl* me = (ClientImpl*) userData_;
7820 AMPS_CALL_EXCEPTION_WRAPPER_2(me, me->processDeferredExecutions());
7821 if (!messageHandle_)
7823 if (me->_queueAckTimeout)
7825 me->checkQueueAcks();
7827 me->checkAndSendHeartbeat();
7831 me->_readMessage.replace(messageHandle_);
7832 Message& message = me->_readMessage;
7833 Message::Command::Type commandType = message.getCommandEnum();
7834 if (commandType & SOWMask)
7840 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
7841 me->_globalCommandTypeHandlers[1 + (commandType / 8192)].invoke(message));
7843 AMPS_CALL_EXCEPTION_WRAPPER_2(me, me->_routes.deliverData(message,
7844 message.getQueryID()));
7846 else if (commandType & PublishMask)
7849 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
7850 me->_globalCommandTypeHandlers[(commandType == Message::Command::Publish ?
7851 GlobalCommandTypeHandlers::Publish :
7852 GlobalCommandTypeHandlers::OOF)].invoke(message));
7854 const char* subIds = NULL;
7855 size_t subIdsLen = 0;
7858 &subIds, &subIdsLen);
7859 size_t subIdCount = me->_routes.parseRoutes(
AMPS::Field(subIds, subIdsLen), me->_routeCache);
7860 for (
size_t i = 0; i < subIdCount; ++i)
7862 MessageRouter::RouteCache::value_type& lookupResult = me->_routeCache[i];
7863 MessageHandler& handler = lookupResult.handler;
7864 if (handler.isValid())
7867 AMPS_SubscriptionId,
7868 subIds + lookupResult.idOffset,
7869 lookupResult.idLength);
7870 Message::Field bookmark = message.getBookmark();
7871 bool isMessageQueue = message.getLeasePeriod().len() != 0;
7872 bool isAutoAck = me->_isAutoAckEnabled;
7874 if (!isMessageQueue && !bookmark.empty() &&
7875 me->_bookmarkStore.isValid())
7877 if (me->_bookmarkStore.isDiscarded(me->_readMessage))
7880 if (me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage].isValid())
7882 AMPS_CALL_EXCEPTION_WRAPPER_2(me, me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage].invoke(message));
7887 me->_bookmarkStore.log(me->_readMessage);
7888 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
7889 handler.invoke(message));
7894 if (isMessageQueue && isAutoAck)
7898 AMPS_CALL_EXCEPTION_WRAPPER_STREAM_FULL_2(me, handler.invoke(message));
7899 if (!message.getIgnoreAutoAck())
7901 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
7902 me->_ack(message.getTopic(), message.getBookmark()));
7905 catch (std::exception& ex)
7907 if (!message.getIgnoreAutoAck())
7909 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
7910 me->_ack(message.getTopic(), message.getBookmark(),
"cancel"));
7912 AMPS_UNHANDLED_EXCEPTION_2(me, ex);
7917 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
7918 handler.invoke(message));
7924 me->lastChance(message);
7928 else if (commandType == Message::Command::Ack)
7930 unsigned ackType = message.getAckTypeEnum();
7931 unsigned deliveries = 0U;
7934 case Message::AckType::Persisted:
7935 deliveries += me->persistedAck(message);
7937 case Message::AckType::Processed:
7938 deliveries += me->processedAck(message);
7941 MessageHandler ackHandler = me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::Ack];
7942 if (ackHandler.isValid())
7944 AMPS_CALL_EXCEPTION_WRAPPER_2(me, ackHandler.invoke(message));
7947 AMPS_CALL_EXCEPTION_WRAPPER_2(me, deliveries += me->_routes.deliverAck(message, ackType));
7948 if (deliveries == 0)
7950 me->lastChance(message);
7953 else if (commandType == Message::Command::Heartbeat)
7955 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
7956 me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::Heartbeat].invoke(message));
7957 if (me->_heartbeatTimer.getTimeout() != 0.0)
7959 me->checkAndSendHeartbeat(
true);
7963 me->lastChance(message);
7967 else if (!message.getCommandId().empty())
7969 unsigned deliveries = 0U;
7972 while (me->_connected)
7976 deliveries = me->_routes.deliverData(message, message.getCommandId());
7980 catch (MessageStreamFullException&)
7982 catch (MessageStreamFullException& msfEx_)
7987 me->checkAndSendHeartbeat(
false);
7990 catch (std::exception&)
7992 catch (std::exception& stdEx_)
8000 catch (std::exception& stdEx_)
8004 me->_exceptionListener->exceptionThrown(stdEx_);
8011 if (deliveries == 0)
8013 me->lastChance(message);
8016 me->checkAndSendHeartbeat();
8021 ClientImpl::ClientImplPreDisconnectHandler(
amps_handle ,
unsigned failedConnectionVersion,
void* userData)
8023 ClientImpl* me = (ClientImpl*) userData;
8026 me->clearAcks(failedConnectionVersion);
8030 ClientImpl::ClientImplDisconnectHandler(
amps_handle ,
void* userData)
8032 ClientImpl* me = (ClientImpl*) userData;
8033 Lock<Mutex> l(me->_lock);
8034 Client wrapper(me,
false);
8037 me->broadcastConnectionStateChanged(ConnectionStateListener::Disconnected);
8041 AtomicFlagFlip subFlip(&me->_badTimeToHASubscribe);
8042 bool retryInProgress =
false;
8045 me->_connected =
false;
8046 me->_lock.signalAll();
8049 Unlock<Mutex> unlock(me->_lock);
8050 me->_disconnectHandler.invoke(wrapper);
8053 catch (
const RetryOperationException&)
8055 catch (
const RetryOperationException& ex)
8058 retryInProgress =
true;
8060 catch (
const std::exception& ex)
8062 AMPS_UNHANDLED_EXCEPTION_2(me, ex);
8064 me->_lock.signalAll();
8066 if (!me->_connected)
8068 if (retryInProgress)
8070 AMPS_UNHANDLED_EXCEPTION_2(me, RetryOperationException(
"Reconnect in progress."));
8074 me->broadcastConnectionStateChanged(ConnectionStateListener::Shutdown);
8075 AMPS_UNHANDLED_EXCEPTION_2(me, DisconnectedException(
"Reconnect failed."));
8082 if (me->_subscriptionManager)
8087 Unlock<Mutex> unlock(me->_lock);
8088 me->_subscriptionManager->resubscribe(wrapper);
8090 me->broadcastConnectionStateChanged(ConnectionStateListener::Resubscribed);
8094 catch (
const AMPSException& subEx)
8096 AMPS_UNHANDLED_EXCEPTION_2(me, subEx);
8098 catch (
const std::exception& subEx)
8100 AMPS_UNHANDLED_EXCEPTION_2(me, subEx);
8112 ClientImpl::ClientImplGetHttpPreflightMessage(
void* userData_)
8114 ClientImpl* me = (ClientImpl*)userData_;
8115 std::ostringstream os;
8118 size_t firstColon = me->_lastUri.find(
':');
8120 size_t pathEnd = me->_lastUri.find(
'?');
8122 size_t lastColon = me->_lastUri.rfind(
':', pathEnd);
8124 size_t at = me->_lastUri.rfind(
'@', lastColon);
8126 size_t hostStart = at == std::string::npos ? firstColon + 3 : at + 1;
8127 size_t hostLen = lastColon - hostStart;
8129 size_t pathStart = me->_lastUri.find(
'/', lastColon);
8130 size_t pathLen = pathEnd;
8131 if (pathEnd != std::string::npos)
8133 pathLen = pathEnd - pathStart;
8135 os <<
"GET " << me->_lastUri.substr(pathStart, pathLen)
8136 <<
" HTTP/1.1\r\nHost: " << me->_lastUri.substr(hostStart, hostLen)
8137 <<
"\r\nConnection: upgrade\r\nUpgrade: "
8138 << me->_lastUri.substr(0, firstColon) <<
"\r\n";
8139 for (
auto header : me->_httpPreflightHeaders)
8141 os << header <<
"\r\n";
8144 me->_preflightMessage = os.str();
8145 return me->_preflightMessage.c_str();
8160 iterator(
const char* data_,
size_t len_,
size_t pos_,
char fieldSep_)
8161 : _data(data_), _len(len_), _pos(pos_), _fieldSep(fieldSep_)
8163 while (_pos != _len && _data[_pos] == _fieldSep)
8169 typedef void* difference_type;
8170 typedef std::forward_iterator_tag iterator_category;
8171 typedef std::pair<Message::Field, Message::Field> value_type;
8172 typedef value_type* pointer;
8173 typedef value_type& reference;
8174 bool operator==(
const iterator& rhs)
const
8176 return _pos == rhs._pos;
8178 bool operator!=(
const iterator& rhs)
const
8180 return _pos != rhs._pos;
8182 iterator& operator++()
8185 while (_pos != _len && _data[_pos] != _fieldSep)
8190 while (_pos != _len && _data[_pos] == _fieldSep)
8197 value_type operator*()
const
8200 size_t i = _pos, keyLength = 0, valueStart = 0, valueLength = 0;
8201 for (; i < _len && _data[i] !=
'='; ++i)
8206 result.first.assign(_data + _pos, keyLength);
8208 if (i < _len && _data[i] ==
'=')
8212 for (; i < _len && _data[i] != _fieldSep; ++i)
8217 result.second.assign(_data + valueStart, valueLength);
8223 class reverse_iterator
8230 typedef std::pair<Message::Field, Message::Field> value_type;
8231 reverse_iterator(
const char* data,
size_t len,
const char* pos,
char fieldsep)
8232 : _data(data), _len(len), _pos(pos), _fieldSep(fieldsep)
8237 while (_pos >= _data && *_pos == _fieldSep)
8241 while (_pos > _data && *_pos != _fieldSep)
8248 if (_pos > _data || (_pos == _data && *_pos == _fieldSep))
8258 bool operator==(
const reverse_iterator& rhs)
const
8260 return _pos == rhs._pos;
8262 bool operator!=(
const reverse_iterator& rhs)
const
8264 return _pos != rhs._pos;
8266 reverse_iterator& operator++()
8277 while (_pos >= _data && *_pos == _fieldSep)
8282 while (_pos > _data && *_pos != _fieldSep)
8286 if (_pos > _data || (_pos == _data && *_pos == _fieldSep))
8297 value_type operator*()
const
8300 size_t keyLength = 0, valueStart = 0, valueLength = 0;
8301 size_t i = (size_t)(_pos - _data);
8302 for (; i < _len && _data[i] !=
'='; ++i)
8306 result.first.assign(_pos, keyLength);
8307 if (i < _len && _data[i] ==
'=')
8311 for (; i < _len && _data[i] != _fieldSep; ++i)
8316 result.second.assign(_data + valueStart, valueLength);
8320 FIX(
const Message::Field& data,
char fieldSeparator = 1)
8321 : _data(data.data()), _len(data.len()),
8322 _fieldSep(fieldSeparator)
8326 FIX(
const char* data,
size_t len,
char fieldSeparator = 1)
8327 : _data(data), _len(len), _fieldSep(fieldSeparator)
8331 iterator begin()
const
8333 return iterator(_data, _len, 0, _fieldSep);
8335 iterator end()
const
8337 return iterator(_data, _len, _len, _fieldSep);
8341 reverse_iterator rbegin()
const
8343 return reverse_iterator(_data, _len, _data + (_len - 1), _fieldSep);
8346 reverse_iterator rend()
const
8348 return reverse_iterator(_data, _len, 0, _fieldSep);
8369 std::stringstream _data;
8386 void append(
const T& tag,
const char* value,
size_t offset,
size_t length)
8388 _data << tag <<
'=';
8389 _data.write(value + offset, (std::streamsize)length);
8397 void append(
const T& tag,
const std::string& value)
8399 _data << tag <<
'=' << value << _fs;
8408 operator std::string()
const
8416 _data.str(std::string());
8453 typedef std::map<Message::Field, Message::Field>
map_type;
8464 for (FIX::iterator a = fix.begin(); a != fix.end(); ++a)
8473 #define AMPS_MESSAGE_STREAM_CACHE_MAX 128
8477 std::deque<Message> _q;
8478 std::deque<Message> _cache;
8479 std::string _commandId;
8481 std::string _queryId;
8485 unsigned _requestedAcks;
8487 Message::Field _previousTopic;
8488 Message::Field _previousBookmark;
8489 typedef enum :
unsigned int { Unset = 0x0, Running = 0x10, Subscribe = 0x11, SOWOnly = 0x12, AcksOnly = 0x13, Conflate = 0x14, Closed = 0x1, Disconnected = 0x2 } State;
8490 #if __cplusplus >= 201100L || _MSC_VER >= 1900
8491 std::atomic<State> _state;
8493 volatile State _state;
8495 typedef std::map<std::string, Message*> SOWKeyMap;
8496 SOWKeyMap _sowKeyMap;
8498 MessageStreamImpl(
const Client& client_)
8501 _maxDepth((unsigned)~0),
8503 _cacheMax(AMPS_MESSAGE_STREAM_CACHE_MAX),
8506 if (_client.isValid())
8508 _client.addConnectionStateListener(
this);
8512 MessageStreamImpl(ClientImpl* client_)
8515 _maxDepth((unsigned)~0),
8519 if (_client.isValid())
8521 _client.addConnectionStateListener(
this);
8525 ~MessageStreamImpl()
8529 virtual void destroy()
8535 catch (std::exception& e)
8539 if (_client.isValid())
8541 _client.getExceptionListener().exceptionThrown(e);
8546 if (_client.isValid())
8548 _client.removeConnectionStateListener(
this);
8550 _client = Client((ClientImpl*)NULL);
8551 c.deferredExecution(MessageStreamImpl::destroyer,
this);
8559 static void destroyer(
void* vpMessageStreamImpl_)
8561 delete ((MessageStreamImpl*)vpMessageStreamImpl_);
8564 void setSubscription(
const std::string& subId_,
8565 const std::string& commandId_ =
"",
8566 const std::string& queryId_ =
"")
8568 Lock<Mutex> lock(_lock);
8570 if (!commandId_.empty() && commandId_ != subId_)
8572 _commandId = commandId_;
8574 if (!queryId_.empty() && queryId_ != subId_ && queryId_ != commandId_)
8576 _queryId = queryId_;
8579 if (Disconnected == _state)
8583 assert(Unset == _state);
8587 void setSOWOnly(
const std::string& commandId_,
8588 const std::string& queryId_ =
"")
8590 Lock<Mutex> lock(_lock);
8591 _commandId = commandId_;
8592 if (!queryId_.empty() && queryId_ != commandId_)
8594 _queryId = queryId_;
8597 if (Disconnected == _state)
8601 assert(Unset == _state);
8605 void setStatsOnly(
const std::string& commandId_,
8606 const std::string& queryId_ =
"")
8608 Lock<Mutex> lock(_lock);
8609 _commandId = commandId_;
8610 if (!queryId_.empty() && queryId_ != commandId_)
8612 _queryId = queryId_;
8615 if (Disconnected == _state)
8619 assert(Unset == _state);
8621 _requestedAcks = Message::AckType::Stats;
8624 void setAcksOnly(
const std::string& commandId_,
unsigned acks_)
8626 Lock<Mutex> lock(_lock);
8627 _commandId = commandId_;
8629 if (Disconnected == _state)
8633 assert(Unset == _state);
8635 _requestedAcks = acks_;
8640 Lock<Mutex> lock(_lock);
8641 if (state_ == AMPS::ConnectionStateListener::Disconnected)
8643 _state = Disconnected;
8646 else if (state_ == AMPS::ConnectionStateListener::Connected
8647 && _commandId.empty()
8649 && _queryId.empty())
8657 void timeout(
unsigned timeout_)
8659 _timeout = timeout_;
8663 if (_state == Subscribe)
8668 void maxDepth(
unsigned maxDepth_)
8672 _maxDepth = maxDepth_;
8676 _maxDepth = (unsigned)~0;
8679 unsigned getMaxDepth(
void)
const
8683 unsigned getDepth(
void)
const
8685 return (
unsigned)(_q.size());
8688 bool next(Message& current_)
8690 Lock<Mutex> lock(_lock);
8691 if (!_previousTopic.empty() && !_previousBookmark.empty())
8695 if (_client.isValid())
8697 _client.ackDeferredAutoAck(_previousTopic, _previousBookmark);
8701 catch (AMPSException&)
8703 catch (AMPSException& e)
8706 current_.invalidate();
8707 _previousTopic.clear();
8708 _previousBookmark.clear();
8711 _previousTopic.clear();
8712 _previousBookmark.clear();
8715 long minWaitTime = (_timeout && _timeout < 1000) ? _timeout : 1000;
8716 Timer timer((
double)_timeout);
8718 while (_q.empty() && _state & Running)
8721 _lock.wait(minWaitTime);
8723 Unlock<Mutex> unlck(_lock);
8724 amps_invoke_waiting_function();
8729 if (timer.checkAndGetRemaining(&minWaitTime))
8735 minWaitTime = (minWaitTime < 1000) ? minWaitTime : 1000;
8738 if (current_.isValid() && _cache.size() < _cacheMax)
8741 _cache.push_back(current_);
8745 current_ = _q.front();
8746 if (_q.size() == _maxDepth)
8751 if (_state == Conflate)
8753 std::string sowKey = current_.getSowKey();
8754 if (sowKey.length())
8756 _sowKeyMap.erase(sowKey);
8759 else if (_state == AcksOnly)
8761 _requestedAcks &= ~(current_.getAckTypeEnum());
8763 if ((_state == AcksOnly && _requestedAcks == 0) ||
8764 (_state == SOWOnly && current_.getCommand() ==
"group_end"))
8768 else if (current_.isValid()
8769 && current_.getCommandEnum() == Message::Command::Publish
8770 && _client.isValid() && _client.getAutoAck()
8771 && !current_.getLeasePeriod().empty()
8772 && !current_.getBookmark().empty())
8774 _previousTopic = current_.getTopic().deepCopy();
8775 _previousBookmark = current_.getBookmark().deepCopy();
8779 if (_state == Disconnected)
8781 throw DisconnectedException(
"Connection closed.");
8783 current_.invalidate();
8784 if (_state == Closed)
8788 return _timeout != 0;
8792 if (_client.isValid())
8794 if (_state == SOWOnly || _state == Subscribe)
8796 if (!_commandId.empty())
8798 _client.unsubscribe(_commandId);
8800 if (!_subId.empty())
8802 _client.unsubscribe(_subId);
8804 if (!_queryId.empty())
8806 _client.unsubscribe(_queryId);
8811 if (!_commandId.empty())
8813 _client.removeMessageHandler(_commandId);
8815 if (!_subId.empty())
8817 _client.removeMessageHandler(_subId);
8819 if (!_queryId.empty())
8821 _client.removeMessageHandler(_queryId);
8825 if (_state == SOWOnly || _state == Subscribe || _state == Unset)
8830 static void _messageHandler(
const Message& message_, MessageStreamImpl* this_)
8832 Lock<Mutex> lock(this_->_lock);
8833 if (this_->_state != Conflate)
8835 AMPS_TESTING_SLOW_MESSAGE_STREAM
8836 if (this_->_q.size() >= this_->_maxDepth)
8841 this_->_lock.signalAll();
8842 throw MessageStreamFullException(
"Stream is currently full.");
8844 if (!this_->_cache.empty())
8846 this_->_cache.front().deepCopy(message_);
8847 this_->_q.push_back(this_->_cache.front());
8848 this_->_cache.pop_front();
8852 #ifdef AMPS_USE_EMPLACE
8853 this_->_q.emplace_back(message_.deepCopy());
8855 this_->_q.push_back(message_.deepCopy());
8858 if (message_.getCommandEnum() == Message::Command::Publish &&
8859 this_->_client.isValid() && this_->_client.getAutoAck() &&
8860 !message_.getLeasePeriod().empty() &&
8861 !message_.getBookmark().empty())
8863 message_.setIgnoreAutoAck();
8868 std::string sowKey = message_.getSowKey();
8869 if (sowKey.length())
8871 SOWKeyMap::iterator it = this_->_sowKeyMap.find(sowKey);
8872 if (it != this_->_sowKeyMap.end())
8874 it->second->deepCopy(message_);
8878 if (this_->_q.size() >= this_->_maxDepth)
8884 this_->_lock.signalAll();
8885 throw MessageStreamFullException(
"Stream is currently full.");
8887 if (!this_->_cache.empty())
8889 this_->_cache.front().deepCopy(message_);
8890 this_->_q.push_back(this_->_cache.front());
8891 this_->_cache.pop_front();
8895 #ifdef AMPS_USE_EMPLACE
8896 this_->_q.emplace_back(message_.deepCopy());
8898 this_->_q.push_back(message_.deepCopy());
8901 this_->_sowKeyMap[sowKey] = &(this_->_q.back());
8906 if (this_->_q.size() >= this_->_maxDepth)
8911 this_->_lock.signalAll();
8912 throw MessageStreamFullException(
"Stream is currently full.");
8914 if (!this_->_cache.empty())
8916 this_->_cache.front().deepCopy(message_);
8917 this_->_q.push_back(this_->_cache.front());
8918 this_->_cache.pop_front();
8922 #ifdef AMPS_USE_EMPLACE
8923 this_->_q.emplace_back(message_.deepCopy());
8925 this_->_q.push_back(message_.deepCopy());
8928 if (message_.getCommandEnum() == Message::Command::Publish &&
8929 this_->_client.isValid() && this_->_client.getAutoAck() &&
8930 !message_.getLeasePeriod().empty() &&
8931 !message_.getBookmark().empty())
8933 message_.setIgnoreAutoAck();
8937 this_->_lock.signalAll();
8940 inline MessageStream::MessageStream(
void)
8943 inline MessageStream::MessageStream(
const Client& client_)
8944 : _body(new MessageStreamImpl(client_))
8947 inline MessageStream::MessageStream(RefHandle<MessageStreamImpl> body_)
8951 inline void MessageStream::iterator::advance(
void)
8953 _pStream = _pStream->_body->next(_current) ? _pStream : NULL;
8955 inline MessageStream::operator MessageHandler(
void)
8957 return MessageHandler((
void(*)(
const Message&,
void*))MessageStreamImpl::_messageHandler, &_body.get());
8959 inline MessageStream MessageStream::fromExistingHandler(
const MessageHandler& handler_)
8961 MessageStream result;
8962 if (handler_._func == (MessageHandler::FunctionType)MessageStreamImpl::_messageHandler)
8964 result._body = (MessageStreamImpl*)(handler_._userData);
8969 inline void MessageStream::setSOWOnly(
const std::string& commandId_,
8970 const std::string& queryId_)
8972 _body->setSOWOnly(commandId_, queryId_);
8974 inline void MessageStream::setSubscription(
const std::string& subId_,
8975 const std::string& commandId_,
8976 const std::string& queryId_)
8978 _body->setSubscription(subId_, commandId_, queryId_);
8980 inline void MessageStream::setStatsOnly(
const std::string& commandId_,
8981 const std::string& queryId_)
8983 _body->setStatsOnly(commandId_, queryId_);
8985 inline void MessageStream::setAcksOnly(
const std::string& commandId_,
8988 _body->setAcksOnly(commandId_, acks_);
9007 return _body->getMaxDepth();
9011 return _body->getDepth();
9014 inline MessageStream ClientImpl::getEmptyMessageStream(
void)
9024 ClientImpl& body = _body.get();
9025 Message& message = command_.getMessage();
9029 if (useExistingHandler)
9035 if (body._routes.getRoute(subId, existingHandler))
9038 body.executeAsync(command_, existingHandler,
false);
9039 return MessageStream::fromExistingHandler(existingHandler);
9048 if ((command & Message::Command::NoDataCommands)
9049 && (ackTypes == Message::AckType::Persisted
9050 || ackTypes == Message::AckType::None))
9053 if (!body._pEmptyMessageStream)
9055 body._pEmptyMessageStream.reset(
new MessageStream((ClientImpl*)0));
9056 body._pEmptyMessageStream.get()->_body->close();
9058 return body.getEmptyMessageStream();
9061 if (body.getDefaultMaxDepth())
9063 stream.
maxDepth(body.getDefaultMaxDepth());
9066 std::string commandID = body.executeAsync(command_, handler,
false);
9067 if (command_.hasStatsAck())
9069 stream.setStatsOnly(commandID, command_.getMessage().
getQueryId());
9071 else if (command_.isSow())
9075 stream.setAcksOnly(commandID,
9080 stream.setSOWOnly(commandID, command_.getMessage().
getQueryId());
9083 else if (command_.isSubscribe())
9085 stream.setSubscription(commandID,
9092 if (command == Message::Command::Publish ||
9093 command == Message::Command::DeltaPublish ||
9094 command == Message::Command::SOWDelete)
9096 stream.setAcksOnly(commandID,
9097 ackTypes & (
unsigned)~Message::AckType::Persisted);
9101 stream.setAcksOnly(commandID, ackTypes);
9108 inline void Message::ack(
const char* options_)
const
9110 ClientImpl* pClient = _body.get().clientImpl();
9112 if (pClient && bookmark.
len() &&
9113 !pClient->getAutoAck())
9116 pClient->ack(getTopic(), bookmark, options_);
Core type and function declarations for the AMPS C client.
AMPSDLL void amps_client_disconnect(amps_handle handle)
Disconnects from the AMPS server, if connected.
AMPSDLL void amps_message_get_field_value(amps_handle message, FieldId field, const amps_char **value_ptr, size_t *length_ptr)
Retrieves the value of a header field in an AMPS message.
AMPSDLL void amps_client_destroy(amps_handle handle)
Disconnects and destroys an AMPS client object.
AMPSDLL amps_result amps_client_connect(amps_handle handle, const amps_char *uri)
Connects to the AMPS server specified in uri.
AMPSDLL amps_result amps_client_send(amps_handle client, amps_handle message)
Sends a message to the AMPS server.
AMPSDLL amps_uint64_t amps_message_get_field_uint64(amps_handle message, FieldId field)
Gets the unsigned 64-bit int value of a header field in an AMPS message.
AMPSDLL amps_result amps_client_set_name(amps_handle handle, const amps_char *clientName)
Sets the name on an amps client object.
amps_result
Return values from amps_xxx functions.
Definition: amps.h:217
@ AMPS_E_RETRY
The operation has not succeeded, but ought to be retried.
Definition: amps.h:245
@ AMPS_E_OK
Success.
Definition: amps.h:221
@ AMPS_E_DISCONNECTED
The client and server are disconnected.
Definition: amps.h:249
AMPSDLL amps_result amps_client_attempt_reconnect(amps_handle client, unsigned version)
Manually invokes the user-supplied disconnect handler for this client.
AMPSDLL amps_result amps_client_set_read_timeout(amps_handle client, int readTimeout)
Sets a read timeout (seconds), in which if no message is received, the connection is presumed dead.
amps_result(* amps_thread_created_callback)(AMPS_THREAD_T, void *)
Prototype for a user-supplied callback function to allow thread attributes to be set when a new threa...
Definition: amps.h:696
AMPSDLL amps_result amps_client_set_transport_filter_function(amps_handle client, amps_transport_filter_function filter, void *userData)
Sets a user-supplied callback function for filtering data before it is sent and after it is received.
AMPSDLL amps_result amps_client_set_thread_created_callback(amps_handle client, amps_thread_created_callback callback, void *userData)
Sets a user-supplied callback function to allow thread attributes to set when a new thread is created...
AMPSDLL void amps_message_set_field_value(amps_handle message, FieldId field, const amps_char *value, size_t length)
Sets the value of a header field in an AMPS message.
AMPSDLL void amps_client_set_predisconnect_handler(amps_handle client, amps_predisconnect_handler predisconnectHandler, void *userData)
Sets the predisconnect handler function to be called when a disconnect occurs.
AMPSDLL void amps_client_set_message_handler(amps_handle client, amps_handler messageHandler, void *userData)
Sets the message handler function for this client.
AMPSDLL amps_result amps_client_send_batch(amps_handle client, amps_handle message, unsigned *version_out, int addToBatch)
Adds a message to the send cache, possibly sending the cache.
AMPSDLL AMPS_SOCKET amps_client_get_socket(amps_handle client)
Returns the socket from the underlying transport in client, or NULL if no transport is associated wit...
void * amps_handle
Opaque handle type used to refer to objects in the AMPS api.
Definition: amps.h:211
void(* amps_transport_filter_function)(const unsigned char *, size_t, short, void *)
Prototype for a user-supplied callback function for filtering data before it is sent and after it is ...
Definition: amps.h:670
AMPSDLL amps_result amps_client_set_idle_time(amps_handle client, int idleTime)
Sets an idle-time (milliseconds).
AMPSDLL void amps_client_set_batch_send(amps_handle client_, amps_uint64_t batchSizeBytes_, amps_uint64_t batchTimeout_)
Sets a byte size batchSizeBytes and timeout for using batch sends of publish and delta_publish messag...
AMPSDLL amps_handle amps_client_create(const amps_char *clientName)
Functions for creation of an AMPS client.
AMPSDLL void amps_client_set_disconnect_handler(amps_handle client, amps_handler disconnectHandler, void *userData)
Sets the disconnect handler function to be called when a disconnect occurs.
AMPSDLL amps_result amps_client_set_http_preflight_callback(amps_handle client, amps_http_preflight_callback callback, void *userData)
Sets a user-supplied callback function for when a connection is established and the provided uri incl...
bool DangerousFlushPublishStoreResizeHandler(Store store_, size_t, void *data_)
PublishStoreResizeHandler that will block up to the timeout specified in user data milliseconds tryin...
Definition: ampsplusplus.hpp:1411
bool(* PublishStoreResizeHandler)(Store store_, size_t size_, void *userData_)
Function type for PublishStore resize events The store_ param is store which is resizing.
Definition: ampsplusplus.hpp:1091
The interface for handling authentication with the AMPS server.
Definition: ampsplusplus.hpp:1007
virtual std::string authenticate(const std::string &userName_, const std::string &password_)=0
Called by Client just before the logon command is sent.
virtual void completed(const std::string &userName_, const std::string &password_, const std::string &reason_)=0
Called by Client once a logon completes successfully.
virtual std::string retry(const std::string &userName_, const std::string &password_)=0
Called by Client when a logon ack is received with a status of retry.
Interface for BookmarkStoreImpl classes.
Definition: BookmarkStore.hpp:229
Client represents a connection to an AMPS server, but does not provide failover or reconnection behav...
Definition: ampsplusplus.hpp:5190
MessageStream sow(const char *topic_, const std::string &filter_="", const std::string &orderBy_="", const std::string &bookmark_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic.
Definition: ampsplusplus.hpp:6329
amps_uint64_t publish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:5705
void setExceptionListener(const std::shared_ptr< const ExceptionListener > &pListener_)
Sets the exception listener for exceptions that are not thrown back to the user (for example,...
Definition: ampsplusplus.hpp:7067
std::string logon(const char *options_, int timeout_=0)
Logon to the server, providing the client name, credentials (if available) client information (such a...
Definition: ampsplusplus.hpp:5937
void flushAcks(void)
Sends any queued message queue ack messages to the server immediately.
Definition: ampsplusplus.hpp:7479
void startTimer()
Definition: ampsplusplus.hpp:6898
MessageStream subscribe(const std::string &topic_, long timeout_=0, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Subscribe to a topic.
Definition: ampsplusplus.hpp:6007
void setBookmarkStore(const BookmarkStore &bookmarkStore_)
Set the bookmark store to be used by the client.
Definition: ampsplusplus.hpp:5552
const std::string & getURI() const
Returns the last URI this client is connected to.
Definition: ampsplusplus.hpp:5377
void removeConnectionStateListener(ConnectionStateListener *listener)
Attempts to remove listener from self's set of ConnectionStateListeners.
Definition: ampsplusplus.hpp:7298
amps_uint64_t publish(const std::string &topic_, const std::string &data_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store (if a...
Definition: ampsplusplus.hpp:5729
static const char * BOOKMARK_EPOCH()
Convenience method for returning the special value to start a subscription at the beginning of the tr...
Definition: ampsplusplus.hpp:7236
std::string deltaSubscribe(const MessageHandler &messageHandler_, const std::string &topic_, long timeout_, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Delta Subscribe to a topic.
Definition: ampsplusplus.hpp:6068
SubscriptionManager * getSubscriptionManager()
Get the subscription manager being used by the client.
Definition: ampsplusplus.hpp:5568
void setPublishBatching(size_t batchSize_, amps_uint64_t batchTimeoutMillis_)
Sets the max bytes to cache and max timeout in millis for caching delta_publish and publish commands.
Definition: ampsplusplus.hpp:7621
std::string bookmarkSubscribe(const MessageHandler &messageHandler_, const std::string &topic_, long timeout_, const std::string &bookmark_, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Subscribe to a topic using a bookmark.
Definition: ampsplusplus.hpp:6146
void addHttpPreflightHeader(const std::string &key_, const std::string &value_)
Adds a given key/value pair as an HTTP header line as "key: value" to the end of the headers that wil...
Definition: ampsplusplus.hpp:5302
void unsubscribe()
Unsubscribe from all topics.
Definition: ampsplusplus.hpp:6235
std::string send(const MessageHandler &messageHandler, Message &message, int timeout=0)
Sends a Message to the connected AMPS server, performing only minimal validation and bypassing client...
Definition: ampsplusplus.hpp:5495
void setHeartbeat(unsigned heartbeatTime_)
Requests heartbeating with the AMPS server.
Definition: ampsplusplus.hpp:7140
void setLastChanceMessageHandler(const AMPS::MessageHandler &messageHandler)
Sets the message handler called when no other handler matches.
Definition: ampsplusplus.hpp:7156
static const char * BOOKMARK_MOST_RECENT()
Convenience method for returning the special value to start a subscription at a recovery point based ...
Definition: ampsplusplus.hpp:7257
amps_handle getHandle()
Returns the underlying amps_handle for this client, to be used with amps_client_* functions from the ...
Definition: ampsplusplus.hpp:7054
void setFailedWriteHandler(FailedWriteHandler *handler_)
Set the handler that is invoked to report when a publish fails, for example if the publisher is not e...
Definition: ampsplusplus.hpp:5649
void setName(const std::string &name)
Sets the name of this client, assuming no name was provided previously.
Definition: ampsplusplus.hpp:5244
amps_uint64_t deltaPublish(const std::string &topic_, const std::string &data_)
Publish the changed fields of a message to an AMPS topic.
Definition: ampsplusplus.hpp:5823
FailedWriteHandler * getFailedWriteHandler()
Get the handler that is invoked to report on failed writes.
Definition: ampsplusplus.hpp:5657
void setHttpPreflightHeaders(const T &headers_)
Sets the given HTTP header lines to be sent for the HTTP GET Upgrade request.
Definition: ampsplusplus.hpp:5317
void setDefaultMaxDepth(unsigned maxDepth_)
Sets a default max depth on all subsequently created MessageStream objects.
Definition: ampsplusplus.hpp:7575
amps_uint64_t publish(const std::string &topic_, const std::string &data_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:5680
MessageStream sowAndDeltaSubscribe(const char *topic_, const std::string &filter_="", const std::string &orderBy_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic and initiates a new delta subscription on it.
Definition: ampsplusplus.hpp:6683
void setAckBatchSize(const unsigned ackBatchSize_)
Sets the queue ack batch size setting.
Definition: ampsplusplus.hpp:7516
void disconnect()
Disconnect from an AMPS server.
Definition: ampsplusplus.hpp:5408
static const char * NOW()
Convenience method for returning the special value to start a subscription at the end of the transact...
Definition: ampsplusplus.hpp:7226
void clearHttpPreflightHeaders()
Clears all previously set HTTP header lines.
Definition: ampsplusplus.hpp:5308
amps_uint64_t deltaPublish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_)
Publish the changed fields of a message to an AMPS topic.
Definition: ampsplusplus.hpp:5846
static size_t convertVersionToNumber(const char *data_, size_t len_)
Converts a string version, such as "3.8.1.5" into the same numeric form used internally and returned ...
Definition: ampsplusplus.hpp:5370
Client(const std::string &clientName="")
Constructs a new client with a given client name.
Definition: ampsplusplus.hpp:5206
const ExceptionListener & getExceptionListener(void) const
Returns the exception listener set on this Client.
Definition: ampsplusplus.hpp:7090
void unsubscribe(const std::string &commandId)
Unsubscribe from a topic.
Definition: ampsplusplus.hpp:6223
void setExceptionListener(const ExceptionListener &listener_)
Definition: ampsplusplus.hpp:7083
DisconnectHandler getDisconnectHandler(void) const
Definition: ampsplusplus.hpp:5530
int getAckTimeout(void) const
Returns the current value of the message queue ack timeout setting – that is, the amount of time afte...
Definition: ampsplusplus.hpp:7527
MessageStream bookmarkSubscribe(const std::string &topic_, long timeout_, const std::string &bookmark_, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Subscribe to a topic using a bookmark.
Definition: ampsplusplus.hpp:6174
bool getRetryOnDisconnect(void) const
Returns true if automatic retry of a command to AMPS after a reconnect is enabled.
Definition: ampsplusplus.hpp:7566
BookmarkStore getBookmarkStore()
Get the bookmark store being used by the client.
Definition: ampsplusplus.hpp:5560
MessageStream subscribe(const char *topic_, long timeout_=0, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Subscribe to a topic.
Definition: ampsplusplus.hpp:6039
const std::string & getLogonCorrelationData() const
Returns the currently set logon correlation data for the client.
Definition: ampsplusplus.hpp:5285
std::string logon(int timeout_=0, Authenticator &authenticator_=DefaultAuthenticator::instance(), const char *options_=NULL)
Logon to the server, providing the client name, credentials (if available), and client information (s...
Definition: ampsplusplus.hpp:5918
const amps_uint64_t getNameHashValue() const
Returns the numeric name hash of this client as generated by the server and returned when the client ...
Definition: ampsplusplus.hpp:5267
void setGlobalCommandTypeMessageHandler(const Message::Command::Type command_, const MessageHandler &handler_)
Sets a handler for all messages of a particular type: currently supported types are heartbeat message...
Definition: ampsplusplus.hpp:7207
const std::string & getName() const
Returns the name of this client passed in the constructor.
Definition: ampsplusplus.hpp:5251
bool getAutoAck(void) const
Returns the value of the queue auto-ack setting.
Definition: ampsplusplus.hpp:7488
unsigned getDefaultMaxDepth(void) const
Returns the default max depth for returned MessageStream objects.
Definition: ampsplusplus.hpp:7584
void setSubscriptionManager(SubscriptionManager *subscriptionManager_)
Set the subscription manager to be used by the client.
Definition: ampsplusplus.hpp:5580
void ack(Field &topic_, Field &bookmark_, const char *options_=NULL)
Acknowledge a message queue message by supplying a topic and bookmark: this adds the ack to the curre...
Definition: ampsplusplus.hpp:7431
void clearConnectionStateListeners()
Clear all listeners from self's set of ConnectionStateListeners.
Definition: ampsplusplus.hpp:7305
static const char * BOOKMARK_NOW()
Convenience method for returning the special value to start a subscription at the end of the transact...
Definition: ampsplusplus.hpp:7217
MessageStream bookmarkSubscribe(const char *topic_, long timeout_, const std::string &bookmark_, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Subscribe to a topic using a bookmark.
Definition: ampsplusplus.hpp:6195
std::string executeAsyncNoResubscribe(Command &command_, MessageHandler handler_)
Execute the provided command and, once AMPS acknowledges the command, process messages in response to...
Definition: ampsplusplus.hpp:7369
size_t getServerVersion() const
Returns the server version retrieved during logon.
Definition: ampsplusplus.hpp:5330
static const char * EPOCH()
Convenience method for returning the special value to start a subscription at the beginning of the tr...
Definition: ampsplusplus.hpp:7246
void send(const Message &message)
Sends a Message to the connected AMPS server, performing only minimal validation and bypassing client...
Definition: ampsplusplus.hpp:5426
void publishFlush(long timeout_=0, unsigned ackType_=Message::AckType::Processed)
Ensure that AMPS messages are sent and have been processed by the AMPS server.
Definition: ampsplusplus.hpp:5802
amps_uint64_t deltaPublish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, unsigned long expiration_)
Publish the changed fields of a message to an AMPS topic.
Definition: ampsplusplus.hpp:5895
void ack(const std::string &topic_, const std::string &bookmark_, const char *options_=NULL)
Acknowledge a message queue message by supplying a topic and bookmark string: this adds the ack to th...
Definition: ampsplusplus.hpp:7455
MessageStream deltaSubscribe(const char *topic_, long timeout_, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Delta Subscribe to a topic.
Definition: ampsplusplus.hpp:6104
void setUnhandledMessageHandler(const AMPS::MessageHandler &messageHandler)
Definition: ampsplusplus.hpp:7149
void addMessageHandler(const Field &commandId_, const AMPS::MessageHandler &messageHandler_, unsigned requestedAcks_, bool isSubscribe_)
Adds a MessageHandler to be invoked for Messages with the given CommandId as their command id,...
Definition: ampsplusplus.hpp:5439
amps_uint64_t deltaPublish(const std::string &topic_, const std::string &data_, unsigned long expiration_)
Publish the changed fields of a message to an AMPS topic.
Definition: ampsplusplus.hpp:5869
void addMessageHandler(const Field &commandId_, const AMPS::MessageHandler &messageHandler_, unsigned requestedAcks_, Message::Command::Type commandType_)
Adds a MessageHandler to be invoked for Messages with the given CommandId as their command id,...
Definition: ampsplusplus.hpp:5456
std::string executeAsync(Command &command_, MessageHandler handler_)
Execute the provided command and, once AMPS acknowledges the command, process messages in response to...
Definition: ampsplusplus.hpp:7335
unsigned getAckBatchSize(void) const
Returns the value of the queue ack batch size setting.
Definition: ampsplusplus.hpp:7506
void setAutoAck(bool isAutoAckEnabled_)
Sets the queue auto-ack setting on this client.
Definition: ampsplusplus.hpp:7498
void addHttpPreflightHeader(const std::string &header_)
Adds a given HTTP header line to the end of the headers that will be sent for the HTTP GET Upgrade re...
Definition: ampsplusplus.hpp:5293
MessageStream execute(Command &command_)
Execute the provided command and return messages received in response in a MessageStream.
Definition: ampsplusplus.hpp:9019
void connect(const std::string &uri)
Connect to an AMPS server.
Definition: ampsplusplus.hpp:5401
const std::string & getNameHash() const
Returns the name hash string of this client as generated by the server and returned when the client l...
Definition: ampsplusplus.hpp:5259
static const char * MOST_RECENT()
Convenience method for returning the special value to start a subscription at a recovery point based ...
Definition: ampsplusplus.hpp:7268
bool removeMessageHandler(const Field &commandId_)
Removes a MessageHandler for a given ComandId from self.
Definition: ampsplusplus.hpp:5467
void setRetryOnDisconnect(bool isRetryOnDisconnect_)
Enables or disables automatic retry of a command to AMPS after a reconnect.
Definition: ampsplusplus.hpp:7557
void setGlobalCommandTypeMessageHandler(const std::string &command_, const MessageHandler &handler_)
Sets a handler for all messages of a particular type, or for messages that would be delivered to a pa...
Definition: ampsplusplus.hpp:7182
void setTransportFilterFunction(amps_transport_filter_function filter_, void *userData_)
Sets a filter function on the transport that is called with all raw data sent or received.
Definition: ampsplusplus.hpp:7595
VersionInfo getServerVersionInfo() const
Returns the server version retrieved during logon.
Definition: ampsplusplus.hpp:5341
void setPublishStore(const Store &publishStore_)
Set the publish store to be used by the client.
Definition: ampsplusplus.hpp:5604
void setHeartbeat(unsigned heartbeatTime_, unsigned readTimeout_)
Requests heartbeating with the AMPS server.
Definition: ampsplusplus.hpp:7116
MessageStream deltaSubscribe(const std::string &topic_, long timeout_, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Delta Subscribe to a topic.
Definition: ampsplusplus.hpp:6086
void setLogonCorrelationData(const std::string &logonCorrelationData_)
Sets the logon correlation data for the client.
Definition: ampsplusplus.hpp:5278
void addConnectionStateListener(ConnectionStateListener *listener)
Adds a ConnectionStateListener to self's set of listeners.
Definition: ampsplusplus.hpp:7290
void setThreadCreatedCallback(amps_thread_created_callback callback_, void *userData_)
Sets a callback function on the transport that is called when a new thread is created to receive data...
Definition: ampsplusplus.hpp:7609
std::string subscribe(const MessageHandler &messageHandler_, const std::string &topic_, long timeout_=0, const std::string &filter_="", const std::string &options_="", const std::string &subId_="")
Subscribe to a topic.
Definition: ampsplusplus.hpp:5981
virtual void setDisconnectHandler(const DisconnectHandler &disconnectHandler)
Definition: ampsplusplus.hpp:5516
void setAckTimeout(const int ackTimeout_)
Sets the message queue ack timeout value.
Definition: ampsplusplus.hpp:7539
MessageHandler getDuplicateMessageHandler(void)
Returns the callback function that is invoked when a duplicate message is detected.
Definition: ampsplusplus.hpp:5635
virtual ConnectionInfo getConnectionInfo() const
Get the connection information for the current connection.
Definition: ampsplusplus.hpp:5539
void setDuplicateMessageHandler(const MessageHandler &duplicateMessageHandler_)
Sets a callback function that is invoked when a duplicate message is detected.
Definition: ampsplusplus.hpp:5620
MessageStream sowAndSubscribe(const char *topic_, const std::string &filter_="", const std::string &orderBy_="", const std::string &bookmark_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic and initiates a new subscription on it.
Definition: ampsplusplus.hpp:6582
static const char * BOOKMARK_RECENT()
Convenience method for returning the special value to start a subscription at a recovery point based ...
Definition: ampsplusplus.hpp:7279
std::string stopTimer(const MessageHandler &messageHandler)
Definition: ampsplusplus.hpp:6909
void ack(Message &message_, const char *options_=NULL)
Acknowledge a message queue message by supplying the message directly: this adds the ack to the curre...
Definition: ampsplusplus.hpp:7443
static size_t convertVersionToNumber(const std::string &version_)
Converts a string version, such as "3.8.1.5" into the same numeric form used internally and returned ...
Definition: ampsplusplus.hpp:5355
amps_uint64_t publish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:5756
Store getPublishStore()
Get the publish store used by the client.
Definition: ampsplusplus.hpp:5612
std::string logon(const std::string &options_, int timeout_=0)
Logon to the server, providing the client name, credentials (if available) client information (such a...
Definition: ampsplusplus.hpp:5956
Command is an encapsulation of a single AMPS command sent by the client.
Definition: ampsplusplus.hpp:473
Command & setData(const char *data_, size_t dataLen_)
Sets the data for this command.
Definition: ampsplusplus.hpp:837
Command & setTopN(unsigned topN_)
Definition: ampsplusplus.hpp:857
Command & setSequence(const char *seq_, size_t seqLen_)
Definition: ampsplusplus.hpp:810
Command & setTopic(const std::string &topic_)
Definition: ampsplusplus.hpp:679
Command & setAckType(unsigned ackType_)
Definition: ampsplusplus.hpp:931
Command & setOrderBy(const std::string &orderBy_)
Definition: ampsplusplus.hpp:705
Command & setOptions(const char *options_, size_t optionsLen_)
Sets the options string for this command: see Message.Options for a helper class for constructing the...
Definition: ampsplusplus.hpp:797
Command & setSowKey(const char *sowKey_, size_t sowKeyLen_)
Sets the SowKey field of the command, typically used for a publish command to a topic in the state of...
Definition: ampsplusplus.hpp:625
Command & setAckType(const std::string &ackType_)
Definition: ampsplusplus.hpp:909
Command & setTimeout(unsigned timeout_)
Sets the client-side timeout for this command.
Definition: ampsplusplus.hpp:851
Command & setBookmark(const char *bookmark_, size_t bookmarkLen_)
Set the bookmark to be used this command.
Definition: ampsplusplus.hpp:759
Command & setQueryId(const char *queryId_, size_t queryIdLen_)
Definition: ampsplusplus.hpp:738
std::string getAckType() const
Definition: ampsplusplus.hpp:953
Command & reset(Message::Command::Type command_)
Resets the fields of self, and sets the command to command_.
Definition: ampsplusplus.hpp:600
Command & setBatchSize(unsigned batchSize_)
Sets the batch size for this command, which controls how many records are sent together in the result...
Definition: ampsplusplus.hpp:873
Command & setSubId(const char *subId_, size_t subIdLen_)
Definition: ampsplusplus.hpp:725
Command & setSequence(const amps_uint64_t seq_)
Definition: ampsplusplus.hpp:816
Command & setOptions(const std::string &options_)
Sets the options string for this command: see Message.Options for a helper class for constructing the...
Definition: ampsplusplus.hpp:789
Command & setSowKeys(const char *sowKeys_, size_t sowKeysLen_)
Sets the SowKeys for the command.
Definition: ampsplusplus.hpp:660
Command & setSubId(const std::string &subId_)
Definition: ampsplusplus.hpp:718
Command & setCommandId(const std::string &cmdId_)
Definition: ampsplusplus.hpp:666
Command & setSequence(const std::string &seq_)
Definition: ampsplusplus.hpp:803
Command & setCommandId(const char *cmdId_, size_t cmdIdLen_)
Definition: ampsplusplus.hpp:673
Command(Message::Command::Type command_)
Creates an object to represent the given AMPS command, such as "sow" or "subscribe".
Definition: ampsplusplus.hpp:575
Command & setOrderBy(const char *orderBy_, size_t orderByLen_)
Definition: ampsplusplus.hpp:712
Command & setData(const std::string &data_)
Sets the data for this command from an existing string.
Definition: ampsplusplus.hpp:829
Command & setQueryId(const std::string &queryId_)
Definition: ampsplusplus.hpp:731
Command(const std::string &command_)
Creates an object to represent the given AMPS command, such as "sow" or "subscribe".
Definition: ampsplusplus.hpp:560
Command & setTopic(const char *topic_, size_t topicLen_)
Definition: ampsplusplus.hpp:686
Command & setFilter(const std::string &filter_)
Definition: ampsplusplus.hpp:692
Command & setCorrelationId(const std::string &correlationId_)
Set the correlation ID for this command.
Definition: ampsplusplus.hpp:770
Command & setFilter(const char *filter_, size_t filterLen_)
Definition: ampsplusplus.hpp:699
Command(const char *command_, size_t commandLen_)
Creates an object to represent the given AMPS command, such as "sow" or "subscribe".
Definition: ampsplusplus.hpp:568
Command & setCorrelationId(const char *correlationId_, size_t correlationIdLen_)
Set the correlation ID for this command.
Definition: ampsplusplus.hpp:782
unsigned getAckTypeEnum() const
Definition: ampsplusplus.hpp:958
Command & setSowKey(const std::string &sowKey_)
Sets the SowKey field of the command, typically used for a publish command to a topic in the state of...
Definition: ampsplusplus.hpp:612
Command & setSowKeys(const std::string &sowKeys_)
Sets the SowKeys for the command.
Definition: ampsplusplus.hpp:642
Command & addAckType(const std::string &ackType_)
Definition: ampsplusplus.hpp:895
Command & reset(const char *command_, size_t commandLen_)
Resets the fields of self, and sets the command to command_.
Definition: ampsplusplus.hpp:592
Command & setExpiration(unsigned expiration_)
Set the expiration time for a publish command.
Definition: ampsplusplus.hpp:889
Command & setBookmark(const std::string &bookmark_)
Set the bookmark to be used this command.
Definition: ampsplusplus.hpp:748
Command & reset(const std::string &command_)
Resets the fields of self, and sets the command to command_.
Definition: ampsplusplus.hpp:583
Abstract base class for connection state listeners.
Definition: ampsplusplus.hpp:1502
State
Constants for the state of the connection.
Definition: ampsplusplus.hpp:1505
virtual void connectionStateChanged(State newState_)=0
Pure virtual method for receiving the change in connection state.
A default implementation of Authenticator that only uses an unchanged password and does not implement...
Definition: ampsplusplus.hpp:1038
std::string authenticate(const std::string &, const std::string &password_)
A simple implementation that returns an unmodified password.
Definition: ampsplusplus.hpp:1043
static Authenticator & instance()
Static function to return a static instance used when no Authenticator is supplied to a Client.
Definition: ampsplusplus.hpp:1060
std::string retry(const std::string &, const std::string &)
Throws an AuthenticationException because retry is not implemented.
Definition: ampsplusplus.hpp:1050
void completed(const std::string &, const std::string &, const std::string &)
Called by Client once a logon completes successfully.
Definition: ampsplusplus.hpp:1055
Exception listener for unhandled exceptions.
Definition: ampsplusplus.hpp:205
Class for parsing a FIX format message into a std::map of keys and values, where the keys and values ...
Definition: ampsplusplus.hpp:8442
std::map< Message::Field, Message::Field > map_type
Convenience defintion for the std::map specialization used for this class.
Definition: ampsplusplus.hpp:8453
map_type toMap(const Message::Field &data)
Returns the key/value pairs within the message, represented as AMPS::Field objects that contain point...
Definition: ampsplusplus.hpp:8460
FIXShredder(char fieldSep_=(char) 1)
Construct an instance of FIXShredder using the specified value as the delimiter between fields.
Definition: ampsplusplus.hpp:8449
Abstract base class where you can implement handling of exceptions that occur when a SubscriptionMana...
Definition: ampsplusplus.hpp:1440
virtual bool failure(const Message &message_, const MessageHandler &handler_, unsigned requestedAckTypes_, const AMPSException &exception_)=0
Implement this function to return true if the subscription should be removed from the SubscriptionMan...
Class to handle when a client receives a duplicate publish message, or not entitled message.
Definition: ampsplusplus.hpp:1382
virtual void failedWrite(const Message &message_, const char *reason_, size_t reasonLength_)=0
Called when the server indicates a message could not be written.
Field represents the value of a single field in a Message.
Definition: Field.hpp:87
bool empty() const
Returns 'true' if empty, 'false' otherwise.
Definition: Field.hpp:128
size_t len() const
Returns the length of the data underlying this field.
Definition: Field.hpp:280
Represents an iterator over messages in an AMPS topic.
Definition: ampsplusplus.hpp:5064
An iterable object representing the results of an AMPS subscription and/or query.
Definition: ampsplusplus.hpp:5056
iterator begin(void)
Returns an iterator representing the beginning of the topic or subscription.
Definition: ampsplusplus.hpp:5108
bool isValid() const
Returns true if self is a valid stream that may be iterated.
Definition: ampsplusplus.hpp:5101
MessageStream conflate(void)
Sets self to conflation mode, where a new update for a matching sow key will replace the previous one...
Definition: ampsplusplus.hpp:8995
MessageStream maxDepth(unsigned maxDepth_)
Sets the maximum number of messages that can be held in the underlying queue.
Definition: ampsplusplus.hpp:9000
MessageStream timeout(unsigned timeout_)
Sets the maximum time to wait for the next message in milliseconds; if no message is available within...
Definition: ampsplusplus.hpp:8990
unsigned getDepth(void) const
Gets the current number of messages held in the underlying queue.
Definition: ampsplusplus.hpp:9009
unsigned getMaxDepth(void) const
Gets the maximum number of messages that can be held in the underlying queue.
Definition: ampsplusplus.hpp:9005
iterator end(void)
Returns an iterator representing the end of the topic or subscription.
Definition: ampsplusplus.hpp:5119
Message encapsulates a single message sent to or received from an AMPS server, and provides methods f...
Definition: Message.hpp:540
Message & assignExpiration(const std::string &v)
Assigns the value of the Expiration header for this Message without copying.
Definition: Message.hpp:1367
Field getBookmark() const
Retrieves the value of the Bookmark header of the Message as a Field which references the underlying ...
Definition: Message.hpp:1256
Message & setQueryID(const std::string &v)
Sets the value of the QueryID header for this Message.
Definition: Message.hpp:1479
Field getCommandId() const
Retrieves the value of the CommandId header of the Message as a Field which references the underlying...
Definition: Message.hpp:1364
Message & setExpiration(const std::string &v)
Sets the value of the Expiration header for this Message.
Definition: Message.hpp:1367
static const unsigned int IdentifierLength
The length of identifiers used for unique identification of commands and subscriptions.
Definition: Message.hpp:550
Message & assignSubscriptionId(const std::string &v)
Assigns the value of the SubscriptionId header for this Message without copying.
Definition: Message.hpp:1489
Message & newCommandId()
Creates and sets a new sequential value for the CommandId header for this Message.
Definition: Message.hpp:1364
Field getSequence() const
Retrieves the value of the Sequence header of the Message as a Field which references the underlying ...
Definition: Message.hpp:1484
Message & setBookmark(const std::string &v)
Sets the value of the Bookmark header for this Message.
Definition: Message.hpp:1256
Field getSubscriptionId() const
Retrieves the value of the SubscriptionId header of the Message as a Field which references the under...
Definition: Message.hpp:1489
Message & assignFilter(const std::string &v)
Assigns the value of the Filter header for this Message without copying.
Definition: Message.hpp:1368
Message & setSequence(const std::string &v)
Sets the value of the Sequence header for this Message.
Definition: Message.hpp:1484
Message & setOrderBy(const std::string &v)
Sets the value of the OrderBy header for this Message.
Definition: Message.hpp:1477
Message & setCommandId(const std::string &v)
Sets the value of the CommandId header for this Message.
Definition: Message.hpp:1364
Message & setAckTypeEnum(unsigned ackType_)
Encode self's "ack type" field from a bitmask of values from AckType.
Definition: Message.hpp:1245
unsigned getAckTypeEnum() const
Decode self's "ack type" field and return the corresponding bitmask of values from AckType.
Definition: Message.hpp:1222
Message & setQueryId(const std::string &v)
Sets the value of the QueryID header for this Message.
Definition: Message.hpp:1479
Message & setTopNRecordsReturned(const std::string &v)
Sets the value of the TopNRecordsReturned header for this Message.
Definition: Message.hpp:1513
Message & assignSowKeys(const std::string &v)
Assigns the value of the SowKeys header for this Message without copying.
Definition: Message.hpp:1487
Message & setAckType(const std::string &v)
Sets the value of the AckType header for this Message.
Definition: Message.hpp:1192
Message & setSowKey(const std::string &v)
Sets the value of the SowKey header for this Message.
Definition: Message.hpp:1486
Message & setOptions(const std::string &v)
Sets the value of the Options header for this Message.
Definition: Message.hpp:1406
Command::Type getCommandEnum() const
Decode self's "command" field and return one of the values from Command.
Definition: Message.hpp:1290
Message & assignQueryID(const std::string &v)
Assigns the value of the QueryID header for this Message without copying.
Definition: Message.hpp:1479
Message & assignTopic(const std::string &v)
Assigns the value of the Topic header for this Message without copying.
Definition: Message.hpp:1511
Message & setTopic(const std::string &v)
Sets the value of the Topic header for this Message.
Definition: Message.hpp:1511
Message & setCommandEnum(Command::Type command_)
Set self's "command" field from one of the values in Command.
Definition: Message.hpp:1350
Message & setSubscriptionId(const std::string &v)
Sets the value of the SubscriptionId header for this Message.
Definition: Message.hpp:1489
Message & setFilter(const std::string &v)
Sets the value of the Filter header for this Message.
Definition: Message.hpp:1368
Field getAckType() const
Retrieves the value of the AckType header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1192
Field getQueryId() const
Retrieves the value of the QueryID header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1479
Message & assignSequence(const std::string &v)
Assigns the value of the Sequence header for this Message without copying.
Definition: Message.hpp:1484
Field getTopic() const
Retrieves the value of the Topic header of the Message as a Field which references the underlying buf...
Definition: Message.hpp:1511
Field getQueryID() const
Retrieves the value of the QueryID header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1479
Message & setSowKeys(const std::string &v)
Sets the value of the SowKeys header for this Message.
Definition: Message.hpp:1487
Message & setBatchSize(const std::string &v)
Sets the value of the BatchSize header for this Message.
Definition: Message.hpp:1255
Message & setCommand(const std::string &v)
Sets the value of the Command header for this Message.
Definition: Message.hpp:1257
Field getOptions() const
Retrieves the value of the Options header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1378
Message & setCorrelationId(const std::string &v)
Sets the value of the CorrelationId header for this Message.
Definition: Message.hpp:1366
Message & setData(const std::string &v_)
Sets the data portion of self.
Definition: Message.hpp:1538
Class to hold string versions of failure reasons.
Definition: ampsplusplus.hpp:152
Abstract base class for storing published messages for an HA publisher client.
Definition: ampsplusplus.hpp:1098
virtual amps_uint64_t getLowestUnpersisted() const =0
Get the oldest unpersisted message sequence in the store.
virtual size_t unpersistedCount() const =0
Method to return how many messages are in the store that have not been discarded, indicating that the...
static amps_uint64_t getUnsetSequence()
Method to return the value used to represent no such sequence.
Definition: ampsplusplus.hpp:1167
virtual amps_uint64_t getLastPersisted()=0
Get the last persisted sequence number.
static size_t getUnsetPosition()
Method to return the value used to represent not found or unset.
Definition: ampsplusplus.hpp:1160
virtual void discardUpTo(amps_uint64_t index_)=0
Called by Client to indicate that all messages up to and including.
virtual void flush(long timeout_)=0
Method to wait for the Store to discard everything that has been stored up to the point in time when ...
virtual amps_uint64_t store(const Message &message_)=0
Called by Client to store a message being published.
virtual void replay(StoreReplayer &replayer_)=0
Called by Client to get all stored and non-discarded messages replayed by the store onto the StoreRep...
virtual bool replaySingle(StoreReplayer &replayer_, amps_uint64_t index_)=0
Called by Client to get a single message replayed by the store onto the StoreReplayer.
StoreImpl(bool errorOnPublishGap_=false)
Default constructor.
Definition: ampsplusplus.hpp:1105
virtual void setResizeHandler(PublishStoreResizeHandler handler_, void *userData_)
Set a handler to be called if the Store needs to resize in order to keep storing messages.
Definition: ampsplusplus.hpp:1191
Abstract base class for replaying a publish message.
Definition: ampsplusplus.hpp:1070
virtual void execute(Message &message_)=0
Called by implementations of Store to replay a message from the store.
Handle class for StoreImpl classes that track publish messages.
Definition: ampsplusplus.hpp:1224
void replay(StoreReplayer &replayer_)
Called by Client to get all stored and non-discarded messages replayed by the store onto the StoreRep...
Definition: ampsplusplus.hpp:1259
StoreImpl * get()
Used to get a pointer to the implementation.
Definition: ampsplusplus.hpp:1363
bool getErrorOnPublishGap() const
Called to check if the Store will throw PublishStoreGapException.
Definition: ampsplusplus.hpp:1355
size_t unpersistedCount() const
Method to return how many messages are in the store that have not been discarded, indicating that the...
Definition: ampsplusplus.hpp:1280
bool isValid() const
Method to return if there is an underlying implementation for the Store.
Definition: ampsplusplus.hpp:1288
amps_uint64_t getLastPersisted()
Get the last persisted message sequence in the store.
Definition: ampsplusplus.hpp:1317
void discardUpTo(amps_uint64_t index_)
Called by Client to indicate that all messages up to and including.
Definition: ampsplusplus.hpp:1250
amps_uint64_t getLowestUnpersisted()
Get the oldest unpersisted message sequence in the store.
Definition: ampsplusplus.hpp:1309
void flush(long timeout_=0)
Method to wait for the Store to discard everything that has been stored up to the point in time when ...
Definition: ampsplusplus.hpp:1301
void setResizeHandler(PublishStoreResizeHandler handler_, void *userData_)
Set a handler to be called if the Store needs to resize in order to keep storing messages.
Definition: ampsplusplus.hpp:1331
bool replaySingle(StoreReplayer &replayer_, amps_uint64_t index_)
Called by Client to get a single message replayed by the store onto the StoreReplayer.
Definition: ampsplusplus.hpp:1271
void setErrorOnPublishGap(bool errorOnPublishGap_)
Called to enable or disable throwing PublishStoreGapException.
Definition: ampsplusplus.hpp:1346
amps_uint64_t store(const Message &message_)
Called by Client to store a message being published.
Definition: ampsplusplus.hpp:1239
Abstract base class to manage all subscriptions placed on a client so that they can be re-established...
Definition: ampsplusplus.hpp:1462
virtual void resubscribe(Client &client_)=0
Called by Client to get all subscriptions placed again.
virtual void subscribe(MessageHandler messageHandler_, const Message &message_, unsigned requestedAckTypes_)=0
Called by Client when a subscription is placed.
virtual void setFailedResubscribeHandler(std::shared_ptr< FailedResubscribeHandler > handler_)
Set a handler to deal with failing subscriptions after a failover event.
Definition: ampsplusplus.hpp:1489
virtual void unsubscribe(const Message::Field &subId_)=0
Called by Client when a subscription is unsubscribed.
virtual void clear()=0
Clear subscriptions and reset to the initial state.
Provides a convenient way of building messages in FIX format, typically referenced using the typedefs...
Definition: ampsplusplus.hpp:8368
_FIXBuilder(char fieldSep_=(char) 1)
Construct an instance of _FIXBuilder, using the specified separator between fields.
Definition: ampsplusplus.hpp:8377
std::string getString() const
Returns the current contents of this builder as a string.
Definition: ampsplusplus.hpp:8404
void append(const T &tag, const std::string &value)
Write a field with the provided tag and value to the message being constructed.
Definition: ampsplusplus.hpp:8397
void reset()
Clear all data from the builder.
Definition: ampsplusplus.hpp:8414
void append(const T &tag, const char *value, size_t offset, size_t length)
Write a field with the provided tag and value to the message being constructed.
Definition: ampsplusplus.hpp:8386
std::string sowDelete(const MessageHandler &messageHandler, const std::string &topic, const std::string &filter, long timeout)
Deletes one or more messages from a topic's SOW cache.
Definition: ampsplusplus.hpp:6844
Message sowDeleteByData(const std::string &topic_, const std::string &data_, long timeout_=0)
Deletes the message whose keys match the message data provided.
Definition: ampsplusplus.hpp:7024
std::string sowAndSubscribe(const MessageHandler &messageHandler_, const std::string &topic_, const std::string &filter_="", const std::string &orderBy_="", const std::string &bookmark_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic and initiates a new subscription on it.
Definition: ampsplusplus.hpp:6520
std::string sow(const MessageHandler &messageHandler_, const std::string &topic_, long timeout_, const std::string &filter_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N)
Query the SOW cache of a topic.
Definition: ampsplusplus.hpp:6370
std::string sowAndDeltaSubscribe(const MessageHandler &messageHandler_, const std::string &topic_, long timeout_, const std::string &filter_="", int batchSize_=DEFAULT_BATCH_SIZE, bool oofEnabled_=false, bool sendEmpties_=false, int topN_=DEFAULT_TOP_N)
Query the SOW cache of a topic and initiates a new delta subscription on it.
Definition: ampsplusplus.hpp:6728
std::string sowDeleteByData(const MessageHandler &messageHandler_, const std::string &topic_, const std::string &data_, long timeout_=0)
Deletes the message whose keys match the message data provided.
Definition: ampsplusplus.hpp:7003
std::string sowAndSubscribe(const MessageHandler &messageHandler_, const std::string &topic_, long timeout_, const std::string &filter_="", int batchSize_=DEFAULT_BATCH_SIZE, bool oofEnabled_=false, int topN_=DEFAULT_TOP_N)
Query the SOW cache of a topic and initiates a new subscription on it.
Definition: ampsplusplus.hpp:6402
std::string sowDeleteByKeys(const MessageHandler &messageHandler_, const std::string &topic_, const std::string &keys_, long timeout_=0)
Deletes messages that match SOW keys from a topic's SOW cache.
Definition: ampsplusplus.hpp:6935
std::string sowAndDeltaSubscribe(const MessageHandler &messageHandler_, const std::string &topic_, const std::string &filter_="", const std::string &orderBy_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic and initiates a new delta subscription on it.
Definition: ampsplusplus.hpp:6628
std::string sow(const MessageHandler &messageHandler_, const std::string &topic_, const std::string &filter_="", const std::string &orderBy_="", const std::string &bookmark_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query a State-of-the-World topic.
Definition: ampsplusplus.hpp:6270
#define AMPS_BOOKMARK_NOW
Start the subscription at the point in time when AMPS processes the subscription.
Definition: BookmarkStore.hpp:55
#define AMPS_BOOKMARK_EPOCH
Start the subscription at the beginning of the journal.
Definition: BookmarkStore.hpp:51
#define AMPS_BOOKMARK_RECENT
Start the subscription at the first undiscarded message in the bookmark store, or at the end of the b...
Definition: BookmarkStore.hpp:47
BookmarkStoreImpl * get()
Used to get a pointer to the implementation.
Definition: BookmarkStore.hpp:465
MessageStream sowAndDeltaSubscribe(const char *topic_, long timeout_, const std::string &filter_="", int batchSize_=DEFAULT_BATCH_SIZE, bool oofEnabled_=false, bool sendEmpties_=false, int topN_=DEFAULT_TOP_N)
Query the SOW cache of a topic and initiates a new delta subscription on it.
Definition: ampsplusplus.hpp:6805
MessageStream sowAndDeltaSubscribe(const std::string &topic_, const std::string &filter_="", const std::string &orderBy_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic and initiates a new delta subscription on it.
Definition: ampsplusplus.hpp:6661
Message sowDeleteByKeys(const std::string &topic_, const std::string &keys_, long timeout_=0)
Deletes messages that match SOW keys from a topic's SOW cache.
Definition: ampsplusplus.hpp:6962
MessageStream sow(const std::string &topic_, const std::string &filter_="", const std::string &orderBy_="", const std::string &bookmark_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic.
Definition: ampsplusplus.hpp:6308
MessageStream sowAndSubscribe(const std::string &topic_, long timeout_, const std::string &filter_="", int batchSize_=DEFAULT_BATCH_SIZE, bool oofEnabled_=false, int topN_=DEFAULT_TOP_N)
Query the SOW cache of a topic and initiates a new subscription on it.
Definition: ampsplusplus.hpp:6434
MessageStream sowAndSubscribe(const char *topic_, long timeout_, const std::string &filter_="", int batchSize_=DEFAULT_BATCH_SIZE, bool oofEnabled_=false, int topN_=DEFAULT_TOP_N)
Query the SOW cache of a topic and initiates a new subscription on it.
Definition: ampsplusplus.hpp:6472
Message sowDelete(const std::string &topic_, const std::string &filter_, long timeout_=0)
Deletes one or more messages from a topic's SOW cache.
Definition: ampsplusplus.hpp:6867
MessageStream sowAndDeltaSubscribe(const std::string &topic_, long timeout_, const std::string &filter_="", int batchSize_=DEFAULT_BATCH_SIZE, bool oofEnabled_=false, bool sendEmpties_=false, int topN_=DEFAULT_TOP_N)
Query the SOW cache of a topic and initiates a new delta subscription on it.
Definition: ampsplusplus.hpp:6764
MessageStream sowAndSubscribe(const std::string &topic_, const std::string &filter_="", const std::string &orderBy_="", const std::string &bookmark_="", int batchSize_=DEFAULT_BATCH_SIZE, int topN_=DEFAULT_TOP_N, const std::string &options_="", long timeout_=DEFAULT_COMMAND_TIMEOUT)
Query the SOW cache of a topic and initiates a new subscription on it.
Definition: ampsplusplus.hpp:6559