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)
531 setBatchSize(AMPS_DEFAULT_BATCH_SIZE);
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& ) {;}
1076 virtual void execute(
Message& message_) = 0;
1091 typedef bool (*PublishStoreResizeHandler)(
Store store_,
1106 : _resizeHandler(NULL)
1107 , _resizeHandlerData(NULL)
1108 , _errorOnPublishGap(errorOnPublishGap_)
1115 virtual amps_uint64_t store(
const Message& message_) = 0;
1123 virtual void discardUpTo(amps_uint64_t index_) = 0;
1138 virtual bool replaySingle(
StoreReplayer& replayer_, amps_uint64_t index_) = 0;
1144 virtual size_t unpersistedCount()
const = 0;
1156 virtual void flush(
long timeout_) = 0;
1162 return AMPS_UNSET_INDEX;
1169 return AMPS_UNSET_SEQUENCE;
1175 virtual amps_uint64_t getLowestUnpersisted()
const = 0;
1180 virtual amps_uint64_t getLastPersisted() = 0;
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();
1391 virtual void failedWrite(
const Message& message_,
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_,
1475 unsigned requestedAckTypes_) = 0;
1489 virtual void clear() = 0;
1493 virtual void resubscribe(Client& client_) = 0;
1500 _failedResubscribeHandler = handler_;
1503 std::shared_ptr<FailedResubscribeHandler> _failedResubscribeHandler;
1514 typedef enum { Disconnected = 0,
1518 PublishReplayed = 8,
1519 HeartbeatInitiated = 16,
1533 virtual void connectionStateChanged(
State newState_) = 0;
1538 class MessageStreamImpl;
1541 typedef void(*DeferredExecutionFunc)(
void*);
1543 class ClientImpl :
public RefBody
1549 AMPS_SOCKET _socket;
1555 socklen_t _valueLen;
1559 : _socket(AMPS_INVALID_SOCKET), _noDelay(0), _valueLen(
sizeof(
int))
1561 _valuePtr = (
char*)&_noDelay;
1563 if (_socket != AMPS_INVALID_SOCKET)
1565 getsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, _valuePtr, &_valueLen);
1569 setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, _valuePtr, _valueLen);
1573 _socket = AMPS_INVALID_SOCKET;
1580 if (_socket != AMPS_INVALID_SOCKET)
1583 setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, _valuePtr, _valueLen);
1588 friend class Client;
1591 DisconnectHandler _disconnectHandler;
1592 enum GlobalCommandTypeHandlers :
size_t 1602 DuplicateMessage = 8,
1605 std::vector<MessageHandler> _globalCommandTypeHandlers;
1606 Message _beatMessage, _readMessage;
1608 MessageRouter::RouteCache _routeCache;
1609 mutable Mutex _lock;
1610 std::string _name, _nameHash, _connectionName, _lastUri, _logonCorrelationData, _preflightMessage;
1611 std::vector<std::string> _httpPreflightHeaders;
1612 amps_uint64_t _nameHashValue;
1614 Store _publishStore;
1615 bool _isRetryOnDisconnect;
1616 amps_unique_ptr<FailedWriteHandler> _failedWriteHandler;
1617 #if __cplusplus >= 201100L || _MSC_VER >= 1900 1618 std::atomic<amps_uint64_t> _lastSentHaSequenceNumber;
1620 volatile amps_uint64_t _lastSentHaSequenceNumber;
1622 AMPS_ATOMIC_TYPE_8 _logonInProgress;
1623 AMPS_ATOMIC_TYPE _subscriptionManagerGenerationCount;
1624 VersionInfo _serverVersion;
1625 Timer _heartbeatTimer;
1626 amps_unique_ptr<MessageStream> _pEmptyMessageStream;
1629 int _queueAckTimeout;
1630 bool _isAutoAckEnabled;
1631 unsigned _ackBatchSize;
1632 unsigned _queuedAckCount;
1633 unsigned _defaultMaxDepth;
1634 struct QueueBookmarks
1636 QueueBookmarks(
const std::string& topic_)
1643 amps_uint64_t _oldestTime;
1644 unsigned _bookmarkCount;
1646 typedef amps_uint64_t topic_hash;
1647 typedef std::map<topic_hash, QueueBookmarks> TopicHashMap;
1648 TopicHashMap _topicHashMap;
1652 ClientImpl* _client;
1657 ClientStoreReplayer()
1658 : _client(NULL), _version(0), _res(
AMPS_E_OK)
1661 ClientStoreReplayer(ClientImpl* client_)
1662 : _client(client_), _version(0), _res(
AMPS_E_OK)
1665 void setClient(ClientImpl* client_)
1670 void execute(
Message& message_)
1674 throw CommandException(
"Can't replay without a client.");
1678 if (index > _client->_lastSentHaSequenceNumber)
1680 _client->_lastSentHaSequenceNumber = index;
1688 (!_client->_logonInProgress ||
1692 message_.getMessage(),
1697 throw DisconnectedException(
"AMPS Server disconnected during replay");
1703 ClientStoreReplayer _replayer;
1707 ClientImpl* _parent;
1708 const char* _reason;
1709 size_t _reasonLength;
1710 size_t _replayCount;
1712 FailedWriteStoreReplayer(ClientImpl* parent,
const char* reason_,
size_t reasonLength_)
1715 _reasonLength(reasonLength_),
1718 void execute(
Message& message_)
1720 if (_parent->_failedWriteHandler)
1723 _parent->_failedWriteHandler->failedWrite(message_,
1724 _reason, _reasonLength);
1727 size_t replayCount(
void)
const 1729 return _replayCount;
1733 struct AckResponseImpl :
public RefBody
1735 std::string username, password, reason, status, bookmark, options;
1736 amps_uint64_t sequenceNo;
1737 amps_uint64_t nameHashValue;
1738 VersionInfo serverVersion;
1739 #if __cplusplus >= 201100L || _MSC_VER >= 1900 1740 std::atomic<bool> responded;
1741 std::atomic<bool> abandoned;
1743 volatile bool responded;
1744 volatile bool abandoned;
1746 unsigned connectionVersion;
1749 username(), password(), reason(), status(), bookmark(), options(),
1750 sequenceNo((amps_uint64_t)0),
1751 nameHashValue((amps_uint64_t)0),
1755 connectionVersion(UINT_MAX)
1762 RefHandle<AckResponseImpl> _body;
1764 AckResponse() : _body(NULL) {;}
1765 AckResponse(
const AckResponse& rhs) : _body(rhs._body) {;}
1766 static AckResponse create()
1769 r._body =
new AckResponseImpl();
1773 const std::string& username()
1775 return _body.get().username;
1777 void setUsername(
const char* data_,
size_t len_)
1781 _body.get().username.assign(data_, len_);
1785 _body.get().username.clear();
1788 const std::string& password()
1790 return _body.get().password;
1792 void setPassword(
const char* data_,
size_t len_)
1796 _body.get().password.assign(data_, len_);
1800 _body.get().password.clear();
1803 const std::string& reason()
1805 return _body.get().reason;
1807 void setReason(
const char* data_,
size_t len_)
1811 _body.get().reason.assign(data_, len_);
1815 _body.get().reason.clear();
1818 const std::string& status()
1820 return _body.get().status;
1822 void setStatus(
const char* data_,
size_t len_)
1826 _body.get().status.assign(data_, len_);
1830 _body.get().status.clear();
1833 const std::string& bookmark()
1835 return _body.get().bookmark;
1837 void setBookmark(
const Field& bookmark_)
1839 AckResponseImpl& body = _body.get();
1840 if (!bookmark_.
empty())
1842 body.bookmark.assign(bookmark_.
data(), bookmark_.
len());
1843 Field::parseBookmark(bookmark_, body.nameHashValue,
1848 body.bookmark.clear();
1849 body.sequenceNo = (amps_uint64_t)0;
1850 body.nameHashValue = (amps_uint64_t)0;
1853 amps_uint64_t sequenceNo()
const 1855 return _body.get().sequenceNo;
1857 amps_uint64_t nameHashValue()
const 1859 return _body.get().nameHashValue;
1861 void setSequenceNo(
const char* data_,
size_t len_)
1863 amps_uint64_t result = (amps_uint64_t)0;
1866 for (
size_t i = 0; i < len_; ++i)
1868 result *= (amps_uint64_t)10;
1869 result += (amps_uint64_t)(data_[i] -
'0');
1872 _body.get().sequenceNo = result;
1874 VersionInfo serverVersion()
const 1876 return _body.get().serverVersion;
1878 void setServerVersion(
const char* data_,
size_t len_)
1882 _body.get().serverVersion.setVersion(std::string(data_, len_));
1887 return _body.get().responded;
1891 _body.get().responded =
true;
1895 return _body.get().abandoned;
1899 if (_body.isValid())
1901 _body.get().abandoned =
true;
1905 void setConnectionVersion(
unsigned connectionVersion)
1907 _body.get().connectionVersion = connectionVersion;
1910 unsigned getConnectionVersion()
1912 return _body.get().connectionVersion;
1915 void setOptions(
const char* data_,
size_t len_)
1919 _body.get().options.assign(data_, len_);
1923 _body.get().options.clear();
1927 const std::string& options()
1929 return _body.get().options;
1932 AckResponse& operator=(
const AckResponse& rhs)
1940 typedef std::map<std::string, AckResponse> AckMap;
1943 DefaultExceptionListener _defaultExceptionListener;
1946 struct DeferredExecutionRequest
1948 DeferredExecutionRequest(DeferredExecutionFunc func_,
1951 _userData(userData_)
1954 DeferredExecutionFunc _func;
1958 std::shared_ptr<const ExceptionListener> _pExceptionListener;
1959 amps_unique_ptr<SubscriptionManager> _subscriptionManager;
1960 volatile bool _connected;
1961 std::string _username;
1962 typedef std::set<ConnectionStateListener*> ConnectionStateListeners;
1963 ConnectionStateListeners _connectionStateListeners;
1964 typedef std::vector<DeferredExecutionRequest> DeferredExecutionList;
1965 Mutex _deferredExecutionLock;
1966 DeferredExecutionList _deferredExecutionList;
1967 unsigned _heartbeatInterval;
1968 unsigned _readTimeout;
1976 if (!_connected && newState_ > ConnectionStateListener::Connected)
1980 for (ConnectionStateListeners::iterator it = _connectionStateListeners.begin(); it != _connectionStateListeners.end(); ++it)
1982 AMPS_CALL_EXCEPTION_WRAPPER(
1983 (*it)->connectionStateChanged(newState_));
1986 void captureSubscriptionManagerGenerationCount()
1988 if (_subscriptionManager)
1990 _subscriptionManagerGenerationCount = _subscriptionManager->getGenerationCount();
1994 unsigned processedAck(
Message& message);
1995 unsigned persistedAck(
Message& meesage);
1996 void lastChance(
Message& message);
1997 void checkAndSendHeartbeat(
bool force =
false);
1998 virtual ConnectionInfo getConnectionInfo()
const;
2000 ClientImplMessageHandler(
amps_handle message,
void* userData);
2002 ClientImplPreDisconnectHandler(
amps_handle client,
unsigned failedConnectionVersion,
void* userData);
2004 ClientImplDisconnectHandler(
amps_handle client,
void* userData);
2006 ClientImplGetHttpPreflightMessage(
void* userData);
2008 void unsubscribeInternal(
const std::string&
id)
2016 subId.assign(
id.data(),
id.length());
2017 _routes.removeRoute(subId);
2019 if (_subscriptionManager)
2022 Unlock<Mutex> unlock(_lock);
2023 _subscriptionManager->unsubscribe(subId);
2025 threadLocalMessage.reset();
2026 threadLocalMessage.
setCommandEnum(Message::Command::Unsubscribe);
2029 _sendWithoutRetry(threadLocalMessage);
2030 deferredExecution(&s_noOpFn, NULL);
2033 AckResponse syncAckProcessing(
long timeout_,
Message& message_,
2034 amps_uint64_t haSeq = (amps_uint64_t)0,
2035 AMPS_ATOMIC_BASE_TYPE subscribeGeneration_ = 0)
2037 bool isLogon = message_.
getCommand() ==
"logon";
2038 if (_logonInProgress && !isLogon)
2040 while (_logonInProgress)
2042 if (!_lock.wait(200))
2044 amps_invoke_waiting_function();
2045 if (!_isRetryOnDisconnect)
2054 AckResponse ack = AckResponse::create();
2057 Lock<Mutex> guard(_ackMapLock);
2060 if (subscribeGeneration_ == 0)
2062 ack.setConnectionVersion((
unsigned)_sendSequenced(message_, haSeq, 0));
2066 ack.setConnectionVersion((
unsigned)_send(message_, subscribeGeneration_));
2068 if (ack.getConnectionVersion() == 0)
2071 throw DisconnectedException(
"Connection closed while waiting for response.");
2073 else if (ack.getConnectionVersion() == UINT_MAX)
2076 Lock<Mutex> guard(_ackMapLock);
2077 AckMap::iterator i = _ackMap.find(message_.
getCommandId());
2078 if (i != _ackMap.end())
2084 bool timedOut =
false;
2085 AMPS_START_TIMER(timeout_)
2086 while (!timedOut && !ack.responded() && !ack.abandoned())
2090 timedOut = !_lock.wait(timeout_);
2094 AMPS_RESET_TIMER(timedOut, timeout_);
2101 Unlock<Mutex> unlck(_lock);
2102 amps_invoke_waiting_function();
2105 if (ack.responded())
2107 if (ack.status() !=
"failure")
2111 amps_uint64_t ackSequence = ack.sequenceNo();
2112 if (_lastSentHaSequenceNumber < ackSequence)
2114 _lastSentHaSequenceNumber = ackSequence;
2127 _nameHash = ack.bookmark().substr(0, ack.bookmark().find(
'|'));
2128 _nameHashValue = ack.nameHashValue();
2129 const std::string& ackOptions = ack.options();
2130 size_t start = ackOptions.find(
"connection_name=");
2131 if (start != std::string::npos)
2134 size_t end = ackOptions.find(
',', start);
2135 if (end != std::string::npos)
2139 _connectionName = ackOptions.substr(start, end);
2141 _serverVersion = ack.serverVersion();
2142 if (_bookmarkStore.isValid())
2149 const std::string& options = ack.options();
2150 size_t index = options.find_first_of(
"max_backlog=");
2151 if (index != std::string::npos)
2154 const char* c = options.c_str() + index + 12;
2155 while (*c && *c !=
',')
2157 data = (data * 10) + (
unsigned)(*c++ -48);
2159 if (_ackBatchSize > data)
2161 _ackBatchSize = data;
2167 const size_t NotEntitled = 12;
2168 std::string ackReason = ack.reason();
2169 if (ackReason.length() == 0)
2173 if (ackReason.length() == NotEntitled &&
2174 ackReason[0] ==
'n' &&
2179 message_.throwFor(_client, ackReason);
2183 if (!ack.abandoned())
2185 throw TimedOutException(
"timed out waiting for operation.");
2189 throw DisconnectedException(
"Connection closed while waiting for response.");
2203 AMPS_CALL_EXCEPTION_WRAPPER(ClientImpl::disconnect());
2204 _pEmptyMessageStream.reset(NULL);
2211 ClientImpl(
const std::string& clientName)
2212 : _client(NULL), _name(clientName)
2213 , _isRetryOnDisconnect(
true)
2214 , _lastSentHaSequenceNumber((amps_uint64_t)0), _logonInProgress(0)
2215 , _subscriptionManagerGenerationCount(0), _serverVersion()
2216 , _queueAckTimeout(AMPS_DEFAULT_QUEUE_ACK_TIMEOUT)
2217 , _isAutoAckEnabled(
false)
2219 , _queuedAckCount(0)
2220 , _defaultMaxDepth(0)
2222 , _heartbeatInterval(0)
2225 _replayer.setClient(
this);
2228 (amps_handler)ClientImpl::ClientImplMessageHandler,
2231 (amps_predisconnect_handler)ClientImpl::ClientImplPreDisconnectHandler,
2234 (amps_handler)ClientImpl::ClientImplDisconnectHandler,
2237 ClientImpl::ClientImplGetHttpPreflightMessage,
2239 _exceptionListener = &_defaultExceptionListener;
2240 for (
size_t i = 0; i < GlobalCommandTypeHandlers::COUNT; ++i)
2246 virtual ~ClientImpl()
2251 const std::string& getName()
const 2256 const std::string& getNameHash()
const 2261 const amps_uint64_t getNameHashValue()
const 2263 return _nameHashValue;
2266 const std::string& getConnectionName()
const 2268 return _connectionName;
2271 void setName(
const std::string& name)
2283 const std::string& getLogonCorrelationData()
const 2285 return _logonCorrelationData;
2288 void setLogonCorrelationData(
const std::string& logonCorrelationData_)
2290 _logonCorrelationData = logonCorrelationData_;
2293 size_t getServerVersion()
const 2295 return _serverVersion.getOldStyleVersion();
2298 VersionInfo getServerVersionInfo()
const 2300 return _serverVersion;
2303 const std::string& getURI()
const 2308 virtual void connect(
const std::string& uri)
2310 Lock<Mutex> l(_lock);
2314 virtual void _connect(
const std::string& uri)
2322 threadLocalMessage.reset();
2325 _readMessage.setClientImpl(
this);
2326 if (_queueAckTimeout)
2335 broadcastConnectionStateChanged(ConnectionStateListener::Connected);
2338 void addHttpPreflightHeader(
const std::string& header_)
2340 _httpPreflightHeaders.emplace_back(header_);
2343 void addHttpPreflightHeader(
const std::string& key_,
const std::string& value_)
2345 _httpPreflightHeaders.emplace_back(key_ + std::string(
": ") + value_);
2348 void clearHttpPreflightHeaders()
2350 _httpPreflightHeaders.clear();
2354 void setHttpPreflightHeaders(
const T& headers_)
2356 _httpPreflightHeaders.clear();
2357 for (
typename T::const_iterator i = headers_.begin(); i != headers_.end(); ++i)
2359 _httpPreflightHeaders.push_back(*i);
2363 void setDisconnected()
2366 Lock<Mutex> l(_lock);
2369 AMPS_CALL_EXCEPTION_WRAPPER(broadcastConnectionStateChanged(ConnectionStateListener::Disconnected));
2372 _heartbeatTimer.setTimeout(0.0);
2375 clearAcks(UINT_MAX-1);
2381 virtual void disconnect()
2383 AMPS_CALL_EXCEPTION_WRAPPER(flushAcks());
2386 clearAcks(UINT_MAX);
2387 AMPS_CALL_EXCEPTION_WRAPPER(processDeferredExecutions());
2388 Lock<Mutex> l(_lock);
2389 broadcastConnectionStateChanged(ConnectionStateListener::Shutdown);
2392 void clearAcks(
unsigned failedVersion)
2395 Lock<Mutex> guard(_ackMapLock);
2398 std::vector<std::string> worklist;
2399 for (AckMap::iterator i = _ackMap.begin(), e = _ackMap.end(); i != e; ++i)
2401 if (i->second.getConnectionVersion() <= failedVersion)
2403 i->second.setAbandoned();
2404 worklist.push_back(i->first);
2408 for (std::vector<std::string>::iterator j = worklist.begin(), e = worklist.end(); j != e; ++j)
2417 unsigned send(
const Message& message)
2419 Lock<Mutex> l(_lock);
2420 return _send(message);
2423 void sendWithoutRetry(
const Message& message_)
2425 Lock<Mutex> l(_lock);
2428 if (_logonInProgress)
2430 throw DisconnectedException(
"The client has been disconnected.");
2432 _sendWithoutRetry(message_);
2435 void _sendWithoutRetry(
const Message& message_)
2446 unsigned _sendSequenced(
const Message& message, amps_uint64_t haSeq,
int isBatch_)
2453 Message localMessage = message;
2454 unsigned version = 0;
2455 bool isNotLogon = (haSeq) || (localMessage.
getCommand().
data()[0] !=
'l');
2459 if (_logonInProgress && isNotLogon)
2461 if (!_isRetryOnDisconnect)
2474 if (localMessage.getMessage() == message.getMessage())
2478 while (_logonInProgress)
2480 if (!_lock.wait(1000))
2482 amps_invoke_waiting_function();
2489 if (haSeq <= _lastSentHaSequenceNumber)
2496 while (haSeq > _lastSentHaSequenceNumber + 1)
2502 _lastSentHaSequenceNumber + 1))
2507 version = _replayer._version;
2510 catch (
const DisconnectedException&)
2512 catch (
const DisconnectedException& e)
2515 if (!_isRetryOnDisconnect)
2520 result = _replayer._res;
2524 ++_lastSentHaSequenceNumber;
2527 localMessage.getMessage(),
2533 && localMessage.getMessage() == message.getMessage())
2537 if (_isRetryOnDisconnect)
2539 Unlock<Mutex> u(_lock);
2566 amps_invoke_waiting_function();
2579 unsigned _send(
const Message& message, AMPS_ATOMIC_BASE_TYPE subscribeGeneration_ = 0)
2586 Message localMessage = message;
2587 unsigned version = 0;
2588 bool isHASubscribe = subscribeGeneration_ > 0;
2592 if (_logonInProgress && localMessage.
getCommand().
data()[0] !=
'l')
2595 && localMessage.getMessage() == message.getMessage())
2599 while (_logonInProgress)
2601 if (!_lock.wait(1000))
2603 amps_invoke_waiting_function();
2604 if (!_isRetryOnDisconnect)
2613 && subscribeGeneration_ <= (AMPS_ATOMIC_BASE_TYPE)_subscriptionManagerGenerationCount)
2621 localMessage.getMessage(),
2627 && localMessage.getMessage() == message.getMessage())
2631 if (_isRetryOnDisconnect)
2633 Unlock<Mutex> u(_lock);
2638 if (isHASubscribe &&
2656 amps_invoke_waiting_function();
2667 void addMessageHandler(
const Field& commandId_,
2669 unsigned requestedAcks_, Message::Command::Type commandType_)
2671 Lock<Mutex> lock(_lock);
2672 _routes.addRoute(commandId_, messageHandler_, requestedAcks_,
2676 bool removeMessageHandler(
const Field& commandId_)
2678 Lock<Mutex> lock(_lock);
2679 return _routes.removeRoute(commandId_);
2685 AMPS_ATOMIC_BASE_TYPE subscribeGeneration_ = 0)
2690 bool isSubscribeOnly =
false;
2691 bool replace =
false;
2693 unsigned systemAddedAcks = Message::AckType::None;
2696 switch (commandType)
2698 case Message::Command::Subscribe:
2699 case Message::Command::DeltaSubscribe:
2700 replace = message_.
getOptions().operator std::string().find(AMPS_OPTIONS_REPLACE, 0, strlen(AMPS_OPTIONS_REPLACE) - 1) != std::string::npos;
2701 isSubscribeOnly =
true;
2703 case Message::Command::SOWAndSubscribe:
2704 case Message::Command::SOWAndDeltaSubscribe:
2711 while (!replace &&
id != subId && _routes.hasRoute(
id))
2723 systemAddedAcks |= Message::AckType::Persisted;
2726 case Message::Command::SOW:
2733 while (!replace &&
id != subId && _routes.hasRoute(
id))
2744 if (!isSubscribeOnly)
2753 while (!replace && qid != subId && qid !=
id 2754 && _routes.hasRoute(qid))
2760 systemAddedAcks |= Message::AckType::Processed;
2763 int routesAdded = 0;
2764 Lock<Mutex> l(_lock);
2766 if (subscribeGeneration_ > 0
2767 && subscribeGeneration_ <= _subscriptionManagerGenerationCount)
2770 return std::string();
2772 if (!subId.
empty() && messageHandler_.isValid())
2774 if (!_routes.hasRoute(subId))
2780 _routes.addRoute(subId, messageHandler_, requestedAcks,
2781 systemAddedAcks, commandType);
2783 if (!isSubscribeOnly && !qid.
empty()
2784 && messageHandler_.isValid() && qid != subId)
2786 if (routesAdded == 0)
2788 _routes.addRoute(qid, messageHandler_,
2789 requestedAcks, systemAddedAcks, commandType);
2795 Unlock<Mutex> u(_lock);
2796 data = amps_invoke_copy_route_function(
2797 messageHandler_.userData());
2801 _routes.addRoute(qid, messageHandler_, requestedAcks,
2802 systemAddedAcks, commandType);
2806 _routes.addRoute(qid,
2809 requestedAcks, systemAddedAcks, commandType);
2814 if (!
id.empty() && messageHandler_.isValid()
2815 && requestedAcks & ~
Message::AckType::Persisted
2816 &&
id != subId &&
id != qid)
2818 if (routesAdded == 0)
2820 _routes.addRoute(
id, messageHandler_, requestedAcks,
2821 systemAddedAcks, commandType);
2827 Unlock<Mutex> u(_lock);
2828 data = amps_invoke_copy_route_function(
2829 messageHandler_.userData());
2833 _routes.addRoute(
id, messageHandler_, requestedAcks,
2834 systemAddedAcks, commandType);
2838 _routes.addRoute(
id,
2842 systemAddedAcks, commandType);
2849 AckResponse resp = syncAckProcessing(timeout_, message_, 0, subscribeGeneration_);
2851 if (resp.getConnectionVersion() == UINT_MAX)
2860 _routes.removeRoute(
id);
2868 _routes.removeRoute(
id);
2875 case Message::Command::Unsubscribe:
2876 case Message::Command::Heartbeat:
2877 case Message::Command::Logon:
2878 case Message::Command::StartTimer:
2879 case Message::Command::StopTimer:
2880 case Message::Command::SOWDelete:
2882 Lock<Mutex> l(_lock);
2891 if (messageHandler_.isValid())
2893 _routes.addRoute(
id, messageHandler_, requestedAcks,
2894 Message::AckType::None, commandType);
2900 case Message::Command::DeltaPublish:
2901 case Message::Command::Publish:
2904 Lock<Mutex> l(_lock);
2907 if (ackType != Message::AckType::None
2915 if (messageHandler_.isValid())
2917 _routes.addRoute(
id, messageHandler_, requestedAcks,
2918 Message::AckType::None, commandType);
2924 syncAckProcessing(timeout_, message_, 0, 0);
2928 _sendSequenced(message_, 0, 1);
2933 case Message::Command::GroupBegin:
2934 case Message::Command::GroupEnd:
2935 case Message::Command::OOF:
2936 case Message::Command::Ack:
2937 case Message::Command::Unknown:
2939 throw CommandException(
"Command type " + message_.
getCommand() +
" can not be sent directly to AMPS");
2945 void setDisconnectHandler(
const DisconnectHandler& disconnectHandler)
2947 Lock<Mutex> l(_lock);
2948 _disconnectHandler = disconnectHandler;
2951 void setGlobalCommandTypeMessageHandler(
const std::string& command_,
const MessageHandler& handler_)
2953 switch (command_[0])
2955 #if 0 // Not currently implemented to avoid an extra branch in delivery 2957 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Publish] = handler_;
2960 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::SOW] = handler_;
2964 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Heartbeat] = handler_;
2966 #if 0 // Not currently implemented to avoid an extra branch in delivery 2968 if (command_[6] ==
'b')
2970 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupBegin] = handler_;
2972 else if (command_[6] ==
'e')
2974 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupEnd] = handler_;
2978 std::ostringstream os;
2979 os <<
"Invalid command '" << command_ <<
"' passed to setGlobalCommandTypeHandler";
2980 throw CommandException(os.str());
2984 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::OOF] = handler_;
2988 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Ack] = handler_;
2992 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::LastChance] = handler_;
2996 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage] = handler_;
2999 std::ostringstream os;
3000 os <<
"Invalid command '" << command_ <<
"' passed to setGlobalCommandTypeHandler";
3001 throw CommandException(os.str());
3006 void setGlobalCommandTypeMessageHandler(
const Message::Command::Type command_,
const MessageHandler& handler_)
3010 #if 0 // Not currently implemented to avoid an extra branch in delivery 3011 case Message::Command::Publish:
3012 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Publish] = handler_;
3014 case Message::Command::SOW:
3015 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::SOW] = handler_;
3018 case Message::Command::Heartbeat:
3019 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Heartbeat] = handler_;
3021 #if 0 // Not currently implemented to avoid an extra branch in delivery 3022 case Message::Command::GroupBegin:
3023 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupBegin] = handler_;
3025 case Message::Command::GroupEnd:
3026 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::GroupEnd] = handler_;
3028 case Message::Command::OOF:
3029 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::OOF] = handler_;
3032 case Message::Command::Ack:
3033 _globalCommandTypeHandlers[GlobalCommandTypeHandlers::Ack] = handler_;
3037 unsigned command = command_;
3044 AMPS_snprintf(errBuf,
sizeof(errBuf),
3045 "Invalid command '%.*s' passed to setGlobalCommandTypeHandler",
3046 CommandConstants<0>::Lengths[bits],
3047 CommandConstants<0>::Values[bits]);
3048 throw CommandException(errBuf);
3053 void setGlobalCommandTypeMessageHandler(
const GlobalCommandTypeHandlers handlerType_,
const MessageHandler& handler_)
3055 _globalCommandTypeHandlers[handlerType_] = handler_;
3060 Lock<Mutex> l(_lock);
3061 _failedWriteHandler.reset(handler_);
3064 void setPublishStore(
const Store& publishStore_)
3066 Lock<Mutex> l(_lock);
3069 throw AlreadyConnectedException(
"Setting a publish store on a connected client is undefined behavior");
3071 _publishStore = publishStore_;
3076 Lock<Mutex> l(_lock);
3079 throw AlreadyConnectedException(
"Setting a bookmark store on a connected client is undefined behavior");
3081 _bookmarkStore = bookmarkStore_;
3086 Lock<Mutex> l(_lock);
3089 throw AlreadyConnectedException(
"Setting a subscription manager on a connected client is undefined behavior");
3091 _subscriptionManager.reset(subscriptionManager_);
3092 captureSubscriptionManagerGenerationCount();
3100 DisconnectHandler getDisconnectHandler()
const 3102 return _disconnectHandler;
3107 return _globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage];
3115 Store getPublishStore()
const 3117 return _publishStore;
3122 return _bookmarkStore;
3125 amps_uint64_t publish(
Message& message_)
3129 Lock<Mutex> l(_lock);
3130 _sendSequenced(message_, 0, 1);
3136 amps_uint64_t haSequenceNumber = _publishStore.
store(message_);
3137 char buf[AMPS_NUMBER_BUFFER_LEN];
3138 size_t pos = convertToCharArray(buf, haSequenceNumber);
3139 message_.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
3141 Lock<Mutex> l(_lock);
3142 _sendSequenced(message_, haSequenceNumber, 1);
3144 return haSequenceNumber;
3148 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
const char* data_,
size_t dataLen_)
3150 threadLocalMessage.reset();
3153 .assignData(data_, dataLen_);
3156 Lock<Mutex> l(_lock);
3157 _sendSequenced(threadLocalMessage, 0, 1);
3166 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
const char* data_,
3167 size_t dataLen_,
unsigned long expiration_)
3169 threadLocalMessage.reset();
3170 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
3171 size_t exprPos = convertToCharArray(exprBuf, expiration_);
3174 .assignData(data_, dataLen_)
3176 AMPS_NUMBER_BUFFER_LEN - exprPos);
3179 Lock<Mutex> l(_lock);
3180 _sendSequenced(threadLocalMessage, 0, 1);
3189 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
3190 const char* data_,
size_t dataLen_,
3191 const char* correlationId_,
size_t correlationIdLen_)
3193 threadLocalMessage.reset();
3196 .assignData(data_, dataLen_)
3200 Lock<Mutex> l(_lock);
3201 _sendSequenced(threadLocalMessage, 0, 1);
3210 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
3211 const char* data_,
size_t dataLen_,
3212 const char* correlationId_,
size_t correlationIdLen_,
3213 unsigned long expiration_)
3215 threadLocalMessage.reset();
3216 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
3217 size_t exprPos = convertToCharArray(exprBuf, expiration_);
3220 .assignData(data_, dataLen_)
3223 AMPS_NUMBER_BUFFER_LEN - exprPos);
3226 Lock<Mutex> l(_lock);
3227 _sendSequenced(threadLocalMessage, 0, 1);
3236 amps_uint64_t publishKeyed(
const char* topic_,
size_t topicLen_,
3237 const char* data_,
size_t dataLen_,
3238 const char* sowKey_,
size_t sowKeyLen_)
3240 threadLocalMessage.reset();
3243 .assignData(data_, dataLen_)
3247 Lock<Mutex> l(_lock);
3248 _sendSequenced(threadLocalMessage, 0, 1);
3257 amps_uint64_t publishKeyed(
const char* topic_,
size_t topicLen_,
3258 const char* data_,
size_t dataLen_,
3259 const char* sowKey_,
size_t sowKeyLen_,
3260 unsigned long expiration_)
3262 threadLocalMessage.reset();
3263 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
3264 size_t exprPos = convertToCharArray(exprBuf, expiration_);
3267 .assignData(data_, dataLen_)
3270 AMPS_NUMBER_BUFFER_LEN - exprPos);
3273 Lock<Mutex> l(_lock);
3274 _sendSequenced(threadLocalMessage, 0, 1);
3283 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
3284 const char* data_,
size_t dataLen_,
3285 const char* correlationId_,
size_t correlationIdLen_,
3286 const char* sowKey_,
size_t sowKeyLen_)
3288 threadLocalMessage.reset();
3291 .assignData(data_, dataLen_)
3296 Lock<Mutex> l(_lock);
3297 _sendSequenced(threadLocalMessage, 0, 1);
3306 amps_uint64_t publish(
const char* topic_,
size_t topicLen_,
3307 const char* data_,
size_t dataLen_,
3308 const char* correlationId_,
size_t correlationIdLen_,
3309 const char* sowKey_,
size_t sowKeyLen_,
3310 unsigned long expiration_)
3312 threadLocalMessage.reset();
3313 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
3314 size_t exprPos = convertToCharArray(exprBuf, expiration_);
3317 .assignData(data_, dataLen_)
3321 AMPS_NUMBER_BUFFER_LEN - exprPos);
3324 Lock<Mutex> l(_lock);
3325 _sendSequenced(threadLocalMessage, 0, 1);
3337 ClientImpl* _pClient;
3339 #if __cplusplus >= 201100L || _MSC_VER >= 1900 3340 std::atomic<bool> _acked;
3341 std::atomic<bool> _disconnected;
3343 volatile bool _acked;
3344 volatile bool _disconnected;
3347 FlushAckHandler(ClientImpl* pClient_)
3348 : _pClient(pClient_), _cmdId(), _acked(
false), _disconnected(
false)
3350 pClient_->addConnectionStateListener(
this);
3354 _pClient->removeConnectionStateListener(
this);
3355 _pClient->removeMessageHandler(_cmdId);
3358 void setCommandId(
const Field& cmdId_)
3366 void connectionStateChanged(
State state_)
3368 if (state_ <= Shutdown)
3370 _disconnected =
true;
3379 return _acked || _disconnected;
3383 void publishFlush(
long timeout_,
unsigned ackType_)
3385 static const char* processed =
"processed";
3386 static const size_t processedLen = strlen(processed);
3387 static const char* persisted =
"persisted";
3388 static const size_t persistedLen = strlen(persisted);
3389 static const char* flush =
"flush";
3390 static const size_t flushLen = strlen(flush);
3391 static const VersionInfo minPersisted(
"5.3.3.0");
3392 static const VersionInfo minFlush(
"4");
3393 if (ackType_ != Message::AckType::Processed
3394 && ackType_ != Message::AckType::Persisted)
3396 throw CommandException(
"Flush can only be used with processed or persisted acks.");
3398 FlushAckHandler flushHandler(
this);
3399 if (_serverVersion >= minFlush)
3401 Lock<Mutex> l(_lock);
3404 throw DisconnectedException(
"Not connected trying to flush");
3406 threadLocalMessage.reset();
3409 if (_serverVersion < minPersisted
3410 || ackType_ == Message::AckType::Processed)
3418 flushHandler.setCommandId(threadLocalMessage.
getCommandId());
3420 std::bind(&FlushAckHandler::invoke,
3421 std::ref(flushHandler),
3422 std::placeholders::_1),
3424 NoDelay noDelay(_client);
3425 _send(threadLocalMessage);
3431 _publishStore.
flush(timeout_);
3435 AMPS_UNHANDLED_EXCEPTION(ex);
3439 else if (_serverVersion < minFlush)
3443 AMPS_USLEEP(timeout_ * 1000);
3447 AMPS_USLEEP(1000 * 1000);
3453 Timer timer((
double)timeout_);
3455 while (!timer.check() && !flushHandler.done())
3458 amps_invoke_waiting_function();
3463 while (!flushHandler.done())
3466 amps_invoke_waiting_function();
3470 if (!flushHandler.done())
3472 throw TimedOutException(
"Timed out waiting for flush");
3475 if (!flushHandler.acked() && !_publishStore.
isValid())
3477 throw DisconnectedException(
"Disconnected waiting for flush");
3481 amps_uint64_t deltaPublish(
const char* topic_,
size_t topicLength_,
3482 const char* data_,
size_t dataLength_)
3484 threadLocalMessage.reset();
3485 threadLocalMessage.
setCommandEnum(Message::Command::DeltaPublish)
3487 .assignData(data_, dataLength_);
3490 Lock<Mutex> l(_lock);
3491 _sendSequenced(threadLocalMessage, 0, 1);
3500 amps_uint64_t deltaPublish(
const char* topic_,
size_t topicLength_,
3501 const char* data_,
size_t dataLength_,
3502 unsigned long expiration_)
3504 threadLocalMessage.reset();
3505 char exprBuf[AMPS_NUMBER_BUFFER_LEN];
3506 size_t exprPos = convertToCharArray(exprBuf, expiration_);
3507 threadLocalMessage.
setCommandEnum(Message::Command::DeltaPublish)
3509 .assignData(data_, dataLength_)
3511 AMPS_NUMBER_BUFFER_LEN - exprPos);
3514 Lock<Mutex> l(_lock);
3515 _sendSequenced(threadLocalMessage, 0, 1);
3524 amps_uint64_t _publish(
void)
3527 amps_uint64_t haSequenceNumber = _publishStore.
store(threadLocalMessage);
3528 char buf[AMPS_NUMBER_BUFFER_LEN];
3529 size_t pos = convertToCharArray(buf, haSequenceNumber);
3530 threadLocalMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
3532 Lock<Mutex> l(_lock);
3533 _sendSequenced(threadLocalMessage, haSequenceNumber, 1);
3535 return haSequenceNumber;
3538 virtual std::string logon(
long timeout_,
Authenticator& authenticator_,
3539 const char* options_ = NULL);
3541 virtual std::string _logon(
long timeout_,
Authenticator& authenticator_,
3542 const char* options_ = NULL)
3545 threadLocalMessage.reset();
3547 std::string newCommandId = threadLocalMessage.
getCommandId();
3550 #ifdef AMPS_CLIENT_VERSION_WITH_LANGUAGE 3551 threadLocalMessage.
assignVersion(AMPS_CLIENT_VERSION_WITH_LANGUAGE,
3552 strlen(AMPS_CLIENT_VERSION_WITH_LANGUAGE));
3555 if (uri.user().size())
3557 threadLocalMessage.
setUserId(uri.user());
3559 if (uri.password().size())
3563 if (uri.protocol() ==
"amps" && uri.messageType().size())
3567 if (uri.isTrue(
"pretty"))
3573 if (!_logonCorrelationData.empty())
3581 _username = threadLocalMessage.
getUserId();
3584 AtomicFlagFlip pubFlip(&_logonInProgress);
3585 NoDelay noDelay(_client);
3589 AckResponse ack = syncAckProcessing(timeout_, threadLocalMessage);
3590 if (ack.status() ==
"retry")
3592 threadLocalMessage.
setPassword(authenticator_.
retry(ack.username(), ack.password()));
3593 _username = ack.username();
3594 threadLocalMessage.
setUserId(_username);
3598 authenticator_.
completed(ack.username(), ack.password(), ack.reason());
3602 broadcastConnectionStateChanged(ConnectionStateListener::LoggedOn);
3612 Unlock<Mutex> u(_lock);
3616 AMPS_UNHANDLED_EXCEPTION(ex);
3622 Unlock<Mutex> u(_lock);
3633 _publishStore.
replay(_replayer);
3634 broadcastConnectionStateChanged(ConnectionStateListener::PublishReplayed);
3636 catch (
const PublishStoreGapException& ex)
3639 Unlock<Mutex> u(_lock);
3643 AMPS_UNHANDLED_EXCEPTION(ex);
3646 catch (
const StoreException& ex)
3649 Unlock<Mutex> u(_lock);
3653 std::ostringstream os;
3654 os <<
"A local store exception occurred while logging on." 3656 throw ConnectionException(os.str());
3661 Unlock<Mutex> u(_lock);
3665 AMPS_UNHANDLED_EXCEPTION(ex);
3668 catch (
const std::exception& ex)
3671 Unlock<Mutex> u(_lock);
3675 AMPS_UNHANDLED_EXCEPTION(ex);
3681 Unlock<Mutex> u(_lock);
3689 return newCommandId;
3693 const std::string& topic_,
3695 const std::string& filter_,
3696 const std::string& bookmark_,
3697 const std::string& options_,
3698 const std::string& subId_,
3699 bool isHASubscribe_ =
true)
3701 isHASubscribe_ &= (bool)_subscriptionManager;
3702 Lock<Mutex> l(_lock);
3703 threadLocalMessage.reset();
3706 std::string subId(subId_);
3709 if (options_.find(AMPS_OPTIONS_REPLACE, 0, strlen(AMPS_OPTIONS_REPLACE) - 1) != std::string::npos)
3711 throw ConnectionException(
"Cannot issue a replacement subscription; a valid subscription id is required.");
3718 unsigned ackTypes = Message::AckType::Processed;
3720 if (!bookmark_.empty() && _bookmarkStore.isValid())
3722 ackTypes |= Message::AckType::Persisted;
3724 threadLocalMessage.
setTopic(topic_);
3726 if (filter_.length())
3730 if (bookmark_.length())
3741 if (_bookmarkStore.isValid())
3746 _bookmarkStore.
log(threadLocalMessage);
3747 _bookmarkStore.
discard(threadLocalMessage);
3753 if (options_.length())
3758 Message message = threadLocalMessage;
3759 AMPS_ATOMIC_BASE_TYPE generation = (AMPS_ATOMIC_BASE_TYPE)0;
3762 message = threadLocalMessage.
deepCopy();
3764 Unlock<Mutex> u(_lock);
3766 _subscriptionManager->subscribe(messageHandler_, message,
3767 Message::AckType::None);
3769 if (generation <= (AMPS_ATOMIC_BASE_TYPE)_subscriptionManagerGenerationCount)
3780 if (!options_.empty())
3786 syncAckProcessing(timeout_, message, 0, generation);
3788 catch (
const DisconnectedException&)
3790 if (!isHASubscribe_)
3792 _routes.removeRoute(subIdField);
3797 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subIdField));
3801 catch (
const TimedOutException&)
3803 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subIdField));
3811 Unlock<Mutex> unlock(_lock);
3812 _subscriptionManager->unsubscribe(subIdField);
3814 _routes.removeRoute(subIdField);
3820 std::string deltaSubscribe(
const MessageHandler& messageHandler_,
3821 const std::string& topic_,
3823 const std::string& filter_,
3824 const std::string& bookmark_,
3825 const std::string& options_,
3826 const std::string& subId_ =
"",
3827 bool isHASubscribe_ =
true)
3829 isHASubscribe_ &= (bool)_subscriptionManager;
3830 Lock<Mutex> l(_lock);
3831 threadLocalMessage.reset();
3832 threadLocalMessage.
setCommandEnum(Message::Command::DeltaSubscribe);
3834 std::string subId(subId_);
3841 unsigned ackTypes = Message::AckType::Processed;
3843 if (!bookmark_.empty() && _bookmarkStore.isValid())
3845 ackTypes |= Message::AckType::Persisted;
3847 threadLocalMessage.
setTopic(topic_);
3848 if (filter_.length())
3852 if (bookmark_.length())
3863 if (_bookmarkStore.isValid())
3868 _bookmarkStore.
log(threadLocalMessage);
3869 _bookmarkStore.
discard(threadLocalMessage);
3875 if (options_.length())
3879 AMPS_ATOMIC_BASE_TYPE generation = (AMPS_ATOMIC_BASE_TYPE)0;
3883 Unlock<Mutex> u(_lock);
3885 _subscriptionManager->subscribe(messageHandler_, threadLocalMessage.
deepCopy(),
3886 Message::AckType::None);
3888 if (generation <= (AMPS_ATOMIC_BASE_TYPE)_subscriptionManagerGenerationCount)
3896 Message::AckType::None, ackTypes, threadLocalMessage.
getCommandEnum());
3899 if (!options_.empty())
3905 syncAckProcessing(timeout_, threadLocalMessage, 0, generation);
3907 catch (
const DisconnectedException&)
3909 if (!isHASubscribe_)
3911 _routes.removeRoute(subIdField);
3915 catch (
const TimedOutException&)
3917 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subIdField));
3925 Unlock<Mutex> unlock(_lock);
3926 _subscriptionManager->unsubscribe(subIdField);
3928 _routes.removeRoute(subIdField);
3934 void unsubscribe(
const std::string&
id)
3936 Lock<Mutex> l(_lock);
3937 unsubscribeInternal(
id);
3940 void unsubscribe(
void)
3942 if (_subscriptionManager)
3944 _subscriptionManager->clear();
3947 _routes.unsubscribeAll();
3948 Lock<Mutex> l(_lock);
3949 threadLocalMessage.reset();
3950 threadLocalMessage.
setCommandEnum(Message::Command::Unsubscribe);
3953 _sendWithoutRetry(threadLocalMessage);
3955 deferredExecution(&s_noOpFn, NULL);
3959 const std::string& topic_,
3960 const std::string& filter_ =
"",
3961 const std::string& orderBy_ =
"",
3962 const std::string& bookmark_ =
"",
3963 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
3964 int topN_ = AMPS_DEFAULT_TOP_N,
3965 const std::string& options_ =
"",
3966 long timeout_ = AMPS_DEFAULT_COMMAND_TIMEOUT)
3968 Lock<Mutex> l(_lock);
3969 threadLocalMessage.reset();
3973 std::string commandId = threadLocalMessage.
getCommandId();
3975 unsigned ackTypes = Message::AckType::Processed | Message::AckType::Completed;
3977 threadLocalMessage.
setTopic(topic_);
3978 if (filter_.length())
3982 if (orderBy_.length())
3986 if (bookmark_.length())
3990 threadLocalMessage.
setBatchSize(AMPS::asString(batchSize_));
3991 if (topN_ != AMPS_DEFAULT_TOP_N)
3995 if (options_.length())
4000 _routes.addRoute(threadLocalMessage.
getQueryID(), messageHandler_,
4001 Message::AckType::None, ackTypes, threadLocalMessage.
getCommandEnum());
4005 syncAckProcessing(timeout_, threadLocalMessage);
4009 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId));
4017 const std::string& topic_,
4019 const std::string& filter_ =
"",
4020 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
4021 int topN_ = AMPS_DEFAULT_TOP_N)
4024 return sow(messageHandler_,
4035 std::string sowAndSubscribe(
const MessageHandler& messageHandler_,
4036 const std::string& topic_,
4037 const std::string& filter_ =
"",
4038 const std::string& orderBy_ =
"",
4039 const std::string& bookmark_ =
"",
4040 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
4041 int topN_ = AMPS_DEFAULT_TOP_N,
4042 const std::string& options_ =
"",
4043 long timeout_ = AMPS_DEFAULT_COMMAND_TIMEOUT,
4044 bool isHASubscribe_ =
true)
4046 isHASubscribe_ &= (bool)_subscriptionManager;
4047 unsigned ackTypes = Message::AckType::Processed;
4048 Lock<Mutex> l(_lock);
4049 threadLocalMessage.reset();
4050 threadLocalMessage.
setCommandEnum(Message::Command::SOWAndSubscribe);
4053 std::string subId = cid;
4055 if (filter_.length())
4059 if (orderBy_.length())
4063 if (bookmark_.length())
4067 if (_bookmarkStore.isValid())
4069 ackTypes |= Message::AckType::Persisted;
4077 _bookmarkStore.
log(threadLocalMessage);
4078 if (!BookmarkRange::isRange(bookmark))
4080 _bookmarkStore.
discard(threadLocalMessage);
4091 threadLocalMessage.
setBatchSize(AMPS::asString(batchSize_));
4092 if (topN_ != AMPS_DEFAULT_TOP_N)
4096 if (options_.length())
4101 AMPS_ATOMIC_BASE_TYPE generation = (AMPS_ATOMIC_BASE_TYPE)0;
4105 Unlock<Mutex> u(_lock);
4107 _subscriptionManager->subscribe(messageHandler_, threadLocalMessage.
deepCopy(),
4108 Message::AckType::None);
4110 if (generation <= (AMPS_ATOMIC_BASE_TYPE)_subscriptionManagerGenerationCount)
4115 _routes.addRoute(cid, messageHandler_,
4116 Message::AckType::None, ackTypes, threadLocalMessage.
getCommandEnum());
4118 if (!options_.empty())
4124 syncAckProcessing(timeout_, threadLocalMessage, 0, generation);
4126 catch (
const DisconnectedException&)
4128 if (!isHASubscribe_)
4130 _routes.removeRoute(subId);
4134 catch (
const TimedOutException&)
4136 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subId));
4144 Unlock<Mutex> unlock(_lock);
4145 _subscriptionManager->unsubscribe(cid);
4147 _routes.removeRoute(subId);
4153 std::string sowAndSubscribe(
const MessageHandler& messageHandler_,
4154 const std::string& topic_,
4156 const std::string& filter_ =
"",
4157 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
4158 bool oofEnabled_ =
false,
4159 int topN_ = AMPS_DEFAULT_TOP_N,
4160 bool isHASubscribe_ =
true)
4163 return sowAndSubscribe(messageHandler_,
4170 (oofEnabled_ ?
"oof" :
""),
4175 std::string sowAndDeltaSubscribe(
const MessageHandler& messageHandler_,
4176 const std::string& topic_,
4177 const std::string& filter_ =
"",
4178 const std::string& orderBy_ =
"",
4179 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
4180 int topN_ = AMPS_DEFAULT_TOP_N,
4181 const std::string& options_ =
"",
4182 long timeout_ = AMPS_DEFAULT_COMMAND_TIMEOUT,
4183 bool isHASubscribe_ =
true)
4185 isHASubscribe_ &= (bool)_subscriptionManager;
4186 Lock<Mutex> l(_lock);
4187 threadLocalMessage.reset();
4188 threadLocalMessage.
setCommandEnum(Message::Command::SOWAndDeltaSubscribe);
4193 threadLocalMessage.
setTopic(topic_);
4194 if (filter_.length())
4198 if (orderBy_.length())
4202 threadLocalMessage.
setBatchSize(AMPS::asString(batchSize_));
4203 if (topN_ != AMPS_DEFAULT_TOP_N)
4207 if (options_.length())
4211 AMPS_ATOMIC_BASE_TYPE generation = (AMPS_ATOMIC_BASE_TYPE)0;
4215 Unlock<Mutex> u(_lock);
4217 _subscriptionManager->subscribe(messageHandler_, threadLocalMessage.
deepCopy(),
4218 Message::AckType::None);
4220 if (generation <= (AMPS_ATOMIC_BASE_TYPE)_subscriptionManagerGenerationCount)
4225 _routes.addRoute(threadLocalMessage.
getQueryID(), messageHandler_,
4226 Message::AckType::None, Message::AckType::Processed, threadLocalMessage.
getCommandEnum());
4228 if (!options_.empty())
4234 syncAckProcessing(timeout_, threadLocalMessage, 0, generation);
4236 catch (
const DisconnectedException&)
4238 if (!isHASubscribe_)
4240 _routes.removeRoute(subId);
4244 catch (
const TimedOutException&)
4246 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subId));
4254 Unlock<Mutex> unlock(_lock);
4255 _subscriptionManager->unsubscribe(
Field(subId));
4257 _routes.removeRoute(subId);
4263 std::string sowAndDeltaSubscribe(
const MessageHandler& messageHandler_,
4264 const std::string& topic_,
4266 const std::string& filter_ =
"",
4267 int batchSize_ = AMPS_DEFAULT_BATCH_SIZE,
4268 bool oofEnabled_ =
false,
4269 bool sendEmpties_ =
false,
4270 int topN_ = AMPS_DEFAULT_TOP_N,
4271 bool isHASubscribe_ =
true)
4279 if (sendEmpties_ ==
false)
4283 return sowAndDeltaSubscribe(messageHandler_,
4295 const std::string& topic_,
4296 const std::string& filter_,
4302 unsigned ackType = Message::AckType::Processed |
4303 Message::AckType::Stats |
4304 Message::AckType::Persisted;
4305 threadLocalMessage.reset();
4306 if (commandId_.
empty())
4317 .assignQueryID(commandId_.
data(), commandId_.
len())
4318 .setAckTypeEnum(ackType)
4320 .assignFilter(filter_.c_str(), filter_.length());
4321 amps_uint64_t haSequenceNumber = _publishStore.
store(threadLocalMessage);
4322 char buf[AMPS_NUMBER_BUFFER_LEN];
4323 size_t pos = convertToCharArray(buf, haSequenceNumber);
4324 threadLocalMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
4328 Lock<Mutex> l(_lock);
4329 _routes.addRoute(commandId_, messageHandler_,
4330 Message::AckType::Stats,
4331 Message::AckType::Processed | Message::AckType::Persisted,
4333 syncAckProcessing(timeout_, threadLocalMessage,
4336 catch (
const DisconnectedException&)
4342 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4346 return (std::string)commandId_;
4350 Lock<Mutex> l(_lock);
4351 threadLocalMessage.reset();
4352 if (commandId_.
empty())
4363 .assignQueryID(commandId_.
data(), commandId_.
len())
4364 .setAckTypeEnum(Message::AckType::Processed |
4365 Message::AckType::Stats)
4367 .assignFilter(filter_.c_str(), filter_.length());
4368 _routes.addRoute(commandId_, messageHandler_,
4369 Message::AckType::Stats,
4370 Message::AckType::Processed,
4374 syncAckProcessing(timeout_, threadLocalMessage);
4378 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4381 return (std::string)commandId_;
4385 std::string sowDeleteByData(
const MessageHandler& messageHandler_,
4386 const std::string& topic_,
4387 const std::string& data_,
4393 unsigned ackType = Message::AckType::Processed |
4394 Message::AckType::Stats |
4395 Message::AckType::Persisted;
4396 threadLocalMessage.reset();
4397 if (commandId_.
empty())
4408 .assignQueryID(commandId_.
data(), commandId_.
len())
4409 .setAckTypeEnum(ackType)
4411 .assignData(data_.c_str(), data_.length());
4412 amps_uint64_t haSequenceNumber = _publishStore.
store(threadLocalMessage);
4413 char buf[AMPS_NUMBER_BUFFER_LEN];
4414 size_t pos = convertToCharArray(buf, haSequenceNumber);
4415 threadLocalMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
4419 Lock<Mutex> l(_lock);
4420 _routes.addRoute(commandId_, messageHandler_,
4421 Message::AckType::Stats,
4422 Message::AckType::Processed | Message::AckType::Persisted,
4424 syncAckProcessing(timeout_, threadLocalMessage,
4427 catch (
const DisconnectedException&)
4433 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4437 return (std::string)commandId_;
4441 Lock<Mutex> l(_lock);
4442 threadLocalMessage.reset();
4443 if (commandId_.
empty())
4454 .assignQueryID(commandId_.
data(), commandId_.
len())
4455 .setAckTypeEnum(Message::AckType::Processed |
4456 Message::AckType::Stats)
4458 .assignData(data_.c_str(), data_.length());
4459 _routes.addRoute(commandId_, messageHandler_,
4460 Message::AckType::Stats,
4461 Message::AckType::Processed,
4465 syncAckProcessing(timeout_, threadLocalMessage);
4469 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4472 return (std::string)commandId_;
4476 std::string sowDeleteByKeys(
const MessageHandler& messageHandler_,
4477 const std::string& topic_,
4478 const std::string& keys_,
4484 unsigned ackType = Message::AckType::Processed |
4485 Message::AckType::Stats |
4486 Message::AckType::Persisted;
4487 threadLocalMessage.reset();
4488 if (commandId_.
empty())
4499 .assignQueryID(commandId_.
data(), commandId_.
len())
4500 .setAckTypeEnum(ackType)
4502 .assignSowKeys(keys_.c_str(), keys_.length());
4503 amps_uint64_t haSequenceNumber = _publishStore.
store(threadLocalMessage);
4504 char buf[AMPS_NUMBER_BUFFER_LEN];
4505 size_t pos = convertToCharArray(buf, haSequenceNumber);
4506 threadLocalMessage.
assignSequence(buf + pos, AMPS_NUMBER_BUFFER_LEN - pos);
4510 Lock<Mutex> l(_lock);
4511 _routes.addRoute(commandId_, messageHandler_,
4512 Message::AckType::Stats,
4513 Message::AckType::Processed | Message::AckType::Persisted,
4515 syncAckProcessing(timeout_, threadLocalMessage,
4518 catch (
const DisconnectedException&)
4524 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4528 return (std::string)commandId_;
4532 Lock<Mutex> l(_lock);
4533 threadLocalMessage.reset();
4534 if (commandId_.
empty())
4545 .assignQueryID(commandId_.
data(), commandId_.
len())
4546 .setAckTypeEnum(Message::AckType::Processed |
4547 Message::AckType::Stats)
4549 .assignSowKeys(keys_.c_str(), keys_.length());
4550 _routes.addRoute(commandId_, messageHandler_,
4551 Message::AckType::Stats,
4552 Message::AckType::Processed,
4556 syncAckProcessing(timeout_, threadLocalMessage);
4560 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(commandId_));
4563 return (std::string)commandId_;
4567 void startTimer(
void)
4569 if (_serverVersion >=
"5.3.2.0")
4571 throw CommandException(
"The start_timer command is deprecated.");
4573 Lock<Mutex> l(_lock);
4574 threadLocalMessage.reset();
4577 _send(threadLocalMessage);
4582 if (_serverVersion >=
"5.3.2.0")
4584 throw CommandException(
"The stop_timer command is deprecated.");
4586 return executeAsync(
Command(
"stop_timer").addAckType(
"completed"), messageHandler_);
4601 void setExceptionListener(
const std::shared_ptr<const ExceptionListener>& pListener_)
4603 _pExceptionListener = pListener_;
4604 _exceptionListener = _pExceptionListener.get();
4609 _exceptionListener = &listener_;
4614 return *_exceptionListener;
4617 void setHeartbeat(
unsigned heartbeatInterval_,
unsigned readTimeout_)
4619 if (readTimeout_ < heartbeatInterval_)
4621 throw UsageException(
"The socket read timeout must be >= the heartbeat interval.");
4623 Lock<Mutex> l(_lock);
4624 if (_heartbeatInterval != heartbeatInterval_ ||
4625 _readTimeout != readTimeout_)
4627 _heartbeatInterval = heartbeatInterval_;
4628 _readTimeout = readTimeout_;
4633 void _sendHeartbeat(
void)
4635 if (_connected && _heartbeatInterval != 0)
4637 std::ostringstream options;
4638 options <<
"start," << _heartbeatInterval;
4641 _heartbeatTimer.setTimeout(_heartbeatInterval * 1000.0);
4642 _heartbeatTimer.start();
4645 _sendWithoutRetry(_beatMessage);
4646 broadcastConnectionStateChanged(ConnectionStateListener::HeartbeatInitiated);
4648 catch (ConnectionException& ex_)
4652 AMPS_UNHANDLED_EXCEPTION(ex_);
4657 if (_readTimeout && _connected)
4664 if (!_queueAckTimeout)
4667 (
int)(_heartbeatInterval * 1000));
4678 Lock<Mutex> lock(_lock);
4679 _connectionStateListeners.insert(listener_);
4684 Lock<Mutex> lock(_lock);
4685 _connectionStateListeners.erase(listener_);
4688 void clearConnectionStateListeners()
4690 Lock<Mutex> lock(_lock);
4691 _connectionStateListeners.clear();
4696 unsigned systemAddedAcks_, Message::Command::Type commandType_)
4698 Message message = command_.getMessage();
4703 bool added = qid.
len() || subid.
len() || cid_.
len();
4704 bool cidIsQid = cid_ == qid;
4705 bool cidUnique = !cidIsQid && cid_.
len() > 0 && cid_ != subid;
4707 if (subid.
len() > 0)
4711 addedCount += _routes.addRoute(subid, handler_, requestedAcks_,
4712 systemAddedAcks_, commandType_);
4714 && (commandType == Message::Command::Subscribe
4715 || commandType == Message::Command::DeltaSubscribe))
4722 if (qid.
len() > 0 && qid != subid
4723 && (commandType == Message::Command::SOW
4724 || commandType == Message::Command::SOWDelete
4725 || commandType == Message::Command::SOWAndSubscribe
4726 || commandType == Message::Command::SOWAndDeltaSubscribe))
4728 while (_routes.hasRoute(qid))
4737 if (addedCount == 0)
4739 _routes.addRoute(qid, handler_, requestedAcks_,
4740 systemAddedAcks_, commandType_);
4746 Unlock<Mutex> u(_lock);
4747 data = amps_invoke_copy_route_function(handler_.userData());
4751 _routes.addRoute(qid, handler_, requestedAcks_,
4752 systemAddedAcks_, commandType_);
4756 _routes.addRoute(qid,
4760 systemAddedAcks_, commandType_);
4765 if (cidUnique && requestedAcks_ & ~Message::AckType::Persisted)
4767 while (_routes.hasRoute(cid_))
4771 if (addedCount == 0)
4773 _routes.addRoute(cid_, handler_, requestedAcks_,
4774 systemAddedAcks_, commandType_);
4780 Unlock<Mutex> u(_lock);
4781 data = amps_invoke_copy_route_function(handler_.userData());
4785 _routes.addRoute(cid_, handler_, requestedAcks_,
4786 systemAddedAcks_, commandType_);
4790 _routes.addRoute(cid_,
4794 systemAddedAcks_, commandType_);
4798 else if ((commandType == Message::Command::Publish ||
4799 commandType == Message::Command::DeltaPublish)
4800 && requestedAcks_ & ~
Message::AckType::Persisted)
4803 _routes.addRoute(cid_, handler_, requestedAcks_,
4804 systemAddedAcks_, commandType_);
4809 throw UsageException(
"To use a messagehandler, you must also supply a command or subscription ID.");
4814 bool isHASubscribe_ =
true)
4816 isHASubscribe_ &= (bool)_subscriptionManager;
4817 Message& message = command_.getMessage();
4818 unsigned systemAddedAcks = (handler_.isValid() || command_.hasProcessedAck()) ?
4819 Message::AckType::Processed : Message::AckType::None;
4821 bool isPublishStore = _publishStore.
isValid() && command_.needsSequenceNumber();
4823 if (commandType == Message::Command::StopTimer)
4825 systemAddedAcks |= Message::AckType::Completed;
4827 else if (commandType == Message::Command::Unsubscribe)
4833 _routes.unsubscribeAll();
4834 if (_subscriptionManager)
4836 Unlock<Mutex> unlock(_lock);
4837 _subscriptionManager->clear();
4842 _routes.removeRoute(subId);
4844 if (_subscriptionManager)
4847 Unlock<Mutex> unlock(_lock);
4848 _subscriptionManager->unsubscribe(subId);
4852 deferredExecution(&s_noOpFn, NULL);
4855 if (handler_.isValid() && cid.
empty())
4861 if (command_.isSubscribe())
4864 if (_bookmarkStore.isValid())
4866 systemAddedAcks |= Message::AckType::Persisted;
4874 _bookmarkStore.
log(message);
4875 if (!BookmarkRange::isRange(bookmark))
4877 _bookmarkStore.
discard(message);
4891 systemAddedAcks |= Message::AckType::Persisted;
4893 bool isSubscribe = command_.isSubscribe();
4894 if (handler_.isValid() && !isSubscribe)
4896 _registerHandler(command_, cid, handler_,
4897 requestedAcks, systemAddedAcks, commandType);
4901 bool useSyncSend = cid.
len() > 0 && command_.hasProcessedAck();
4902 amps_uint64_t haSequenceNumber = (amps_uint64_t)0;
4905 Unlock<Mutex> u(_lock);
4906 haSequenceNumber = _publishStore.
store(message);
4913 syncAckProcessing((
long)command_.getTimeout(), message,
4918 _sendSequenced(message, haSequenceNumber,
4919 commandType & (Message::Command::Publish
4920 | Message::Command::DeltaPublish));
4923 catch (
const DisconnectedException&)
4929 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
4938 AMPS_ATOMIC_BASE_TYPE generation = (AMPS_ATOMIC_BASE_TYPE)0;
4942 Unlock<Mutex> u(_lock);
4944 _subscriptionManager->subscribe(handler_,
4948 if (generation <= (AMPS_ATOMIC_BASE_TYPE)_subscriptionManagerGenerationCount)
4951 return std::string(subId.
data(), subId.
len());
4954 if (handler_.isValid())
4956 _registerHandler(command_, cid, handler_,
4957 requestedAcks, systemAddedAcks, commandType);
4962 syncAckProcessing((
long)command_.getTimeout(), message, 0, generation);
4964 catch (
const DisconnectedException&)
4966 if (!isHASubscribe_)
4968 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
4969 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(subId));
4970 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(message.
getQueryId()));
4975 catch (
const TimedOutException&)
4977 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(cid));
4978 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(subId));
4979 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(message.
getQueryId()));
4988 Unlock<Mutex> unlock(_lock);
4989 _subscriptionManager->unsubscribe(subId);
4995 _routes.removeRoute(cid);
4996 _routes.removeRoute(subId);
5000 if (subId.
len() > 0)
5003 return std::string(subId.
data(), subId.
len());
5009 bool useSyncSend = commandType & ~
Message::Command::NoDataCommands
5010 || (cid.
len() > 0 && command_.hasProcessedAck());
5016 syncAckProcessing((
long)(command_.getTimeout()), message);
5020 _sendSequenced(message, 0,
5021 commandType & (Message::Command::Publish
5022 | Message::Command::DeltaPublish));
5025 catch (
const TimedOutException&)
5027 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(cid));
5028 AMPS_CALL_EXCEPTION_WRAPPER(unsubscribeInternal(message.
getQueryId()));
5032 catch (
const DisconnectedException&)
5034 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
5035 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(message.
getQueryId()));
5041 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(cid));
5042 AMPS_CALL_EXCEPTION_WRAPPER(_routes.removeRoute(message.
getQueryId()));
5055 bool isHASubscribe_ =
true)
5057 Lock<Mutex> lock(_lock);
5058 return executeAsyncNoLock(command_, handler_, isHASubscribe_);
5062 void setAutoAck(
bool isAutoAckEnabled_)
5064 _isAutoAckEnabled = isAutoAckEnabled_;
5066 bool getAutoAck(
void)
const 5068 return _isAutoAckEnabled;
5070 void setAckBatchSize(
const unsigned batchSize_)
5072 _ackBatchSize = batchSize_;
5073 if (!_queueAckTimeout)
5075 _queueAckTimeout = AMPS_DEFAULT_QUEUE_ACK_TIMEOUT;
5079 unsigned getAckBatchSize(
void)
const 5081 return _ackBatchSize;
5083 int getAckTimeout(
void)
const 5085 return _queueAckTimeout;
5087 void setAckTimeout(
const int ackTimeout_)
5090 _queueAckTimeout = ackTimeout_;
5092 size_t _ack(QueueBookmarks& queueBookmarks_)
5094 if (queueBookmarks_._bookmarkCount)
5096 threadLocalMessage.reset();
5101 amps_uint64_t haSequenceNumber = 0;
5104 haSequenceNumber = _publishStore.
store(threadLocalMessage);
5107 queueBookmarks_._data.erase();
5108 queueBookmarks_._bookmarkCount = 0;
5110 _sendSequenced(threadLocalMessage, haSequenceNumber, 0);
5113 queueBookmarks_._data.erase();
5114 queueBookmarks_._bookmarkCount = 0;
5120 void ack(
const Field& topic_,
const Field& bookmark_,
const char* options_ = NULL)
5122 if (_isAutoAckEnabled)
5126 _ack(topic_, bookmark_, options_);
5128 void _ack(
const Field& topic_,
const Field& bookmark_,
const char* options_ = NULL)
5130 if (bookmark_.
len() == 0)
5134 Lock<Mutex> lock(_lock);
5135 if (_ackBatchSize < 2 || options_ != NULL)
5137 threadLocalMessage.reset();
5145 amps_uint64_t haSequenceNumber = 0;
5148 haSequenceNumber = _publishStore.
store(threadLocalMessage);
5152 _sendSequenced(threadLocalMessage, haSequenceNumber, 0);
5156 topic_hash hash = CRC<0>::crcNoSSE(topic_.
data(), topic_.
len());
5157 TopicHashMap::iterator it = _topicHashMap.find(hash);
5158 if (it == _topicHashMap.end())
5161 it = _topicHashMap.emplace(TopicHashMap::value_type(hash, QueueBookmarks(topic_))).first;
5163 QueueBookmarks& queueBookmarks = it->second;
5164 if (queueBookmarks._data.length())
5166 queueBookmarks._data.append(
",");
5170 queueBookmarks._oldestTime = amps_now();
5172 queueBookmarks._data.append(bookmark_);
5173 if (++queueBookmarks._bookmarkCount >= _ackBatchSize)
5175 _ack(queueBookmarks);
5178 void flushAcks(
void)
5180 size_t sendCount = 0;
5187 Lock<Mutex> lock(_lock);
5188 typedef TopicHashMap::iterator iterator;
5189 for (iterator it = _topicHashMap.begin(), end = _topicHashMap.end(); it != end; ++it)
5191 QueueBookmarks& queueBookmarks = it->second;
5192 sendCount += _ack(queueBookmarks);
5195 if (sendCount && _connected)
5197 publishFlush(0, Message::AckType::Processed);
5201 void checkQueueAcks(
void)
5203 if (!_topicHashMap.size())
5207 Lock<Mutex> lock(_lock);
5210 amps_uint64_t threshold = amps_now()
5211 - (amps_uint64_t)_queueAckTimeout;
5212 typedef TopicHashMap::iterator iterator;
5213 for (iterator it = _topicHashMap.begin(), end = _topicHashMap.end(); it != end; ++it)
5215 QueueBookmarks& queueBookmarks = it->second;
5216 if (queueBookmarks._bookmarkCount && queueBookmarks._oldestTime < threshold)
5218 _ack(queueBookmarks);
5222 catch (std::exception& ex)
5224 AMPS_UNHANDLED_EXCEPTION(ex);
5228 void deferredExecution(DeferredExecutionFunc func_,
void* userData_)
5230 Lock<Mutex> lock(_deferredExecutionLock);
5231 _deferredExecutionList.emplace_back(
5232 DeferredExecutionRequest(func_, userData_));
5235 inline void processDeferredExecutions(
void)
5237 if (_deferredExecutionList.size())
5239 Lock<Mutex> lock(_deferredExecutionLock);
5240 DeferredExecutionList::iterator it = _deferredExecutionList.begin();
5241 DeferredExecutionList::iterator end = _deferredExecutionList.end();
5242 for (; it != end; ++it)
5246 it->_func(it->_userData);
5253 _deferredExecutionList.clear();
5254 _routes.invalidateCache();
5255 _routeCache.invalidateCache();
5259 bool getRetryOnDisconnect(
void)
const 5261 return _isRetryOnDisconnect;
5264 void setRetryOnDisconnect(
bool isRetryOnDisconnect_)
5266 _isRetryOnDisconnect = isRetryOnDisconnect_;
5269 void setDefaultMaxDepth(
unsigned maxDepth_)
5271 _defaultMaxDepth = maxDepth_;
5274 unsigned getDefaultMaxDepth(
void)
const 5276 return _defaultMaxDepth;
5291 void setPublishBatching(amps_uint64_t batchSizeBytes_, amps_uint64_t batchTimeoutMillis_)
5374 RefHandle<MessageStreamImpl> _body;
5384 inline void advance(
void);
5391 : _pStream(pStream_)
5396 bool operator==(
const iterator& rhs)
const 5398 return _pStream == rhs._pStream;
5400 bool operator!=(
const iterator& rhs)
const 5402 return _pStream != rhs._pStream;
5404 void operator++(
void)
5420 return _body.isValid();
5427 if (!_body.isValid())
5429 throw UsageException(
"This MessageStream is not valid and cannot be iterated.");
5461 unsigned getMaxDepth(
void)
const;
5464 unsigned getDepth(
void)
const;
5469 inline void setSOWOnly(
const std::string& commandId_,
5470 const std::string& queryId_ =
"");
5471 inline void setSubscription(
const std::string& subId_,
5472 const std::string& commandId_ =
"",
5473 const std::string& queryId_ =
"");
5474 inline void setStatsOnly(
const std::string& commandId_,
5475 const std::string& queryId_ =
"");
5476 inline void setAcksOnly(
const std::string& commandId_,
unsigned acks_);
5482 friend class Client;
5483 friend class ClientImpl;
5509 BorrowRefHandle<ClientImpl> _body;
5511 static const int DEFAULT_COMMAND_TIMEOUT = AMPS_DEFAULT_COMMAND_TIMEOUT;
5512 static const int DEFAULT_BATCH_SIZE = AMPS_DEFAULT_BATCH_SIZE;
5513 static const int DEFAULT_TOP_N = AMPS_DEFAULT_TOP_N;
5524 : _body(new ClientImpl(clientName), true)
5527 Client(ClientImpl* existingClient)
5528 : _body(existingClient,
true)
5531 Client(ClientImpl* existingClient,
bool isRef)
5532 : _body(existingClient, isRef)
5535 Client(
const Client& rhs) : _body(rhs._body) {;}
5536 virtual ~Client(
void) {;}
5538 Client& operator=(
const Client& rhs)
5546 return _body.isValid();
5563 _body.get().setName(name);
5570 return _body.get().getName();
5578 return _body.get().getNameHash();
5586 return _body.get().getNameHashValue();
5594 return _body.get().getConnectionName();
5605 _body.get().setLogonCorrelationData(logonCorrelationData_);
5612 return _body.get().getLogonCorrelationData();
5620 _body.get().addHttpPreflightHeader(header_);
5629 _body.get().addHttpPreflightHeader(key_, value_);
5635 _body.get().clearHttpPreflightHeaders();
5644 _body.get().setHttpPreflightHeaders(headers_);
5657 return _body.get().getServerVersion();
5668 return _body.get().getServerVersionInfo();
5682 return AMPS::convertVersionToNumber(version_.c_str(), version_.length());
5697 return AMPS::convertVersionToNumber(data_, len_);
5704 return _body.get().getURI();
5728 _body.get().connect(uri);
5735 _body.get().disconnect();
5753 _body.get().send(message);
5766 unsigned requestedAcks_,
bool isSubscribe_)
5768 Message::Command::Type commandType = isSubscribe_ ? Message::Command::Subscribe : Message::Command::SOW;
5769 _body.get().addMessageHandler(commandId_, messageHandler_,
5770 requestedAcks_, commandType);
5783 unsigned requestedAcks_, Message::Command::Type commandType_)
5785 _body.get().addMessageHandler(commandId_, messageHandler_,
5786 requestedAcks_, commandType_);
5794 return _body.get().removeMessageHandler(commandId_);
5824 AMPS_ATOMIC_BASE_TYPE subscribeGeneration_ = 0)
5826 return _body.get().send(messageHandler_, message_, timeout_, subscribeGeneration_);
5842 #if defined(_WIN32) || __cplusplus >= 201402L 5843 [[deprecated(
"Use HAClient for automatic reconnection and a ConnectionStateListener to monitor connection state.")]]
5847 _body.get().setDisconnectHandler(disconnectHandler);
5856 #if defined(_WIN32) || __cplusplus >= 201402L 5857 [[deprecated(
"Use HAClient for automatic reconnection and a ConnectionStateListener to monitor connection state.")]]
5861 return _body.get().getDisconnectHandler();
5870 return _body.get().getConnectionInfo();
5883 _body.get().setBookmarkStore(bookmarkStore_);
5891 return _body.
get().getBookmarkStore();
5899 return _body.get().getSubscriptionManager();
5911 _body.get().setSubscriptionManager(subscriptionManager_);
5935 _body.get().setPublishStore(publishStore_);
5943 return _body.
get().getPublishStore();
5951 _body.get().setGlobalCommandTypeMessageHandler(ClientImpl::GlobalCommandTypeHandlers::DuplicateMessage,
5952 duplicateMessageHandler_);
5966 return _body.get().getDuplicateMessageHandler();
5980 _body.get().setFailedWriteHandler(handler_);
5988 return _body.get().getFailedWriteHandler();
6009 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_)
6011 return _body.get().publish(topic_.c_str(), topic_.length(),
6012 data_.c_str(), data_.length());
6034 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
6035 const char* data_,
size_t dataLength_)
6037 return _body.get().publish(topic_, topicLength_, data_, dataLength_);
6058 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_,
6059 unsigned long expiration_)
6061 return _body.get().publish(topic_.c_str(), topic_.length(),
6062 data_.c_str(), data_.length(), expiration_);
6085 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
6086 const char* data_,
size_t dataLength_,
6087 unsigned long expiration_)
6089 return _body.get().publish(topic_, topicLength_,
6090 data_, dataLength_, expiration_);
6111 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_,
6112 const std::string& correlationId_)
6114 return _body.get().publish(topic_.c_str(), topic_.length(),
6115 data_.c_str(), data_.length(),
6116 correlationId_.c_str(), correlationId_.length());
6140 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
6141 const char* data_,
size_t dataLength_,
6142 const char* correlationId_,
size_t correlationIdLength_)
6144 return _body.get().publish(topic_, topicLength_, data_, dataLength_,
6145 correlationId_, correlationIdLength_);
6167 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_,
6168 const std::string& correlationId_,
6169 unsigned long expiration_)
6171 return _body.get().publish(topic_.c_str(), topic_.length(),
6172 data_.c_str(), data_.length(),
6173 correlationId_.c_str(), correlationId_.length(),
6199 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
6200 const char* data_,
size_t dataLength_,
6201 const char* correlationId_,
size_t correlationIdLength_,
6202 unsigned long expiration_)
6204 return _body.get().publish(topic_, topicLength_, data_, dataLength_,
6205 correlationId_, correlationIdLength_,
6228 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_,
6229 const std::string& correlationId_,
6230 const std::string& sowKey_)
6232 return _body.get().publish(topic_.c_str(), topic_.length(),
6233 data_.c_str(), data_.length(),
6234 correlationId_.c_str(), correlationId_.length(),
6235 sowKey_.c_str(), sowKey_.length());
6261 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
6262 const char* data_,
size_t dataLength_,
6263 const char* correlationId_,
size_t correlationIdLength_,
6264 const char* sowKey_,
size_t sowKeyLength_)
6266 return _body.get().publish(topic_, topicLength_, data_, dataLength_,
6267 correlationId_, correlationIdLength_,
6268 sowKey_, sowKeyLength_);
6291 amps_uint64_t
publish(
const std::string& topic_,
const std::string& data_,
6292 const std::string& correlationId_,
6293 const std::string& sowKey_,
6294 unsigned long expiration_)
6296 return _body.get().publish(topic_.c_str(), topic_.length(),
6297 data_.c_str(), data_.length(),
6298 correlationId_.c_str(), correlationId_.length(),
6299 sowKey_.c_str(), sowKey_.length(),
6327 amps_uint64_t
publish(
const char* topic_,
size_t topicLength_,
6328 const char* data_,
size_t dataLength_,
6329 const char* correlationId_,
size_t correlationIdLength_,
6330 const char* sowKey_,
size_t sowKeyLength_,
6331 unsigned long expiration_)
6333 return _body.get().publish(topic_, topicLength_,
6335 correlationId_, correlationIdLength_,
6336 sowKey_, sowKeyLength_,
6358 return _body.get().publish(message_);
6379 amps_uint64_t
publishKeyed(
const std::string& topic_,
const std::string& data_,
6380 const std::string& sowKey_)
6382 return _body.get().publishKeyed(topic_.c_str(), topic_.length(),
6383 data_.c_str(), data_.length(),
6384 sowKey_.c_str(), sowKey_.length());
6409 const char* data_,
size_t dataLength_,
6410 const char* sowKey_,
size_t sowKeyLength_)
6412 return _body.get().publishKeyed(topic_, topicLength_, data_, dataLength_,
6413 sowKey_, sowKeyLength_);
6435 amps_uint64_t
publishKeyed(
const std::string& topic_,
const std::string& data_,
6436 const std::string& sowKey_,
6437 unsigned long expiration_)
6439 return _body.get().publishKeyed(topic_.c_str(), topic_.length(),
6440 data_.c_str(), data_.length(),
6441 sowKey_.c_str(), sowKey_.length(),
6468 const char* data_,
size_t dataLength_,
6469 const char* sowKey_,
size_t sowKeyLength_,
6470 unsigned long expiration_)
6472 return _body.get().publishKeyed(topic_, topicLength_,
6474 sowKey_, sowKeyLength_,
6516 void publishFlush(
long timeout_ = 0,
unsigned ackType_ = Message::AckType::Processed)
6518 _body.get().publishFlush(timeout_, ackType_);
6537 amps_uint64_t
deltaPublish(
const std::string& topic_,
const std::string& data_)
6539 return _body.get().deltaPublish(topic_.c_str(), topic_.length(),
6540 data_.c_str(), data_.length());
6561 const char* data_,
size_t dataLength_)
6563 return _body.get().deltaPublish(topic_, topicLength_,
6564 data_, dataLength_);
6583 amps_uint64_t
deltaPublish(
const std::string& topic_,
const std::string& data_,
6584 unsigned long expiration_)
6586 return _body.get().deltaPublish(topic_.c_str(), topic_.length(),
6587 data_.c_str(), data_.length(),
6610 const char* data_,
size_t dataLength_,
6611 unsigned long expiration_)
6613 return _body.get().deltaPublish(topic_, topicLength_,
6614 data_, dataLength_, expiration_);
6634 const char* options_ = NULL)
6636 return _body.get().logon(timeout_, authenticator_, options_);
6651 std::string
logon(
const char* options_,
int timeout_ = 0)
6670 std::string
logon(
const std::string& options_,
int timeout_ = 0)
6696 const std::string& topic_,
6698 const std::string& filter_ =
"",
6699 const std::string& options_ =
"",
6700 const std::string& subId_ =
"")
6702 return _body.get().subscribe(messageHandler_, topic_, timeout_,
6703 filter_,
"", options_, subId_);
6722 long timeout_ = 0,
const std::string& filter_ =
"",
6723 const std::string& options_ =
"",
6724 const std::string& subId_ =
"")
6727 if (_body.get().getDefaultMaxDepth())
6729 result.
maxDepth(_body.get().getDefaultMaxDepth());
6731 result.setSubscription(_body.get().subscribe(
6733 topic_, timeout_, filter_,
"",
6734 options_, subId_,
false));
6754 long timeout_ = 0,
const std::string& filter_ =
"",
6755 const std::string& options_ =
"",
6756 const std::string& subId_ =
"")
6759 if (_body.get().getDefaultMaxDepth())
6761 result.
maxDepth(_body.get().getDefaultMaxDepth());
6763 result.setSubscription(_body.get().subscribe(
6765 topic_, timeout_, filter_,
"",
6766 options_, subId_,
false));
6783 const std::string& topic_,
6785 const std::string& filter_ =
"",
6786 const std::string& options_ =
"",
6787 const std::string& subId_ =
"")
6789 return _body.get().deltaSubscribe(messageHandler_, topic_, timeout_,
6790 filter_,
"", options_, subId_);
6801 long timeout_,
const std::string& filter_ =
"",
6802 const std::string& options_ =
"",
6803 const std::string& subId_ =
"")
6806 if (_body.get().getDefaultMaxDepth())
6808 result.
maxDepth(_body.get().getDefaultMaxDepth());
6810 result.setSubscription(_body.get().deltaSubscribe(
6812 topic_, timeout_, filter_,
"",
6813 options_, subId_,
false));
6819 long timeout_,
const std::string& filter_ =
"",
6820 const std::string& options_ =
"",
6821 const std::string& subId_ =
"")
6824 if (_body.get().getDefaultMaxDepth())
6826 result.
maxDepth(_body.get().getDefaultMaxDepth());
6828 result.setSubscription(_body.get().deltaSubscribe(
6830 topic_, timeout_, filter_,
"",
6831 options_, subId_,
false));
6861 const std::string& topic_,
6863 const std::string& bookmark_,
6864 const std::string& filter_ =
"",
6865 const std::string& options_ =
"",
6866 const std::string& subId_ =
"")
6868 return _body.get().subscribe(messageHandler_, topic_, timeout_,
6869 filter_, bookmark_, options_, subId_);
6890 const std::string& bookmark_,
6891 const std::string& filter_ =
"",
6892 const std::string& options_ =
"",
6893 const std::string& subId_ =
"")
6896 if (_body.get().getDefaultMaxDepth())
6898 result.
maxDepth(_body.get().getDefaultMaxDepth());
6900 result.setSubscription(_body.get().subscribe(
6902 topic_, timeout_, filter_,
6903 bookmark_, options_,
6911 const std::string& bookmark_,
6912 const std::string& filter_ =
"",
6913 const std::string& options_ =
"",
6914 const std::string& subId_ =
"")
6917 if (_body.get().getDefaultMaxDepth())
6919 result.
maxDepth(_body.get().getDefaultMaxDepth());
6921 result.setSubscription(_body.get().subscribe(
6923 topic_, timeout_, filter_,
6924 bookmark_, options_,
6939 return _body.get().unsubscribe(commandId);
6951 return _body.get().unsubscribe();
6985 const std::string& topic_,
6986 const std::string& filter_ =
"",
6987 const std::string& orderBy_ =
"",
6988 const std::string& bookmark_ =
"",
6989 int batchSize_ = DEFAULT_BATCH_SIZE,
6990 int topN_ = DEFAULT_TOP_N,
6991 const std::string& options_ =
"",
6992 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
6994 return _body.get().sow(messageHandler_, topic_, filter_, orderBy_,
6995 bookmark_, batchSize_, topN_, options_,
7023 const std::string& filter_ =
"",
7024 const std::string& orderBy_ =
"",
7025 const std::string& bookmark_ =
"",
7026 int batchSize_ = DEFAULT_BATCH_SIZE,
7027 int topN_ = DEFAULT_TOP_N,
7028 const std::string& options_ =
"",
7029 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7032 if (_body.get().getDefaultMaxDepth())
7034 result.
maxDepth(_body.get().getDefaultMaxDepth());
7036 result.setSOWOnly(_body.get().sow(result.operator
MessageHandler(),
7037 topic_, filter_, orderBy_, bookmark_,
7038 batchSize_, topN_, options_, timeout_));
7044 const std::string& filter_ =
"",
7045 const std::string& orderBy_ =
"",
7046 const std::string& bookmark_ =
"",
7047 int batchSize_ = DEFAULT_BATCH_SIZE,
7048 int topN_ = DEFAULT_TOP_N,
7049 const std::string& options_ =
"",
7050 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7053 if (_body.get().getDefaultMaxDepth())
7055 result.
maxDepth(_body.get().getDefaultMaxDepth());
7057 result.setSOWOnly(_body.get().sow(result.operator
MessageHandler(),
7058 topic_, filter_, orderBy_, bookmark_,
7059 batchSize_, topN_, options_, timeout_));
7085 const std::string& topic_,
7087 const std::string& filter_ =
"",
7088 int batchSize_ = DEFAULT_BATCH_SIZE,
7089 int topN_ = DEFAULT_TOP_N)
7091 return _body.get().sow(messageHandler_, topic_, timeout_, filter_,
7117 const std::string& topic_,
7119 const std::string& filter_ =
"",
7120 int batchSize_ = DEFAULT_BATCH_SIZE,
7121 bool oofEnabled_ =
false,
7122 int topN_ = DEFAULT_TOP_N)
7124 return _body.get().sowAndSubscribe(messageHandler_, topic_, timeout_,
7125 filter_, batchSize_, oofEnabled_,
7150 const std::string& filter_ =
"",
7151 int batchSize_ = DEFAULT_BATCH_SIZE,
7152 bool oofEnabled_ =
false,
7153 int topN_ = DEFAULT_TOP_N)
7156 if (_body.get().getDefaultMaxDepth())
7158 result.
maxDepth(_body.get().getDefaultMaxDepth());
7160 result.setSubscription(_body.get().sowAndSubscribe(
7162 topic_, timeout_, filter_,
7163 batchSize_, oofEnabled_,
7188 const std::string& filter_ =
"",
7189 int batchSize_ = DEFAULT_BATCH_SIZE,
7190 bool oofEnabled_ =
false,
7191 int topN_ = DEFAULT_TOP_N)
7194 if (_body.get().getDefaultMaxDepth())
7196 result.
maxDepth(_body.get().getDefaultMaxDepth());
7198 result.setSubscription(_body.get().sowAndSubscribe(
7200 topic_, timeout_, filter_,
7201 batchSize_, oofEnabled_,
7235 const std::string& topic_,
7236 const std::string& filter_ =
"",
7237 const std::string& orderBy_ =
"",
7238 const std::string& bookmark_ =
"",
7239 int batchSize_ = DEFAULT_BATCH_SIZE,
7240 int topN_ = DEFAULT_TOP_N,
7241 const std::string& options_ =
"",
7242 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7244 return _body.get().sowAndSubscribe(messageHandler_, topic_, filter_,
7245 orderBy_, bookmark_, batchSize_,
7246 topN_, options_, timeout_);
7274 const std::string& filter_ =
"",
7275 const std::string& orderBy_ =
"",
7276 const std::string& bookmark_ =
"",
7277 int batchSize_ = DEFAULT_BATCH_SIZE,
7278 int topN_ = DEFAULT_TOP_N,
7279 const std::string& options_ =
"",
7280 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7283 if (_body.get().getDefaultMaxDepth())
7285 result.
maxDepth(_body.get().getDefaultMaxDepth());
7287 result.setSubscription(_body.get().sowAndSubscribe(
7289 topic_, filter_, orderBy_,
7290 bookmark_, batchSize_, topN_,
7291 options_, timeout_,
false));
7297 const std::string& filter_ =
"",
7298 const std::string& orderBy_ =
"",
7299 const std::string& bookmark_ =
"",
7300 int batchSize_ = DEFAULT_BATCH_SIZE,
7301 int topN_ = DEFAULT_TOP_N,
7302 const std::string& options_ =
"",
7303 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7306 if (_body.get().getDefaultMaxDepth())
7308 result.
maxDepth(_body.get().getDefaultMaxDepth());
7310 result.setSubscription(_body.get().sowAndSubscribe(
7312 topic_, filter_, orderBy_,
7313 bookmark_, batchSize_, topN_,
7314 options_, timeout_,
false));
7343 const std::string& topic_,
7344 const std::string& filter_ =
"",
7345 const std::string& orderBy_ =
"",
7346 int batchSize_ = DEFAULT_BATCH_SIZE,
7347 int topN_ = DEFAULT_TOP_N,
7348 const std::string& options_ =
"",
7349 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7351 return _body.get().sowAndDeltaSubscribe(messageHandler_, topic_,
7352 filter_, orderBy_, batchSize_,
7353 topN_, options_, timeout_);
7376 const std::string& filter_ =
"",
7377 const std::string& orderBy_ =
"",
7378 int batchSize_ = DEFAULT_BATCH_SIZE,
7379 int topN_ = DEFAULT_TOP_N,
7380 const std::string& options_ =
"",
7381 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7384 if (_body.get().getDefaultMaxDepth())
7386 result.
maxDepth(_body.get().getDefaultMaxDepth());
7388 result.setSubscription(_body.get().sowAndDeltaSubscribe(
7390 topic_, filter_, orderBy_,
7391 batchSize_, topN_, options_,
7398 const std::string& filter_ =
"",
7399 const std::string& orderBy_ =
"",
7400 int batchSize_ = DEFAULT_BATCH_SIZE,
7401 int topN_ = DEFAULT_TOP_N,
7402 const std::string& options_ =
"",
7403 long timeout_ = DEFAULT_COMMAND_TIMEOUT)
7406 if (_body.get().getDefaultMaxDepth())
7408 result.
maxDepth(_body.get().getDefaultMaxDepth());
7410 result.setSubscription(_body.get().sowAndDeltaSubscribe(
7412 topic_, filter_, orderBy_,
7413 batchSize_, topN_, options_,
7443 const std::string& topic_,
7445 const std::string& filter_ =
"",
7446 int batchSize_ = DEFAULT_BATCH_SIZE,
7447 bool oofEnabled_ =
false,
7448 bool sendEmpties_ =
false,
7449 int topN_ = DEFAULT_TOP_N)
7451 return _body.get().sowAndDeltaSubscribe(messageHandler_, topic_,
7452 timeout_, filter_, batchSize_,
7453 oofEnabled_, sendEmpties_,
7480 const std::string& filter_ =
"",
7481 int batchSize_ = DEFAULT_BATCH_SIZE,
7482 bool oofEnabled_ =
false,
7483 bool sendEmpties_ =
false,
7484 int topN_ = DEFAULT_TOP_N)
7487 if (_body.get().getDefaultMaxDepth())
7489 result.
maxDepth(_body.get().getDefaultMaxDepth());
7491 result.setSubscription(_body.get().sowAndDeltaSubscribe(
7493 topic_, timeout_, filter_,
7494 batchSize_, oofEnabled_,
7495 sendEmpties_, topN_,
false));
7521 const std::string& filter_ =
"",
7522 int batchSize_ = DEFAULT_BATCH_SIZE,
7523 bool oofEnabled_ =
false,
7524 bool sendEmpties_ =
false,
7525 int topN_ = DEFAULT_TOP_N)
7528 if (_body.get().getDefaultMaxDepth())
7530 result.
maxDepth(_body.get().getDefaultMaxDepth());
7532 result.setSubscription(_body.get().sowAndDeltaSubscribe(
7534 topic_, timeout_, filter_,
7535 batchSize_, oofEnabled_,
7536 sendEmpties_, topN_,
false));
7559 const std::string& topic,
7560 const std::string& filter,
7563 return _body.get().sowDelete(messageHandler, topic, filter, timeout);
7585 stream.
timeout((
unsigned int)timeout_);
7592 stream.setStatsOnly(cid);
7593 _body.get().sowDelete(stream.operator
MessageHandler(), topic_, filter_, timeout_, cid);
7594 return *(stream.
begin());
7596 catch (
const DisconnectedException&)
7598 removeMessageHandler(cid);
7601 catch (
const TimedOutException&)
7603 removeMessageHandler(cid);
7614 _body.get().startTimer();
7625 return _body.get().stopTimer(messageHandler);
7650 const std::string& topic_,
7651 const std::string& keys_,
7654 return _body.get().sowDeleteByKeys(messageHandler_, topic_, keys_, timeout_);
7680 stream.
timeout((
unsigned int)timeout_);
7687 stream.setStatsOnly(cid);
7688 _body.get().sowDeleteByKeys(stream.operator
MessageHandler(), topic_, keys_, timeout_, cid);
7689 return *(stream.
begin());
7691 catch (
const DisconnectedException&)
7693 removeMessageHandler(cid);
7696 catch (
const TimedOutException&)
7698 removeMessageHandler(cid);
7718 const std::string& topic_,
const std::string& data_,
7721 return _body.get().sowDeleteByData(messageHandler_, topic_, data_, timeout_);
7742 stream.
timeout((
unsigned int)timeout_);
7749 stream.setStatsOnly(cid);
7750 _body.get().sowDeleteByData(stream.operator
MessageHandler(), topic_, data_, timeout_, cid);
7751 return *(stream.
begin());
7753 catch (
const DisconnectedException&)
7755 removeMessageHandler(cid);
7758 catch (
const TimedOutException&)
7760 removeMessageHandler(cid);
7770 return _body.get().getHandle();
7783 _body.get().setExceptionListener(pListener_);
7794 #if defined(_WIN32) || __cplusplus >= 201402L 7795 [[deprecated(
"Use setExceptionListener(std::shared_ptr<const ExceptionListener>&)")]]
7799 _body.get().setExceptionListener(listener_);
7806 return _body.get().getExceptionListener();
7832 _body.get().setHeartbeat(heartbeatTime_, readTimeout_);
7856 _body.get().setHeartbeat(heartbeatTime_, 2 * heartbeatTime_);
7860 #if defined(_WIN32) || __cplusplus >= 201402L 7861 [[deprecated(
"Use setLastChanceMessageHandler.")]]
7865 setLastChanceMessageHandler(messageHandler);
7872 _body.get().setGlobalCommandTypeMessageHandler(ClientImpl::GlobalCommandTypeHandlers::LastChance,
7898 _body.get().setGlobalCommandTypeMessageHandler(command_, handler_);
7923 _body.get().setGlobalCommandTypeMessageHandler(command_, handler_);
8006 _body.get().addConnectionStateListener(listener);
8014 _body.get().removeConnectionStateListener(listener);
8021 _body.get().clearConnectionStateListeners();
8051 return _body.get().executeAsync(command_, handler_);
8089 if (command_.isSubscribe())
8091 Message& message = command_.getMessage();
8094 if (useExistingHandler)
8097 if (_body.get()._routes.getRoute(subId, existingHandler))
8100 _body.get().executeAsync(command_, existingHandler,
false);
8105 id = _body.get().executeAsync(command_, handler_,
false);
8107 catch (
const DisconnectedException&)
8109 removeMessageHandler(command_.getMessage().
getCommandId());
8110 if (command_.isSubscribe())
8114 if (command_.isSow())
8116 removeMessageHandler(command_.getMessage().
getQueryID());
8147 _body.get().ack(topic_, bookmark_, options_);
8169 void ack(
const std::string& topic_,
const std::string& bookmark_,
8170 const char* options_ = NULL)
8172 _body.get().ack(
Field(topic_.data(), topic_.length()),
Field(bookmark_.data(), bookmark_.length()), options_);
8180 void ackDeferredAutoAck(
Field& topic_,
Field& bookmark_,
const char* options_ = NULL)
8182 _body.get()._ack(topic_, bookmark_, options_);
8195 _body.get().flushAcks();
8204 return _body.get().getAutoAck();
8214 _body.get().setAutoAck(isAutoAckEnabled_);
8222 return _body.get().getAckBatchSize();
8232 _body.get().setAckBatchSize(ackBatchSize_);
8243 return _body.get().getAckTimeout();
8255 if (!ackTimeout_ && _body.get().getAckBatchSize() > 1)
8257 throw UsageException(
"Ack timeout must be > 0 when ack batch size > 1");
8259 _body.get().setAckTimeout(ackTimeout_);
8273 _body.get().setRetryOnDisconnect(isRetryOnDisconnect_);
8282 return _body.get().getRetryOnDisconnect();
8291 _body.get().setDefaultMaxDepth(maxDepth_);
8300 return _body.get().getDefaultMaxDepth();
8312 return _body.get().setTransportFilterFunction(filter_, userData_);
8326 return _body.get().setThreadCreatedCallback(callback_, userData_);
8337 return _body.get().setPublishBatching(batchSize_, batchTimeoutMillis_);
8345 void deferredExecution(DeferredExecutionFunc func_,
void* userData_)
8347 _body.get().deferredExecution(func_, userData_);
8357 AMPS_CALL_EXCEPTION_WRAPPER(_globalCommandTypeHandlers[GlobalCommandTypeHandlers::LastChance].invoke(message));
8363 unsigned deliveries = 0;
8375 const char* data = NULL;
8377 const char* status = NULL;
8378 size_t statusLen = 0;
8380 const size_t NotEntitled = 12, Duplicate = 9, Failure = 7;
8383 if (len == NotEntitled || len == Duplicate ||
8384 (statusLen == Failure && status[0] ==
'f'))
8386 if (_failedWriteHandler)
8388 if (_publishStore.isValid())
8390 amps_uint64_t sequence =
8392 FailedWriteStoreReplayer replayer(
this, data, len);
8393 AMPS_CALL_EXCEPTION_WRAPPER(_publishStore.replaySingle(
8394 replayer, sequence));
8400 AMPS_CALL_EXCEPTION_WRAPPER(
8401 _failedWriteHandler->failedWrite(emptyMessage,
8407 if (_publishStore.isValid())
8416 AMPS_CALL_EXCEPTION_WRAPPER(_publishStore.discardUpTo(seq));
8420 if (!deliveries && _bookmarkStore.isValid())
8427 const char* bookmarkData = NULL;
8428 size_t bookmarkLen = 0;
8434 if (bookmarkLen > 0 && _routes.hasRoute(subId))
8437 _bookmarkStore.persisted(subId,
Message::Field(bookmarkData, bookmarkLen));
8442 catch (std::exception& ex)
8444 AMPS_UNHANDLED_EXCEPTION(ex);
8450 ClientImpl::processedAck(
Message& message)
8452 unsigned deliveries = 0;
8454 const char* data = NULL;
8458 Lock<Mutex> l(_lock);
8461 Lock<Mutex> guard(_ackMapLock);
8462 AckMap::iterator i = _ackMap.find(std::string(data, len));
8463 if (i != _ackMap.end())
8473 ack.setStatus(data, len);
8475 ack.setReason(data, len);
8477 ack.setUsername(data, len);
8479 ack.setPassword(data, len);
8481 ack.setServerVersion(data, len);
8483 ack.setOptions(data, len);
8493 ClientImpl::checkAndSendHeartbeat(
bool force)
8495 if (force || _heartbeatTimer.check())
8497 _heartbeatTimer.start();
8500 sendWithoutRetry(_beatMessage);
8509 inline ConnectionInfo ClientImpl::getConnectionInfo()
const 8511 ConnectionInfo info;
8512 std::ostringstream writer;
8514 info[
"client.uri"] = _lastUri;
8515 info[
"client.name"] = _name;
8516 info[
"client.username"] = _username;
8517 if (_publishStore.isValid())
8519 writer << _publishStore.unpersistedCount();
8520 info[
"publishStore.unpersistedCount"] = writer.str();
8528 inline std::string ClientImpl::logon(
long timeout_,
Authenticator& authenticator_,
8529 const char* options_)
8531 Lock<Mutex> l(_lock);
8532 std::string cmdId = _logon(timeout_, authenticator_, options_);
8534 if (_subscriptionManager)
8537 Client wrapper(
this,
false);
8540 Unlock<Mutex> unlock(_lock);
8541 _subscriptionManager->resubscribe(wrapper);
8543 broadcastConnectionStateChanged(ConnectionStateListener::Resubscribed);
8549 ClientImpl::ClientImplMessageHandler(
amps_handle messageHandle_,
void* userData_)
8551 const unsigned SOWMask = Message::Command::SOW | Message::Command::GroupBegin | Message::Command::GroupEnd;
8552 const unsigned PublishMask = Message::Command::OOF | Message::Command::Publish | Message::Command::DeltaPublish;
8553 ClientImpl* me = (ClientImpl*) userData_;
8554 AMPS_CALL_EXCEPTION_WRAPPER_2(me, me->processDeferredExecutions());
8555 if (!messageHandle_)
8557 if (me->_queueAckTimeout)
8559 me->checkQueueAcks();
8561 me->checkAndSendHeartbeat();
8565 me->_readMessage.replace(messageHandle_);
8566 Message& message = me->_readMessage;
8568 if (commandType & SOWMask)
8570 #if 0 // Not currently implemented, to avoid an extra branch in delivery 8574 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
8575 me->_globalCommandTypeHandlers[1 + (commandType / 8192)].invoke(message));
8577 AMPS_CALL_EXCEPTION_WRAPPER_2(me, me->_routes.deliverData(message,
8580 else if (commandType & PublishMask)
8582 #if 0 // Not currently implemented, to avoid an extra branch in delivery 8583 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
8584 me->_globalCommandTypeHandlers[(commandType == Message::Command::Publish ?
8585 GlobalCommandTypeHandlers::Publish :
8586 GlobalCommandTypeHandlers::OOF)].invoke(message));
8588 const char* subIds = NULL;
8589 size_t subIdsLen = 0;
8592 &subIds, &subIdsLen);
8593 size_t subIdCount = me->_routes.parseRoutes(
AMPS::Field(subIds, subIdsLen), me->_routeCache);
8594 for (
size_t i = 0; i < subIdCount; ++i)
8596 MessageRouter::RouteCache::value_type& lookupResult = me->_routeCache[i];
8598 if (handler.isValid())
8601 AMPS_SubscriptionId,
8602 subIds + lookupResult.idOffset,
8603 lookupResult.idLength);
8606 bool isAutoAck = me->_isAutoAckEnabled;
8608 if (!isMessageQueue && !bookmark.
empty() &&
8609 me->_bookmarkStore.isValid())
8611 if (me->_bookmarkStore.isDiscarded(me->_readMessage))
8614 if (me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage].isValid())
8616 AMPS_CALL_EXCEPTION_WRAPPER_2(me, me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::DuplicateMessage].invoke(message));
8621 me->_bookmarkStore.log(me->_readMessage);
8622 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
8623 handler.invoke(message));
8628 if (isMessageQueue && isAutoAck)
8632 AMPS_CALL_EXCEPTION_WRAPPER_STREAM_FULL_2(me, handler.invoke(message));
8633 if (!message.getIgnoreAutoAck())
8635 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
8639 catch (std::exception& ex)
8641 if (!message.getIgnoreAutoAck())
8643 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
8646 AMPS_UNHANDLED_EXCEPTION_2(me, ex);
8651 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
8652 handler.invoke(message));
8658 me->lastChance(message);
8662 else if (commandType == Message::Command::Ack)
8665 unsigned deliveries = 0U;
8668 case Message::AckType::Persisted:
8669 deliveries += me->persistedAck(message);
8671 case Message::AckType::Processed:
8672 deliveries += me->processedAck(message);
8675 MessageHandler ackHandler = me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::Ack];
8676 if (ackHandler.isValid())
8678 AMPS_CALL_EXCEPTION_WRAPPER_2(me, ackHandler.invoke(message));
8681 AMPS_CALL_EXCEPTION_WRAPPER_2(me, deliveries += me->_routes.deliverAck(message, ackType));
8682 if (deliveries == 0)
8684 me->lastChance(message);
8687 else if (commandType == Message::Command::Heartbeat)
8689 AMPS_CALL_EXCEPTION_WRAPPER_2(me,
8690 me->_globalCommandTypeHandlers[GlobalCommandTypeHandlers::Heartbeat].invoke(message));
8691 if (me->_heartbeatTimer.getTimeout() != 0.0)
8693 me->checkAndSendHeartbeat(
true);
8697 me->lastChance(message);
8703 unsigned deliveries = 0U;
8706 while (me->_connected)
8710 deliveries = me->_routes.deliverData(message, message.
getCommandId());
8714 catch (MessageStreamFullException&)
8716 catch (MessageStreamFullException& msfEx_)
8721 me->checkAndSendHeartbeat(
false);
8724 catch (std::exception&)
8726 catch (std::exception& stdEx_)
8734 catch (std::exception& stdEx_)
8738 me->_exceptionListener->exceptionThrown(stdEx_);
8745 if (deliveries == 0)
8747 me->lastChance(message);
8750 me->checkAndSendHeartbeat();
8755 ClientImpl::ClientImplPreDisconnectHandler(
amps_handle ,
unsigned failedConnectionVersion,
void* userData)
8757 ClientImpl* me = (ClientImpl*) userData;
8760 me->clearAcks(failedConnectionVersion);
8764 ClientImpl::ClientImplDisconnectHandler(
amps_handle ,
void* userData)
8766 ClientImpl* me = (ClientImpl*) userData;
8767 Lock<Mutex> l(me->_lock);
8768 Client wrapper(me,
false);
8771 me->broadcastConnectionStateChanged(ConnectionStateListener::Disconnected);
8773 me->captureSubscriptionManagerGenerationCount();
8774 bool retryInProgress =
false;
8777 me->_connected =
false;
8778 me->_lock.signalAll();
8781 Unlock<Mutex> unlock(me->_lock);
8782 me->_disconnectHandler.invoke(wrapper);
8785 catch (
const RetryOperationException&)
8787 catch (
const RetryOperationException& ex)
8790 retryInProgress =
true;
8792 catch (
const std::exception& ex)
8794 AMPS_UNHANDLED_EXCEPTION_2(me, ex);
8796 me->_lock.signalAll();
8798 if (!me->_connected)
8800 if (retryInProgress)
8802 AMPS_UNHANDLED_EXCEPTION_2(me, RetryOperationException(
"Reconnect in progress."));
8806 me->broadcastConnectionStateChanged(ConnectionStateListener::Shutdown);
8807 AMPS_UNHANDLED_EXCEPTION_2(me, DisconnectedException(
"Reconnect failed."));
8815 ClientImpl::ClientImplGetHttpPreflightMessage(
void* userData_)
8817 ClientImpl* me = (ClientImpl*)userData_;
8818 std::ostringstream os;
8821 size_t firstColon = me->_lastUri.find(
':');
8823 size_t pathEnd = me->_lastUri.find(
'?');
8825 size_t lastColon = me->_lastUri.rfind(
':', pathEnd);
8827 size_t at = me->_lastUri.rfind(
'@', lastColon);
8829 size_t hostStart = at == std::string::npos ? firstColon + 3 : at + 1;
8830 size_t hostLen = lastColon - hostStart;
8832 size_t pathStart = me->_lastUri.find(
'/', lastColon);
8833 size_t pathLen = pathEnd;
8834 if (pathEnd != std::string::npos)
8836 pathLen = pathEnd - pathStart;
8838 os <<
"GET " << me->_lastUri.substr(pathStart, pathLen)
8839 <<
" HTTP/1.1\r\nHost: " << me->_lastUri.substr(hostStart, hostLen)
8840 <<
"\r\nConnection: upgrade\r\nUpgrade: " 8841 << me->_lastUri.substr(0, firstColon) <<
"\r\n";
8842 for (
auto& header : me->_httpPreflightHeaders)
8844 os << header <<
"\r\n";
8847 me->_preflightMessage = os.str();
8848 return me->_preflightMessage.c_str();
8863 iterator(
const char* data_,
size_t len_,
size_t pos_,
char fieldSep_)
8864 : _data(data_), _len(len_), _pos(pos_), _fieldSep(fieldSep_)
8866 while (_pos != _len && _data[_pos] == _fieldSep)
8872 typedef void* difference_type;
8873 typedef std::forward_iterator_tag iterator_category;
8874 typedef std::pair<Message::Field, Message::Field> value_type;
8875 typedef value_type* pointer;
8876 typedef value_type& reference;
8877 bool operator==(
const iterator& rhs)
const 8879 return _pos == rhs._pos;
8881 bool operator!=(
const iterator& rhs)
const 8883 return _pos != rhs._pos;
8885 iterator& operator++()
8888 while (_pos != _len && _data[_pos] != _fieldSep)
8893 while (_pos != _len && _data[_pos] == _fieldSep)
8900 value_type operator*()
const 8903 size_t i = _pos, keyLength = 0, valueStart = 0, valueLength = 0;
8904 for (; i < _len && _data[i] !=
'='; ++i)
8909 result.first.assign(_data + _pos, keyLength);
8911 if (i < _len && _data[i] ==
'=')
8915 for (; i < _len && _data[i] != _fieldSep; ++i)
8920 result.second.assign(_data + valueStart, valueLength);
8926 class reverse_iterator
8933 typedef std::pair<Message::Field, Message::Field> value_type;
8934 reverse_iterator(
const char* data,
size_t len,
const char* pos,
char fieldsep)
8935 : _data(data), _len(len), _pos(pos), _fieldSep(fieldsep)
8940 while (_pos >= _data && *_pos == _fieldSep)
8944 while (_pos > _data && *_pos != _fieldSep)
8951 if (_pos > _data || (_pos == _data && *_pos == _fieldSep))
8961 bool operator==(
const reverse_iterator& rhs)
const 8963 return _pos == rhs._pos;
8965 bool operator!=(
const reverse_iterator& rhs)
const 8967 return _pos != rhs._pos;
8969 reverse_iterator& operator++()
8980 while (_pos >= _data && *_pos == _fieldSep)
8985 while (_pos > _data && *_pos != _fieldSep)
8989 if (_pos > _data || (_pos == _data && *_pos == _fieldSep))
9000 value_type operator*()
const 9003 size_t keyLength = 0, valueStart = 0, valueLength = 0;
9004 size_t i = (size_t)(_pos - _data);
9005 for (; i < _len && _data[i] !=
'='; ++i)
9009 result.first.assign(_pos, keyLength);
9010 if (i < _len && _data[i] ==
'=')
9014 for (; i < _len && _data[i] != _fieldSep; ++i)
9019 result.second.assign(_data + valueStart, valueLength);
9024 : _data(data.
data()), _len(data.
len()),
9025 _fieldSep(fieldSeparator)
9029 FIX(
const char* data,
size_t len,
char fieldSeparator = 1)
9030 : _data(data), _len(len), _fieldSep(fieldSeparator)
9034 iterator begin()
const 9036 return iterator(_data, _len, 0, _fieldSep);
9038 iterator end()
const 9040 return iterator(_data, _len, _len, _fieldSep);
9044 reverse_iterator rbegin()
const 9046 return reverse_iterator(_data, _len, _data + (_len - 1), _fieldSep);
9049 reverse_iterator rend()
const 9051 return reverse_iterator(_data, _len, 0, _fieldSep);
9072 std::stringstream _data;
9089 void append(
const T& tag,
const char* value,
size_t offset,
size_t length)
9091 _data << tag <<
'=';
9092 _data.write(value + offset, (std::streamsize)length);
9100 void append(
const T& tag,
const std::string& value)
9102 _data << tag <<
'=' << value << _fs;
9111 operator std::string()
const 9119 _data.str(std::string());
9156 typedef std::map<Message::Field, Message::Field>
map_type;
9167 for (FIX::iterator a = fix.begin(); a != fix.end(); ++a)
9176 #define AMPS_MESSAGE_STREAM_CACHE_MAX 128 9180 std::deque<Message> _q;
9181 std::deque<Message> _cache;
9182 std::string _commandId;
9184 std::string _queryId;
9188 unsigned _requestedAcks;
9192 typedef enum :
unsigned int { Unset = 0x0, Running = 0x10, Subscribe = 0x11, SOWOnly = 0x12, AcksOnly = 0x13, Conflate = 0x14, Closed = 0x1, Disconnected = 0x2 } State;
9193 #if __cplusplus >= 201100L || _MSC_VER >= 1900 9194 std::atomic<State> _state;
9196 volatile State _state;
9198 typedef std::map<std::string, Message*> SOWKeyMap;
9199 SOWKeyMap _sowKeyMap;
9201 MessageStreamImpl(
const Client& client_)
9204 _maxDepth((
unsigned)~0),
9206 _cacheMax(AMPS_MESSAGE_STREAM_CACHE_MAX),
9209 if (_client.isValid())
9215 MessageStreamImpl(ClientImpl* client_)
9216 : _client(client_,
false),
9218 _maxDepth((
unsigned)~0),
9222 if (_client.isValid())
9228 ~MessageStreamImpl()
9232 virtual void destroy()
9238 catch (std::exception& e)
9242 if (_client.isValid())
9249 if (_client.isValid())
9253 _client = Client((ClientImpl*)NULL);
9254 c.deferredExecution(MessageStreamImpl::destroyer,
this);
9262 static void destroyer(
void* vpMessageStreamImpl_)
9264 delete ((MessageStreamImpl*)vpMessageStreamImpl_);
9267 void setSubscription(
const std::string& subId_,
9268 const std::string& commandId_ =
"",
9269 const std::string& queryId_ =
"")
9271 Lock<Mutex> lock(_lock);
9273 if (!commandId_.empty() && commandId_ != subId_)
9275 _commandId = commandId_;
9277 if (!queryId_.empty() && queryId_ != subId_ && queryId_ != commandId_)
9279 _queryId = queryId_;
9282 if (Disconnected == _state)
9286 assert(Unset == _state);
9290 void setSOWOnly(
const std::string& commandId_,
9291 const std::string& queryId_ =
"")
9293 Lock<Mutex> lock(_lock);
9294 _commandId = commandId_;
9295 if (!queryId_.empty() && queryId_ != commandId_)
9297 _queryId = queryId_;
9300 if (Disconnected == _state)
9304 assert(Unset == _state);
9308 void setStatsOnly(
const std::string& commandId_,
9309 const std::string& queryId_ =
"")
9311 Lock<Mutex> lock(_lock);
9312 _commandId = commandId_;
9313 if (!queryId_.empty() && queryId_ != commandId_)
9315 _queryId = queryId_;
9318 if (Disconnected == _state)
9322 assert(Unset == _state);
9324 _requestedAcks = Message::AckType::Stats;
9327 void setAcksOnly(
const std::string& commandId_,
unsigned acks_)
9329 Lock<Mutex> lock(_lock);
9330 _commandId = commandId_;
9332 if (Disconnected == _state)
9336 assert(Unset == _state);
9338 _requestedAcks = acks_;
9343 Lock<Mutex> lock(_lock);
9344 if (state_ == AMPS::ConnectionStateListener::Disconnected)
9346 _state = Disconnected;
9349 else if (state_ == AMPS::ConnectionStateListener::Connected
9350 && _commandId.empty()
9352 && _queryId.empty())
9360 void timeout(
unsigned timeout_)
9362 _timeout = timeout_;
9366 if (_state == Subscribe)
9371 void maxDepth(
unsigned maxDepth_)
9375 _maxDepth = maxDepth_;
9379 _maxDepth = (unsigned)~0;
9382 unsigned getMaxDepth(
void)
const 9386 unsigned getDepth(
void)
const 9388 return (
unsigned)(_q.size());
9393 Lock<Mutex> lock(_lock);
9394 if (!_previousTopic.
empty() && !_previousBookmark.
empty())
9398 if (_client.isValid())
9400 _client.ackDeferredAutoAck(_previousTopic, _previousBookmark);
9409 current_.invalidate();
9410 _previousTopic.
clear();
9411 _previousBookmark.
clear();
9414 _previousTopic.
clear();
9415 _previousBookmark.
clear();
9418 long minWaitTime = (_timeout && _timeout < 1000) ? _timeout : 1000;
9419 Timer timer((
double)_timeout);
9421 while (_q.empty() && _state & Running)
9424 _lock.wait(minWaitTime);
9426 Unlock<Mutex> unlck(_lock);
9427 amps_invoke_waiting_function();
9432 if (timer.checkAndGetRemaining(&minWaitTime))
9438 minWaitTime = (minWaitTime < 1000) ? minWaitTime : 1000;
9441 if (current_.isValid() && _cache.size() < _cacheMax)
9444 _cache.push_back(current_);
9448 current_ = _q.front();
9449 if (_q.size() == _maxDepth)
9454 if (_state == Conflate)
9456 std::string sowKey = current_.
getSowKey();
9457 if (sowKey.length())
9459 _sowKeyMap.erase(sowKey);
9462 else if (_state == AcksOnly)
9466 if ((_state == AcksOnly && _requestedAcks == 0) ||
9467 (_state == SOWOnly && current_.
getCommand() ==
"group_end"))
9471 else if (current_.isValid()
9482 if (_state == Disconnected)
9484 throw DisconnectedException(
"Connection closed.");
9486 current_.invalidate();
9487 if (_state == Closed)
9491 return _timeout != 0;
9495 if (_client.isValid())
9497 if (_state == SOWOnly || _state == Subscribe)
9499 if (!_commandId.empty())
9503 if (!_subId.empty())
9507 if (!_queryId.empty())
9514 if (!_commandId.empty())
9518 if (!_subId.empty())
9522 if (!_queryId.empty())
9528 if (_state == SOWOnly || _state == Subscribe || _state == Unset)
9533 static void _messageHandler(
const Message& message_, MessageStreamImpl* this_)
9535 Lock<Mutex> lock(this_->_lock);
9536 if (this_->_state != Conflate)
9538 AMPS_TESTING_SLOW_MESSAGE_STREAM
9539 if (this_->_q.size() >= this_->_maxDepth)
9544 this_->_lock.signalAll();
9545 throw MessageStreamFullException(
"Stream is currently full.");
9547 if (!this_->_cache.empty())
9549 this_->_cache.front().deepCopy(message_);
9550 this_->_q.push_back(this_->_cache.front());
9551 this_->_cache.pop_front();
9555 this_->_q.emplace_back(message_.
deepCopy());
9558 this_->_client.isValid() && this_->_client.getAutoAck() &&
9562 message_.setIgnoreAutoAck();
9567 std::string sowKey = message_.
getSowKey();
9568 if (sowKey.length())
9570 SOWKeyMap::iterator it = this_->_sowKeyMap.find(sowKey);
9571 if (it != this_->_sowKeyMap.end())
9573 it->second->deepCopy(message_);
9577 if (this_->_q.size() >= this_->_maxDepth)
9583 this_->_lock.signalAll();
9584 throw MessageStreamFullException(
"Stream is currently full.");
9586 if (!this_->_cache.empty())
9588 this_->_cache.front().deepCopy(message_);
9589 this_->_q.push_back(this_->_cache.front());
9590 this_->_cache.pop_front();
9594 this_->_q.emplace_back(message_.
deepCopy());
9596 this_->_sowKeyMap[sowKey] = &(this_->_q.back());
9601 if (this_->_q.size() >= this_->_maxDepth)
9606 this_->_lock.signalAll();
9607 throw MessageStreamFullException(
"Stream is currently full.");
9609 if (!this_->_cache.empty())
9611 this_->_cache.front().deepCopy(message_);
9612 this_->_q.push_back(this_->_cache.front());
9613 this_->_cache.pop_front();
9617 this_->_q.emplace_back(message_.
deepCopy());
9620 this_->_client.isValid() && this_->_client.getAutoAck() &&
9624 message_.setIgnoreAutoAck();
9628 this_->_lock.signalAll();
9631 inline MessageStream::MessageStream(
const Client& client_)
9632 : _body(
new MessageStreamImpl(client_))
9635 inline MessageStream::MessageStream(RefHandle<MessageStreamImpl> body_)
9639 inline void MessageStream::iterator::advance(
void)
9641 _pStream = _pStream->_body->next(_current) ? _pStream : NULL;
9645 return MessageHandler((
void(*)(
const Message&,
void*))MessageStreamImpl::_messageHandler, &_body.get());
9650 if (handler_._func == (MessageHandler::FunctionType)MessageStreamImpl::_messageHandler)
9652 result._body = (MessageStreamImpl*)(handler_._userData);
9657 inline void MessageStream::setSOWOnly(
const std::string& commandId_,
9658 const std::string& queryId_)
9660 _body->setSOWOnly(commandId_, queryId_);
9662 inline void MessageStream::setSubscription(
const std::string& subId_,
9663 const std::string& commandId_,
9664 const std::string& queryId_)
9666 _body->setSubscription(subId_, commandId_, queryId_);
9668 inline void MessageStream::setStatsOnly(
const std::string& commandId_,
9669 const std::string& queryId_)
9671 _body->setStatsOnly(commandId_, queryId_);
9673 inline void MessageStream::setAcksOnly(
const std::string& commandId_,
9676 _body->setAcksOnly(commandId_, acks_);
9695 return _body->getMaxDepth();
9699 return _body->getDepth();
9702 inline MessageStream ClientImpl::getEmptyMessageStream(
void)
9712 ClientImpl& body = _body.get();
9713 Message& message = command_.getMessage();
9717 if (useExistingHandler)
9723 if (body._routes.getRoute(subId, existingHandler))
9726 body.executeAsync(command_, existingHandler,
false);
9727 return MessageStream::fromExistingHandler(existingHandler);
9736 if ((command & Message::Command::NoDataCommands)
9737 && (ackTypes == Message::AckType::Persisted
9738 || ackTypes == Message::AckType::None))
9741 if (!body._pEmptyMessageStream)
9743 body._pEmptyMessageStream.reset(
new MessageStream((ClientImpl*)0));
9744 body._pEmptyMessageStream.get()->_body->close();
9746 return body.getEmptyMessageStream();
9749 if (body.getDefaultMaxDepth())
9751 stream.
maxDepth(body.getDefaultMaxDepth());
9754 std::string commandID = body.executeAsync(command_, handler,
false);
9755 if (command_.hasStatsAck())
9757 stream.setStatsOnly(commandID, command_.getMessage().
getQueryId());
9759 else if (command_.isSow())
9763 stream.setAcksOnly(commandID,
9768 stream.setSOWOnly(commandID, command_.getMessage().
getQueryId());
9771 else if (command_.isSubscribe())
9773 stream.setSubscription(commandID,
9780 if (command == Message::Command::Publish ||
9781 command == Message::Command::DeltaPublish ||
9782 command == Message::Command::SOWDelete)
9784 stream.setAcksOnly(commandID,
9785 ackTypes & (
unsigned)~Message::AckType::Persisted);
9789 stream.setAcksOnly(commandID, ackTypes);
9796 inline void Message::ack(
const char* options_)
const 9798 ClientImpl* pClient = _body.get().clientImpl();
9800 if (pClient && bookmark.
len() &&
9801 !pClient->getAutoAck())
9804 pClient->ack(getTopic(), bookmark, options_);
Command & setBookmark(const std::string &bookmark_)
Set the bookmark to be used this command.
Definition: ampsplusplus.hpp:748
Command & setFilter(const char *filter_, size_t filterLen_)
Definition: ampsplusplus.hpp:699
Class to hold string versions of failure reasons.
Definition: ampsplusplus.hpp:151
Message & setData(const std::string &v_)
Sets the data portion of self.
Definition: Message.hpp:1516
Core type and function declarations for the AMPS C client.
Client(const std::string &clientName="")
Constructs a new client with a given client name.
Definition: ampsplusplus.hpp:5523
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...
Field getUserId() const
Retrieves the value of the UserId header of the Message as a Field which references the underlying bu...
Definition: Message.hpp:1493
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:7649
std::string stopTimer(const MessageHandler &messageHandler)
Definition: ampsplusplus.hpp:7623
static const unsigned int IdentifierLength
The length of identifiers used for unique identification of commands and subscriptions.
Definition: Message.hpp:528
amps_uint64_t publish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, const char *correlationId_, size_t correlationIdLength_, const char *sowKey_, size_t sowKeyLength_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6261
std::string getAckType() const
Definition: ampsplusplus.hpp:953
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.
Message & assignOwnershipBookmark(const Field &f)
Assigns the value of the Bookmark header for this Message without copying and makes this Message resp...
Definition: Message.hpp:1234
bool removeMessageHandler(const Field &commandId_)
Removes a MessageHandler for a given ComandId from self.
Definition: ampsplusplus.hpp:5792
Message & assignTopic(const std::string &v)
Assigns the value of the Topic header for this Message without copying.
Definition: Message.hpp:1489
Provides a convenient way of building messages in FIX format, typically referenced using the typedefs...
Definition: ampsplusplus.hpp:9070
void startTimer()
Definition: ampsplusplus.hpp:7612
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:7148
Abstract base class for storing published messages for an HA publisher client.
Definition: ampsplusplus.hpp:1097
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:9683
Field getSequence() const
Retrieves the value of the Sequence header of the Message as a Field which references the underlying ...
Definition: Message.hpp:1462
AMPSDLL amps_result amps_client_set_name(amps_handle handle, const amps_char *clientName)
Sets the name on an amps client object.
Message & setCorrelationId(const std::string &v)
Sets the value of the CorrelationId header for this Message.
Definition: Message.hpp:1344
Message & setQueryID(const std::string &v)
Sets the value of the QueryID header for this Message.
Definition: Message.hpp:1457
Command(const std::string &command_)
Creates an object to represent the given AMPS command, such as "sow" or "subscribe".
Definition: ampsplusplus.hpp:560
Command::Type getCommandEnum() const
Decode self's "command" field and return one of the values from Command.
Definition: Message.hpp:1268
Command & setBookmark(const char *bookmark_, size_t bookmarkLen_)
Set the bookmark to be used this command.
Definition: ampsplusplus.hpp:759
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:7921
Command & setAckType(unsigned ackType_)
Definition: ampsplusplus.hpp:931
void setServerVersion(size_t version_)
Internally used to set the server version so the store knows how to deal with persisted acks and call...
Definition: BookmarkStore.hpp:429
void setDefaultMaxDepth(unsigned maxDepth_)
Sets a default max depth on all subsequently created MessageStream objects.
Definition: ampsplusplus.hpp:8289
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:5584
amps_uint64_t publish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, const char *correlationId_, size_t correlationIdLength_, const char *sowKey_, size_t sowKeyLength_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6327
Field getSubscriptionId() const
Retrieves the value of the SubscriptionId header of the Message as a Field which references the under...
Definition: Message.hpp:1467
AMPSDLL amps_result amps_client_connect(amps_handle handle, const amps_char *uri)
Connects to the AMPS server specified in uri.
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:5680
void unsubscribe(const std::string &commandId)
Unsubscribe from a topic.
Definition: ampsplusplus.hpp:6937
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
Message & setOrderBy(const std::string &v)
Sets the value of the OrderBy header for this Message.
Definition: Message.hpp:1455
Abstract base class for replaying a publish message.
Definition: ampsplusplus.hpp:1069
Command & setCommandId(const char *cmdId_, size_t cmdIdLen_)
Definition: ampsplusplus.hpp:673
void persisted(const Message::Field &subId_, const Message::Field &bookmark_)
Called internally to indicate messages up to and including bookmark are replicated to all replication...
Definition: BookmarkStore.hpp:405
unsigned getDefaultMaxDepth(void) const
Returns the default max depth for returned MessageStream objects.
Definition: ampsplusplus.hpp:8298
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:8157
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:6888
AMPSDLL void amps_client_disconnect(amps_handle handle)
Disconnects from the AMPS server, if connected.
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 discard(const Message::Field &subId_, size_t bookmarkSeqNo_)
Log a discard-bookmark entry to the persistent log based on a bookmark sequence number.
Definition: BookmarkStore.hpp:283
void setPublishStore(const Store &publishStore_)
Set the publish store to be used by the client.
Definition: ampsplusplus.hpp:5933
void setErrorOnPublishGap(bool errorOnPublishGap_)
Called to enable or disable throwing PublishStoreGapException.
Definition: ampsplusplus.hpp:1346
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:6583
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:5695
Message & setFilter(const std::string &v)
Sets the value of the Filter header for this Message.
Definition: Message.hpp:1346
Command & setSubId(const char *subId_, size_t subIdLen_)
Definition: ampsplusplus.hpp:725
void setNoEmpties(void)
Set the option to not send empty messages on a delta subscription.
Definition: Message.hpp:848
void setDuplicateMessageHandler(const MessageHandler &duplicateMessageHandler_)
Sets a callback function that is invoked when a duplicate message is detected.
Definition: ampsplusplus.hpp:5949
Message deepCopy(void) const
Returns a deep copy of self.
Definition: Message.hpp:565
void removeConnectionStateListener(ConnectionStateListener *listener)
Attempts to remove listener from self's set of ConnectionStateListeners.
Definition: ampsplusplus.hpp:8012
void setOOF(void)
Set the option to receive out of focus (OOF) messages on a subscription, where applicable.
Definition: Message.hpp:831
int getAckTimeout(void) const
Returns the current value of the message queue ack timeout setting – that is, the amount of time aft...
Definition: ampsplusplus.hpp:8241
VersionInfo getServerVersionInfo() const
Returns the server version retrieved during logon.
Definition: ampsplusplus.hpp:5666
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:7676
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...
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
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_idle_time(amps_handle client, int idleTime)
Sets an idle-time (milliseconds).
Message encapsulates a single message sent to or received from an AMPS server, and provides methods f...
Definition: Message.hpp:517
Message & setAckTypeEnum(unsigned ackType_)
Encode self's "ack type" field from a bitmask of values from AckType.
Definition: Message.hpp:1223
amps_uint64_t getLastPersisted()
Get the last persisted message sequence in the store.
Definition: ampsplusplus.hpp:1317
static void throwFor(const T &context_, amps_result result_)
Constructs and throws the appropriate exception corresponding to a given result.
std::string getString() const
Returns the current contents of this builder as a string.
Definition: ampsplusplus.hpp:9107
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:8309
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:6085
iterator begin(void)
Returns an iterator representing the beginning of the topic or subscription.
Definition: ampsplusplus.hpp:5425
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:5627
Field getLeasePeriod() const
Retrieves the value of the LeasePeriod header of the Message as a Field which references the underlyi...
Definition: Message.hpp:1349
Command & setSowKeys(const char *sowKeys_, size_t sowKeysLen_)
Sets the SowKeys for the command.
Definition: ampsplusplus.hpp:660
static const char * NOW()
Convenience method for returning the special value to start a subscription at the end of the transact...
Definition: ampsplusplus.hpp:7940
Command & setAckType(const std::string &ackType_)
Definition: ampsplusplus.hpp:909
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:7950
void send(const Message &message)
Sends a Message to the connected AMPS server, performing only minimal validation and bypassing client...
Definition: ampsplusplus.hpp:5751
Message & setSowKey(const std::string &v)
Sets the value of the SowKey header for this Message.
Definition: Message.hpp:1464
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.
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:6860
Field getFilter() const
Retrieves the value of the Filter header of the Message as a Field which references the underlying bu...
Definition: Message.hpp:1346
static size_t getUnsetPosition()
Method to return the value used to represent not found or unset.
Definition: ampsplusplus.hpp:1160
void setRetryOnDisconnect(bool isRetryOnDisconnect_)
Enables or disables automatic retry of a command to AMPS after a reconnect.
Definition: ampsplusplus.hpp:8271
amps_uint64_t publishKeyed(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, const char *sowKey_, size_t sowKeyLength_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6408
unsigned getMaxDepth(void) const
Gets the maximum number of messages that can be held in the underlying queue.
Definition: ampsplusplus.hpp:9693
Message & assignUserId(const std::string &v)
Assigns the value of the UserId header for this Message without copying.
Definition: Message.hpp:1493
void connect(const std::string &uri)
Connect to an AMPS server.
Definition: ampsplusplus.hpp:5726
void clear()
Deletes the data associated with this Field, should only be used on Fields that were created as deepC...
Definition: Field.hpp:266
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:5781
Abstract base class to manage all subscriptions placed on a client so that they can be re-established...
Definition: ampsplusplus.hpp:1461
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:7342
Success.
Definition: amps.h:221
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...
Message & setCommandEnum(Command::Type command_)
Set self's "command" field from one of the values in Command.
Definition: Message.hpp:1328
amps_uint64_t publish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, const char *correlationId_, size_t correlationIdLength_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6140
Field getOptions() const
Retrieves the value of the Options header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1356
std::string authenticate(const std::string &, const std::string &password_)
A simple implementation that returns an unmodified password.
Definition: ampsplusplus.hpp:1043
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:6560
FIXShredder(char fieldSep_=(char) 1)
Construct an instance of FIXShredder using the specified value as the delimiter between fields...
Definition: ampsplusplus.hpp:9152
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:6984
void * amps_handle
Opaque handle type used to refer to objects in the AMPS api.
Definition: amps.h:211
Class for constructing the options string to pass to AMPS in a Message.
Definition: Message.hpp:587
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:5764
const char * data() const
Returns the (non-null-terminated) data underlying this field.
Definition: Field.hpp:279
bool isValid() const
Returns true if self is a valid stream that may be iterated.
Definition: ampsplusplus.hpp:5418
amps_result
Return values from amps_xxx functions.
Definition: amps.h:216
FailedWriteHandler * getFailedWriteHandler()
Get the handler that is invoked to report on failed writes.
Definition: ampsplusplus.hpp:5986
Field getAckType() const
Retrieves the value of the AckType header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1170
amps_uint64_t publish(const std::string &topic_, const std::string &data_, const std::string &correlationId_, const std::string &sowKey_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6228
AMPSDLL amps_handle amps_client_create(const amps_char *clientName)
Functions for creation of an AMPS client.
Field getCommand() const
Retrieves the value of the Command header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1235
MessageStream execute(Command &command_)
Execute the provided command and return messages received in response in a MessageStream.
Definition: ampsplusplus.hpp:9707
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
Message & setTopic(const std::string &v)
Sets the value of the Topic header for this Message.
Definition: Message.hpp:1489
Store getPublishStore()
Get the publish store used by the client.
Definition: ampsplusplus.hpp:5941
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:8323
unsigned getAckTypeEnum() const
Definition: ampsplusplus.hpp:958
size_t getServerVersion() const
Returns the server version retrieved during logon.
Definition: ampsplusplus.hpp:5655
State
Constants for the state of the connection.
Definition: ampsplusplus.hpp:1514
Command & setData(const std::string &data_)
Sets the data for this command from an existing string.
Definition: ampsplusplus.hpp:829
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:6632
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 publishKeyed(const std::string &topic_, const std::string &data_, const std::string &sowKey_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store (if a...
Definition: ampsplusplus.hpp:6435
Command & setFilter(const std::string &filter_)
Definition: ampsplusplus.hpp:692
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:5576
virtual AMPS_ATOMIC_BASE_TYPE getGenerationCount() const
Gets the current subscription manager generation count.
Definition: ampsplusplus.hpp:1479
StoreImpl(bool errorOnPublishGap_=false)
Default constructor.
Definition: ampsplusplus.hpp:1105
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:7296
Client represents a connection to an AMPS server, but does not provide failover or reconnection behav...
Definition: ampsplusplus.hpp:5506
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:7896
Command & setSubId(const std::string &subId_)
Definition: ampsplusplus.hpp:718
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:7931
Message & newCommandId()
Creates and sets a new sequential value for the CommandId header for this Message.
Definition: Message.hpp:1342
void addConnectionStateListener(ConnectionStateListener *listener)
Adds a ConnectionStateListener to self's set of listeners.
Definition: ampsplusplus.hpp:8004
Command & reset(const std::string &command_)
Resets the fields of self, and sets the command to command_.
Definition: ampsplusplus.hpp:583
void clearHttpPreflightHeaders()
Clears all previously set HTTP header lines.
Definition: ampsplusplus.hpp:5633
Command & setTimeout(unsigned timeout_)
Sets the client-side timeout for this command.
Definition: ampsplusplus.hpp:851
void clearConnectionStateListeners()
Clear all listeners from self's set of ConnectionStateListeners.
Definition: ampsplusplus.hpp:8019
amps_uint64_t publish(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, const char *correlationId_, size_t correlationIdLength_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6199
Message & setSequence(const std::string &v)
Sets the value of the Sequence header for this Message.
Definition: Message.hpp:1462
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:6034
Command & setCommandId(const std::string &cmdId_)
Definition: ampsplusplus.hpp:666
Message & setUserId(const std::string &v)
Sets the value of the UserId header for this Message.
Definition: Message.hpp:1493
Base class for all exceptions in AMPS.
Definition: AMPSException.hpp:40
Field getTopic() const
Retrieves the value of the Topic header of the Message as a Field which references the underlying buf...
Definition: Message.hpp:1489
AMPSDLL void amps_client_set_message_handler(amps_handle client, amps_handler messageHandler, void *userData)
Sets the message handler function for this client.
SubscriptionManager * getSubscriptionManager()
Get the subscription manager being used by the client.
Definition: ampsplusplus.hpp:5897
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:6695
Command(Message::Command::Type command_)
Creates an object to represent the given AMPS command, such as "sow" or "subscribe".
Definition: ampsplusplus.hpp:575
Message & setMessageType(const std::string &v)
Sets the value of the MessageType header for this Message.
Definition: Message.hpp:1352
Field getCommandId() const
Retrieves the value of the CommandId header of the Message as a Field which references the underlying...
Definition: Message.hpp:1342
const ExceptionListener & getExceptionListener(void) const
Returns the exception listener set on this Client.
Definition: ampsplusplus.hpp:7804
Field getQueryId() const
Retrieves the value of the QueryID header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1457
static Authenticator & instance()
Static function to return a static instance used when no Authenticator is supplied to a Client...
Definition: ampsplusplus.hpp:1060
Abstract base class for connection state listeners.
Definition: ampsplusplus.hpp:1510
Message & setSubscriptionId(const std::string &v)
Sets the value of the SubscriptionId header for this Message.
Definition: Message.hpp:1467
virtual void setDisconnectHandler(const DisconnectHandler &disconnectHandler)
Definition: ampsplusplus.hpp:5845
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:7717
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
amps_uint64_t publishKeyed(const std::string &topic_, const std::string &data_, const std::string &sowKey_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6379
Message & newQueryId()
Creates and sets a new sequential value for the QueryID header for this Message.
Definition: Message.hpp:1457
#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
Message & assignExpiration(const std::string &v)
Assigns the value of the Expiration header for this Message without copying.
Definition: Message.hpp:1345
bool empty() const
Returns 'true' if empty, 'false' otherwise.
Definition: Field.hpp:129
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 completed(const std::string &, const std::string &, const std::string &)
Called by Client once a logon completes successfully.
Definition: ampsplusplus.hpp:1055
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:6800
static const char * EPOCH()
Convenience method for returning the special value to start a subscription at the beginning of the tr...
Definition: ampsplusplus.hpp:7960
Interface for BookmarkStoreImpl classes.
Definition: BookmarkStore.hpp:228
Command & reset(const char *command_, size_t commandLen_)
Resets the fields of self, and sets the command to command_.
Definition: ampsplusplus.hpp:592
Command & setSequence(const char *seq_, size_t seqLen_)
Definition: ampsplusplus.hpp:810
amps_uint64_t publish(const std::string &topic_, const std::string &data_, const std::string &correlationId_, const std::string &sowKey_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store (if a...
Definition: ampsplusplus.hpp:6291
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:6651
size_t len() const
Returns the length of the data underlying this field.
Definition: Field.hpp:286
virtual void completed(const std::string &userName_, const std::string &password_, const std::string &reason_)=0
Called by Client once a logon completes successfully.
amps_uint64_t publish(const std::string &topic_, const std::string &data_, const std::string &correlationId_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6111
Message & setClientName(const std::string &v)
Sets the value of the ClientName header for this Message.
Definition: Message.hpp:1343
Field getSowKey() const
Retrieves the value of the SowKey header of the Message as a Field which references the underlying bu...
Definition: Message.hpp:1464
#define AMPS_BOOKMARK_EPOCH
Start the subscription at the beginning of the journal.
Definition: BookmarkStore.hpp:51
A default implementation of Authenticator that only uses an unchanged password and does not implement...
Definition: ampsplusplus.hpp:1037
void setLogonCorrelationData(const std::string &logonCorrelationData_)
Sets the logon correlation data for the client.
Definition: ampsplusplus.hpp:5603
Message & setCommand(const std::string &v)
Sets the value of the Command header for this Message.
Definition: Message.hpp:1235
_FIXBuilder(char fieldSep_=(char) 1)
Construct an instance of _FIXBuilder, using the specified separator between fields.
Definition: ampsplusplus.hpp:9080
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:5618
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:8169
std::string retry(const std::string &, const std::string &)
Throws an AuthenticationException because retry is not implemented.
Definition: ampsplusplus.hpp:1050
Message & assignSubscriptionId(const std::string &v)
Assigns the value of the SubscriptionId header for this Message without copying.
Definition: Message.hpp:1467
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
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.
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:7186
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
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:9089
Message & assignCommand(const std::string &v)
Assigns the value of the Command header for this Message without copying.
Definition: Message.hpp:1235
#define AMPS_BOOKMARK_NOW
Start the subscription at the point in time when AMPS processes the subscription. ...
Definition: BookmarkStore.hpp:55
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
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.
BookmarkStore getBookmarkStore()
Get the bookmark store being used by the client.
Definition: ampsplusplus.hpp:5889
void setHttpPreflightHeaders(const T &headers_)
Sets the given HTTP header lines to be sent for the HTTP GET Upgrade request.
Definition: ampsplusplus.hpp:5642
bool isValid() const
Method to return if there is an underlying implementation for the Store.
Definition: ampsplusplus.hpp:1288
void setAckBatchSize(const unsigned ackBatchSize_)
Sets the queue ack batch size setting.
Definition: ampsplusplus.hpp:8230
Field getPassword() const
Retrieves the value of the Password header of the Message as a Field which references the underlying ...
Definition: Message.hpp:1456
Message & setTopNRecordsReturned(const std::string &v)
Sets the value of the TopNRecordsReturned header for this Message.
Definition: Message.hpp:1491
Class to handle when a client receives a duplicate publish message, or not entitled message...
Definition: ampsplusplus.hpp:1381
amps_uint64_t publishKeyed(const char *topic_, size_t topicLength_, const char *data_, size_t dataLength_, const char *sowKey_, size_t sowKeyLength_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6467
virtual void setFailedResubscribeHandler(std::shared_ptr< FailedResubscribeHandler > handler_)
Set a handler to deal with failing subscriptions after a failover event.
Definition: ampsplusplus.hpp:1498
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:8335
Message & setSowKeys(const std::string &v)
Sets the value of the SowKeys header for this Message.
Definition: Message.hpp:1465
void setBookmarkStore(const BookmarkStore &bookmarkStore_)
Set the bookmark store to be used by the client.
Definition: ampsplusplus.hpp:5881
This class multiplexes messages from AMPS to multiple subscribers and uses the stream of acks from AM...
Definition: MessageRouter.hpp:135
Message & setExpiration(const std::string &v)
Sets the value of the Expiration header for this Message.
Definition: Message.hpp:1345
virtual std::string authenticate(const std::string &userName_, const std::string &password_)=0
Called by Client just before the logon command is sent.
Command & setOrderBy(const std::string &orderBy_)
Definition: ampsplusplus.hpp:705
void setExceptionListener(const ExceptionListener &listener_)
Definition: ampsplusplus.hpp:7797
Command & reset(Message::Command::Type command_)
Resets the fields of self, and sets the command to command_.
Definition: ampsplusplus.hpp:600
void setSubscriptionManager(SubscriptionManager *subscriptionManager_)
Set the subscription manager to be used by the client.
Definition: ampsplusplus.hpp:5909
void setUnhandledMessageHandler(const AMPS::MessageHandler &messageHandler)
Definition: ampsplusplus.hpp:7863
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:9100
unsigned getAckBatchSize(void) const
Returns the value of the queue ack batch size setting.
Definition: ampsplusplus.hpp:8220
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:6537
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:7273
Command & setExpiration(unsigned expiration_)
Set the expiration time for a publish command.
Definition: ampsplusplus.hpp:889
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.
Represents an iterator over messages in an AMPS topic.
Definition: ampsplusplus.hpp:5380
size_t log(Message &message_)
Log a bookmark to the persistent log.
Definition: BookmarkStore.hpp:268
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:7519
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
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.
Command & setData(const char *data_, size_t dataLen_)
Sets the data for this command.
Definition: ampsplusplus.hpp:837
Message & assignAckType(const std::string &v)
Assigns the value of the AckType header for this Message without copying.
Definition: Message.hpp:1170
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:6516
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:8049
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
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:7478
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:6670
void unsubscribe()
Unsubscribe from all topics.
Definition: ampsplusplus.hpp:6949
void setAutoAck(bool isAutoAckEnabled_)
Sets the queue auto-ack setting on this client.
Definition: ampsplusplus.hpp:8212
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:6818
Message & assignCorrelationId(const std::string &v)
Assigns the value of the CorrelationId header for this Message without copying.
Definition: Message.hpp:1344
amps_uint64_t store(const Message &message_)
Called by Client to store a message being published.
Definition: ampsplusplus.hpp:1239
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:7442
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
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:7781
StoreImpl * get()
Used to get a pointer to the implementation.
Definition: ampsplusplus.hpp:1363
MessageHandler getDuplicateMessageHandler(void)
Returns the callback function that is invoked when a duplicate message is detected.
Definition: ampsplusplus.hpp:5964
Command & setQueryId(const char *queryId_, size_t queryIdLen_)
Definition: ampsplusplus.hpp:738
DisconnectHandler getDisconnectHandler(void) const
Definition: ampsplusplus.hpp:5859
Class for parsing a FIX format message into a std::map of keys and values, where the keys and values ...
Definition: ampsplusplus.hpp:9144
Field represents the value of a single field in a Message.
Definition: Field.hpp:87
Message & setAckType(const std::string &v)
Sets the value of the AckType header for this Message.
Definition: Message.hpp:1170
virtual ConnectionInfo getConnectionInfo() const
Get the connection information for the current connection.
Definition: ampsplusplus.hpp:5868
Message & setOptions(const std::string &v)
Sets the value of the Options header for this Message.
Definition: Message.hpp:1384
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:8145
Abstract base class where you can implement handling of exceptions that occur when a SubscriptionMana...
Definition: ampsplusplus.hpp:1439
AMPSDLL amps_result amps_client_send(amps_handle client, amps_handle message)
Sends a message to the AMPS server.
std::map< Message::Field, Message::Field > map_type
Convenience defintion for the std::map specialization used for this class.
Definition: ampsplusplus.hpp:9156
Command & setTopic(const char *topic_, size_t topicLen_)
Definition: ampsplusplus.hpp:686
Handle class for StoreImpl classes that track publish messages.
Definition: ampsplusplus.hpp:1223
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:9163
Exception listener for unhandled exceptions.
Definition: ampsplusplus.hpp:204
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:7375
void setHeartbeat(unsigned heartbeatTime_)
Requests heartbeating with the AMPS server.
Definition: ampsplusplus.hpp:7854
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:6753
An iterable object representing the results of an AMPS subscription and/or query. ...
Definition: ampsplusplus.hpp:5372
bool getErrorOnPublishGap() const
Called to check if the Store will throw PublishStoreGapException.
Definition: ampsplusplus.hpp:1355
Command & setSequence(const std::string &seq_)
Definition: ampsplusplus.hpp:803
static const char * MOST_RECENT()
Convenience method for returning the special value to start a subscription at a recovery point based ...
Definition: ampsplusplus.hpp:7982
Command & setQueryId(const std::string &queryId_)
Definition: ampsplusplus.hpp:731
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...
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:7581
Message & setCommandId(const std::string &v)
Sets the value of the CommandId header for this Message.
Definition: Message.hpp:1342
Command & setSequence(const amps_uint64_t seq_)
Definition: ampsplusplus.hpp:816
static const char * BOOKMARK_RECENT()
Convenience method for returning the special value to start a subscription at a recovery point based ...
Definition: ampsplusplus.hpp:7993
Message & setQueryId(const std::string &v)
Sets the value of the QueryID header for this Message.
Definition: Message.hpp:1457
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
amps_uint64_t getLowestUnpersisted()
Get the oldest unpersisted message sequence in the store.
Definition: ampsplusplus.hpp:1309
Command & setTopic(const std::string &topic_)
Definition: ampsplusplus.hpp:679
MessageStream maxDepth(unsigned maxDepth_)
Sets the maximum number of messages that can be held in the underlying queue.
Definition: ampsplusplus.hpp:9688
Message & assignVersion(const std::string &v)
Assigns the value of the Version header for this Message without copying.
Definition: Message.hpp:1492
void disconnect()
Disconnect from an AMPS server.
Definition: ampsplusplus.hpp:5733
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:7022
unsigned getDepth(void) const
Gets the current number of messages held in the underlying queue.
Definition: ampsplusplus.hpp:9697
Field getQueryID() const
Retrieves the value of the QueryID header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1457
The operation has not succeeded, but ought to be retried.
Definition: amps.h:245
const std::string & getLogonCorrelationData() const
Returns the currently set logon correlation data for the client.
Definition: ampsplusplus.hpp:5610
void setHeartbeat(unsigned heartbeatTime_, unsigned readTimeout_)
Requests heartbeating with the AMPS server.
Definition: ampsplusplus.hpp:7830
Command & setTopN(unsigned topN_)
Definition: ampsplusplus.hpp:857
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...
const std::string & getURI() const
Returns the last URI this client is connected to.
Definition: ampsplusplus.hpp:5702
Command & addAckType(const std::string &ackType_)
Definition: ampsplusplus.hpp:895
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
amps_uint64_t publish(const std::string &topic_, const std::string &data_, const std::string &correlationId_, unsigned long expiration_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store (if a...
Definition: ampsplusplus.hpp:6167
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:7971
Message & setBookmark(const std::string &v)
Sets the value of the Bookmark header for this Message.
Definition: Message.hpp:1234
std::string send(const MessageHandler &messageHandler_, Message &message_, int timeout_=0, AMPS_ATOMIC_BASE_TYPE subscribeGeneration_=0)
Sends a Message to the connected AMPS server, performing only minimal validation and bypassing client...
Definition: ampsplusplus.hpp:5821
void deepCopy(const Field &orig_)
Makes self a deep copy of the original field.
Definition: Field.hpp:219
Command & setOrderBy(const char *orderBy_, size_t orderByLen_)
Definition: ampsplusplus.hpp:712
unsigned getAckTypeEnum() const
Decode self's "ack type" field and return the corresponding bitmask of values from AckType...
Definition: Message.hpp:1200
BookmarkStoreImpl * get()
Used to get a pointer to the implementation.
Definition: BookmarkStore.hpp:465
amps_handle getHandle()
Returns the underlying amps_handle for this client, to be used with amps_client_* functions from the ...
Definition: ampsplusplus.hpp:7768
AMPSDLL amps_result amps_client_attempt_reconnect(amps_handle client, unsigned version)
Manually invokes the user-supplied disconnect handler for this client.
AMPSDLL void amps_client_destroy(amps_handle handle)
Disconnects and destroys an AMPS client object.
void reset()
Clear all data from the builder.
Definition: ampsplusplus.hpp:9117
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:5978
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:7397
void setAckTimeout(const int ackTimeout_)
Sets the message queue ack timeout value.
Definition: ampsplusplus.hpp:8253
Command & setSowKeys(const std::string &sowKeys_)
Sets the SowKeys for the command.
Definition: ampsplusplus.hpp:642
Message & setPassword(const std::string &v)
Sets the value of the Password header for this Message.
Definition: Message.hpp:1456
bool getAutoAck(void) const
Returns the value of the queue auto-ack setting.
Definition: ampsplusplus.hpp:8202
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:6009
Definition: AMPSException.hpp:32
void setName(const std::string &name)
Sets the name of this client, assuming no name was provided previously.
Definition: ampsplusplus.hpp:5561
The interface for handling authentication with the AMPS server.
Definition: ampsplusplus.hpp:1006
amps_uint64_t publish(Message &message_)
Publish a message to an AMPS topic, returning the sequence number assigned by the publish store if on...
Definition: ampsplusplus.hpp:6356
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
Field getBookmark() const
Retrieves the value of the Bookmark header of the Message as a Field which references the underlying ...
Definition: Message.hpp:1234
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
static amps_uint64_t getUnsetSequence()
Method to return the value used to represent no such sequence.
Definition: ampsplusplus.hpp:1167
Command & setCorrelationId(const char *correlationId_, size_t correlationIdLen_)
Set the correlation ID for this command.
Definition: ampsplusplus.hpp:782
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:7043
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:6058
void setLastChanceMessageHandler(const AMPS::MessageHandler &messageHandler)
Sets the message handler called when no other handler matches.
Definition: ampsplusplus.hpp:7870
Message & assignSowKey(const std::string &v)
Assigns the value of the SowKey header for this Message without copying.
Definition: Message.hpp:1464
Message::Field getMostRecent(const Message::Field &subId_)
Returns the most recent bookmark from the log that ought to be used for (re-)subscriptions.
Definition: BookmarkStore.hpp:310
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:6609
The client and server are disconnected.
Definition: amps.h:249
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:7738
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:6782
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:9678
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:7084
const std::string & getName() const
Returns the name of this client passed in the constructor.
Definition: ampsplusplus.hpp:5568
Command is an encapsulation of a single AMPS command sent by the client.
Definition: ampsplusplus.hpp:472
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:7234
Message & setBatchSize(const std::string &v)
Sets the value of the BatchSize header for this Message.
Definition: Message.hpp:1233
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:6721
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:6909
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
const std::string & getConnectionName() const
Returns the connection name string of this client as generated by the server and returned when the cl...
Definition: ampsplusplus.hpp:5592
Message & assignSequence(const std::string &v)
Assigns the value of the Sequence header for this Message without copying.
Definition: Message.hpp:1462
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:8083
Command & setCorrelationId(const std::string &correlationId_)
Set the correlation ID for this command.
Definition: ampsplusplus.hpp:770
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:7558
iterator end(void)
Returns an iterator representing the end of the topic or subscription.
Definition: ampsplusplus.hpp:5436
bool getRetryOnDisconnect(void) const
Returns true if automatic retry of a command to AMPS after a reconnect is enabled.
Definition: ampsplusplus.hpp:8280
void flushAcks(void)
Sends any queued message queue ack messages to the server immediately.
Definition: ampsplusplus.hpp:8193
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:7116