ffi-nats-core 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ffi-nats-core.gemspec +8 -0
- data/lib/ffi/nats/core/version.rb +1 -1
- data/vendor/cnats/CMakeLists.txt +137 -0
- data/vendor/cnats/adapters/libevent.h +220 -0
- data/vendor/cnats/adapters/libuv.h +472 -0
- data/vendor/cnats/examples/CMakeLists.txt +56 -0
- data/vendor/cnats/examples/asynctimeout.c +83 -0
- data/vendor/cnats/examples/examples.h +322 -0
- data/vendor/cnats/examples/libevent-pub.c +136 -0
- data/vendor/cnats/examples/libevent-sub.c +104 -0
- data/vendor/cnats/examples/libuv-pub.c +120 -0
- data/vendor/cnats/examples/libuv-sub.c +114 -0
- data/vendor/cnats/examples/publisher.c +62 -0
- data/vendor/cnats/examples/queuegroup.c +132 -0
- data/vendor/cnats/examples/replier.c +149 -0
- data/vendor/cnats/examples/requestor.c +75 -0
- data/vendor/cnats/examples/subscriber.c +133 -0
- data/vendor/cnats/src/CMakeLists.txt +31 -0
- data/vendor/cnats/src/asynccb.c +66 -0
- data/vendor/cnats/src/asynccb.h +42 -0
- data/vendor/cnats/src/buf.c +246 -0
- data/vendor/cnats/src/buf.h +116 -0
- data/vendor/cnats/src/comsock.c +474 -0
- data/vendor/cnats/src/comsock.h +81 -0
- data/vendor/cnats/src/conn.c +2725 -0
- data/vendor/cnats/src/conn.h +75 -0
- data/vendor/cnats/src/err.h +31 -0
- data/vendor/cnats/src/gc.h +27 -0
- data/vendor/cnats/src/hash.c +725 -0
- data/vendor/cnats/src/hash.h +141 -0
- data/vendor/cnats/src/include/n-unix.h +56 -0
- data/vendor/cnats/src/include/n-win.h +59 -0
- data/vendor/cnats/src/mem.h +20 -0
- data/vendor/cnats/src/msg.c +155 -0
- data/vendor/cnats/src/msg.h +43 -0
- data/vendor/cnats/src/nats.c +1734 -0
- data/vendor/cnats/src/nats.h +2024 -0
- data/vendor/cnats/src/natsp.h +518 -0
- data/vendor/cnats/src/natstime.c +79 -0
- data/vendor/cnats/src/natstime.h +27 -0
- data/vendor/cnats/src/nuid.c +265 -0
- data/vendor/cnats/src/nuid.h +21 -0
- data/vendor/cnats/src/opts.c +1030 -0
- data/vendor/cnats/src/opts.h +19 -0
- data/vendor/cnats/src/parser.c +869 -0
- data/vendor/cnats/src/parser.h +87 -0
- data/vendor/cnats/src/pub.c +293 -0
- data/vendor/cnats/src/srvpool.c +380 -0
- data/vendor/cnats/src/srvpool.h +71 -0
- data/vendor/cnats/src/stats.c +54 -0
- data/vendor/cnats/src/stats.h +21 -0
- data/vendor/cnats/src/status.c +60 -0
- data/vendor/cnats/src/status.h +95 -0
- data/vendor/cnats/src/sub.c +956 -0
- data/vendor/cnats/src/sub.h +34 -0
- data/vendor/cnats/src/timer.c +86 -0
- data/vendor/cnats/src/timer.h +57 -0
- data/vendor/cnats/src/unix/cond.c +103 -0
- data/vendor/cnats/src/unix/mutex.c +107 -0
- data/vendor/cnats/src/unix/sock.c +105 -0
- data/vendor/cnats/src/unix/thread.c +162 -0
- data/vendor/cnats/src/url.c +134 -0
- data/vendor/cnats/src/url.h +24 -0
- data/vendor/cnats/src/util.c +823 -0
- data/vendor/cnats/src/util.h +75 -0
- data/vendor/cnats/src/version.h +29 -0
- data/vendor/cnats/src/version.h.in +29 -0
- data/vendor/cnats/src/win/cond.c +86 -0
- data/vendor/cnats/src/win/mutex.c +54 -0
- data/vendor/cnats/src/win/sock.c +158 -0
- data/vendor/cnats/src/win/strings.c +108 -0
- data/vendor/cnats/src/win/thread.c +180 -0
- data/vendor/cnats/test/CMakeLists.txt +35 -0
- data/vendor/cnats/test/certs/ca.pem +38 -0
- data/vendor/cnats/test/certs/client-cert.pem +30 -0
- data/vendor/cnats/test/certs/client-key.pem +51 -0
- data/vendor/cnats/test/certs/server-cert.pem +31 -0
- data/vendor/cnats/test/certs/server-key.pem +51 -0
- data/vendor/cnats/test/dylib/CMakeLists.txt +10 -0
- data/vendor/cnats/test/dylib/nonats.c +13 -0
- data/vendor/cnats/test/list.txt +125 -0
- data/vendor/cnats/test/test.c +11655 -0
- data/vendor/cnats/test/tls.conf +15 -0
- data/vendor/cnats/test/tlsverify.conf +19 -0
- metadata +83 -1
@@ -0,0 +1,71 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#ifndef SRVPOOL_H_
|
4
|
+
#define SRVPOOL_H_
|
5
|
+
|
6
|
+
#include "status.h"
|
7
|
+
#include "hash.h"
|
8
|
+
|
9
|
+
// Tracks individual backend servers.
|
10
|
+
typedef struct __natsSrv
|
11
|
+
{
|
12
|
+
natsUrl *url;
|
13
|
+
bool didConnect;
|
14
|
+
bool isImplicit;
|
15
|
+
int reconnects;
|
16
|
+
int64_t lastAttempt;
|
17
|
+
|
18
|
+
} natsSrv;
|
19
|
+
|
20
|
+
typedef struct __natsSrvPool
|
21
|
+
{
|
22
|
+
natsSrv **srvrs;
|
23
|
+
natsStrHash *urls;
|
24
|
+
int size;
|
25
|
+
int cap;
|
26
|
+
|
27
|
+
} natsSrvPool;
|
28
|
+
|
29
|
+
// This is defined in natsp.h, but natsp.h includes this file. Alternatively,
|
30
|
+
// we would need to move the defs above in natsp.h.
|
31
|
+
struct __natsOptions;
|
32
|
+
|
33
|
+
#define natsSrvPool_GetSize(p) ((p)->size)
|
34
|
+
#define natsSrvPool_GetSrv(p,i) ((p)->srvrs[(i)])
|
35
|
+
#define natsSrvPool_GetSrvUrl(p,i) (natsSrvPool_GetSrv((p),(i))->url)
|
36
|
+
#define natsSrvPool_SetSrvDidConnect(p,i,c) (natsSrvPool_GetSrv((p),(i))->didConnect=(c))
|
37
|
+
#define natsSrvPool_SetSrvReconnects(p,i,r) (natsSrvPool_GetSrv((p),(i))->reconnects=(r))
|
38
|
+
|
39
|
+
// Create the server pool using the options given.
|
40
|
+
// We will place a Url option first, followed by any
|
41
|
+
// Server Options. We will randomize the server pool unlesss
|
42
|
+
// the NoRandomize flag is set.
|
43
|
+
natsStatus
|
44
|
+
natsSrvPool_Create(natsSrvPool **newPool, struct __natsOptions *opts);
|
45
|
+
|
46
|
+
// Return the server from the pool that has the given 'url'. If the 'index'
|
47
|
+
// pointer is not NULL, will place at this location the index of the returned
|
48
|
+
// server in the pool.
|
49
|
+
natsSrv*
|
50
|
+
natsSrvPool_GetCurrentServer(natsSrvPool *pool, const natsUrl *url, int *index);
|
51
|
+
|
52
|
+
// Pop the current server and put onto the end of the list. Select head of list as long
|
53
|
+
// as number of reconnect attempts under MaxReconnect.
|
54
|
+
natsSrv*
|
55
|
+
natsSrvPool_GetNextServer(natsSrvPool *pool, struct __natsOptions *opts, const natsUrl *ncUrl);
|
56
|
+
|
57
|
+
// Go through the list of the given URLs and add them to the pool if not already
|
58
|
+
// present. If `doShuffle` is true, shuffles the pool if new URLs were added.
|
59
|
+
natsStatus
|
60
|
+
natsSrvPool_addNewURLs(natsSrvPool *pool, char **urls, int urlCount, bool doShuffle);
|
61
|
+
|
62
|
+
// Returns an array of servers (as a copy). User is responsible to free the memory.
|
63
|
+
natsStatus
|
64
|
+
natsSrvPool_GetServers(natsSrvPool *pool, bool implicitOnly, char ***servers, int *count);
|
65
|
+
|
66
|
+
// Destroy the pool, freeing up all memory used.
|
67
|
+
void
|
68
|
+
natsSrvPool_Destroy(natsSrvPool *pool);
|
69
|
+
|
70
|
+
|
71
|
+
#endif /* SRVPOOL_H_ */
|
@@ -0,0 +1,54 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include <stdlib.h>
|
6
|
+
#include "status.h"
|
7
|
+
#include "stats.h"
|
8
|
+
#include "mem.h"
|
9
|
+
|
10
|
+
natsStatus
|
11
|
+
natsStatistics_Create(natsStatistics **newStats)
|
12
|
+
{
|
13
|
+
natsStatistics *stats = NULL;
|
14
|
+
|
15
|
+
stats = (natsStatistics*) NATS_CALLOC(1, sizeof(natsStatistics));
|
16
|
+
if (stats == NULL)
|
17
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
18
|
+
|
19
|
+
*newStats = stats;
|
20
|
+
|
21
|
+
return NATS_OK;
|
22
|
+
}
|
23
|
+
|
24
|
+
natsStatus
|
25
|
+
natsStatistics_GetCounts(natsStatistics *stats,
|
26
|
+
uint64_t *inMsgs, uint64_t *inBytes,
|
27
|
+
uint64_t *outMsgs, uint64_t *outBytes,
|
28
|
+
uint64_t *reconnects)
|
29
|
+
{
|
30
|
+
if (stats == NULL)
|
31
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
32
|
+
|
33
|
+
if (inMsgs != NULL)
|
34
|
+
*inMsgs = stats->inMsgs;
|
35
|
+
if (inBytes != NULL)
|
36
|
+
*inBytes = stats->inBytes;
|
37
|
+
if (outMsgs != NULL)
|
38
|
+
*outMsgs = stats->outMsgs;
|
39
|
+
if (outBytes != NULL)
|
40
|
+
*outBytes = stats->outBytes;
|
41
|
+
if (reconnects != NULL)
|
42
|
+
*reconnects = stats->reconnects;
|
43
|
+
|
44
|
+
return NATS_OK;
|
45
|
+
}
|
46
|
+
|
47
|
+
void
|
48
|
+
natsStatistics_Destroy(natsStatistics *stats)
|
49
|
+
{
|
50
|
+
if (stats == NULL)
|
51
|
+
return;
|
52
|
+
|
53
|
+
NATS_FREE(stats);
|
54
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
|
4
|
+
#ifndef STATS_H_
|
5
|
+
#define STATS_H_
|
6
|
+
|
7
|
+
#include <stdint.h>
|
8
|
+
|
9
|
+
#include "status.h"
|
10
|
+
|
11
|
+
struct __natsStatistics
|
12
|
+
{
|
13
|
+
uint64_t inMsgs;
|
14
|
+
uint64_t outMsgs;
|
15
|
+
uint64_t inBytes;
|
16
|
+
uint64_t outBytes;
|
17
|
+
uint64_t reconnects;
|
18
|
+
|
19
|
+
};
|
20
|
+
|
21
|
+
#endif /* STATS_H_ */
|
@@ -0,0 +1,60 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
//#include <stdio.h>
|
6
|
+
//#include <stdlib.h>
|
7
|
+
|
8
|
+
//#include "status.h"
|
9
|
+
|
10
|
+
static const char *statusText[] = {
|
11
|
+
"OK",
|
12
|
+
|
13
|
+
"Error",
|
14
|
+
"Protocol Error",
|
15
|
+
"IO Error",
|
16
|
+
"Line too long",
|
17
|
+
|
18
|
+
"Connection Closed",
|
19
|
+
"No server available for connection",
|
20
|
+
"Stale Connection",
|
21
|
+
"Secure Connection not available",
|
22
|
+
"Secure Connection Required",
|
23
|
+
"Connection Disconnected",
|
24
|
+
"Authentication Violation",
|
25
|
+
|
26
|
+
"Not Permitted",
|
27
|
+
"Not Found",
|
28
|
+
|
29
|
+
"TCP Address missing",
|
30
|
+
|
31
|
+
"Invalid Subject",
|
32
|
+
"Invalid Argument",
|
33
|
+
"Invalid Subscription",
|
34
|
+
"Invalid Timeout",
|
35
|
+
|
36
|
+
"Illegal State",
|
37
|
+
|
38
|
+
"Slow Consumer, messages dropped",
|
39
|
+
|
40
|
+
"Maximum Payload Exceeded",
|
41
|
+
"Maximum Messages Delivered",
|
42
|
+
|
43
|
+
"Insufficient Buffer",
|
44
|
+
|
45
|
+
"No Memory",
|
46
|
+
|
47
|
+
"System Error",
|
48
|
+
|
49
|
+
"Timeout",
|
50
|
+
|
51
|
+
"Initialization Failed",
|
52
|
+
"Not Initialized",
|
53
|
+
|
54
|
+
"SSL Error"
|
55
|
+
};
|
56
|
+
|
57
|
+
const char*
|
58
|
+
natsStatus_GetText(natsStatus s) {
|
59
|
+
return statusText[(int) s];
|
60
|
+
}
|
@@ -0,0 +1,95 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#ifndef STATUS_H_
|
4
|
+
#define STATUS_H_
|
5
|
+
|
6
|
+
#ifdef __cplusplus
|
7
|
+
extern "C" {
|
8
|
+
#endif
|
9
|
+
|
10
|
+
/// The connection state
|
11
|
+
typedef enum
|
12
|
+
{
|
13
|
+
DISCONNECTED = 0, ///< The connection has been disconnected
|
14
|
+
CONNECTING, ///< The connection is in the process or connecting
|
15
|
+
CONNECTED, ///< The connection is connected
|
16
|
+
CLOSED, ///< The connection is closed
|
17
|
+
RECONNECTING ///< The connection is in the process or reconnecting
|
18
|
+
|
19
|
+
} natsConnStatus;
|
20
|
+
|
21
|
+
/// Status returned by most of the APIs
|
22
|
+
typedef enum
|
23
|
+
{
|
24
|
+
NATS_OK = 0, ///< Success
|
25
|
+
|
26
|
+
NATS_ERR, ///< Generic error
|
27
|
+
NATS_PROTOCOL_ERROR, ///< Error when parsing a protocol message,
|
28
|
+
/// or not getting the expected message.
|
29
|
+
NATS_IO_ERROR, ///< IO Error (network communication).
|
30
|
+
NATS_LINE_TOO_LONG, ///< The protocol message read from the socket
|
31
|
+
/// does not fit in the read buffer.
|
32
|
+
|
33
|
+
NATS_CONNECTION_CLOSED, ///< Operation on this connection failed because
|
34
|
+
/// the connection is closed.
|
35
|
+
NATS_NO_SERVER, ///< Unable to connect, the server could not be
|
36
|
+
/// reached or is not running.
|
37
|
+
NATS_STALE_CONNECTION, ///< The server closed our connection because it
|
38
|
+
/// did not receive PINGs at the expected interval.
|
39
|
+
NATS_SECURE_CONNECTION_WANTED, ///< The client is configured to use TLS, but the
|
40
|
+
/// server is not.
|
41
|
+
NATS_SECURE_CONNECTION_REQUIRED, ///< The server expects a TLS connection.
|
42
|
+
NATS_CONNECTION_DISCONNECTED, ///< The connection was disconnected. Depending on
|
43
|
+
/// the configuration, the connection may reconnect.
|
44
|
+
|
45
|
+
NATS_CONNECTION_AUTH_FAILED, ///< The connection failed due to authentication error.
|
46
|
+
NATS_NOT_PERMITTED, ///< The action is not permitted.
|
47
|
+
NATS_NOT_FOUND, ///< An action could not complete because something
|
48
|
+
/// was not found. So far, this is an internal error.
|
49
|
+
|
50
|
+
NATS_ADDRESS_MISSING, ///< Incorrect URL. For instance no host specified in
|
51
|
+
/// the URL.
|
52
|
+
|
53
|
+
NATS_INVALID_SUBJECT, ///< Invalid subject, for instance NULL or empty string.
|
54
|
+
NATS_INVALID_ARG, ///< An invalid argument is passed to a function. For
|
55
|
+
/// instance passing NULL to an API that does not
|
56
|
+
/// accept this value.
|
57
|
+
NATS_INVALID_SUBSCRIPTION, ///< The call to a subscription function fails because
|
58
|
+
/// the subscription has previously been closed.
|
59
|
+
NATS_INVALID_TIMEOUT, ///< Timeout must be positive numbers.
|
60
|
+
|
61
|
+
NATS_ILLEGAL_STATE, ///< An unexpected state, for instance calling
|
62
|
+
/// #natsSubscription_NextMsg() on an asynchronous
|
63
|
+
/// subscriber.
|
64
|
+
|
65
|
+
NATS_SLOW_CONSUMER, ///< The maximum number of messages waiting to be
|
66
|
+
/// delivered has been reached. Messages are dropped.
|
67
|
+
|
68
|
+
NATS_MAX_PAYLOAD, ///< Attempt to send a payload larger than the maximum
|
69
|
+
/// allowed by the NATS Server.
|
70
|
+
NATS_MAX_DELIVERED_MSGS, ///< Attempt to receive more messages than allowed, for
|
71
|
+
/// instance because of #natsSubscription_AutoUnsubscribe().
|
72
|
+
|
73
|
+
NATS_INSUFFICIENT_BUFFER, ///< A buffer is not large enough to accommodate the data.
|
74
|
+
|
75
|
+
NATS_NO_MEMORY, ///< An operation could not complete because of insufficient
|
76
|
+
/// memory.
|
77
|
+
|
78
|
+
NATS_SYS_ERROR, ///< Some system function returned an error.
|
79
|
+
|
80
|
+
NATS_TIMEOUT, ///< An operation timed-out. For instance
|
81
|
+
/// #natsSubscription_NextMsg().
|
82
|
+
|
83
|
+
NATS_FAILED_TO_INITIALIZE, ///< The library failed to initialize.
|
84
|
+
NATS_NOT_INITIALIZED, ///< The library is not yet initialized.
|
85
|
+
|
86
|
+
NATS_SSL_ERROR ///< An SSL error occurred when trying to establish a
|
87
|
+
/// connection.
|
88
|
+
|
89
|
+
} natsStatus;
|
90
|
+
|
91
|
+
#ifdef __cplusplus
|
92
|
+
}
|
93
|
+
#endif
|
94
|
+
|
95
|
+
#endif /* STATUS_H_ */
|
@@ -0,0 +1,956 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include <string.h>
|
6
|
+
#include <stdio.h>
|
7
|
+
|
8
|
+
#include "mem.h"
|
9
|
+
#include "conn.h"
|
10
|
+
#include "sub.h"
|
11
|
+
#include "msg.h"
|
12
|
+
#include "util.h"
|
13
|
+
|
14
|
+
#ifdef DEV_MODE
|
15
|
+
|
16
|
+
static void _retain(natsSubscription *sub) { sub->refs++; }
|
17
|
+
static void _release(natsSubscription *sub) { sub->refs--; }
|
18
|
+
|
19
|
+
void natsSub_Lock(natsSubscription *sub) { natsMutex_Lock(sub->mu); }
|
20
|
+
void natsSub_Unlock(natsSubscription *sub) { natsMutex_Unlock(sub->mu); }
|
21
|
+
|
22
|
+
#else
|
23
|
+
|
24
|
+
#define _retain(s) ((s)->refs++)
|
25
|
+
#define _release(s) ((s)->refs--)
|
26
|
+
|
27
|
+
#endif // DEV_MODE
|
28
|
+
|
29
|
+
#define SUB_DLV_WORKER_LOCK(s) if ((s)->libDlvWorker != NULL) \
|
30
|
+
natsMutex_Lock((s)->libDlvWorker->lock)
|
31
|
+
|
32
|
+
#define SUB_DLV_WORKER_UNLOCK(s) if ((s)->libDlvWorker != NULL) \
|
33
|
+
natsMutex_Unlock((s)->libDlvWorker->lock)
|
34
|
+
|
35
|
+
static void
|
36
|
+
_freeSubscription(natsSubscription *sub)
|
37
|
+
{
|
38
|
+
natsMsg *m;
|
39
|
+
|
40
|
+
if (sub == NULL)
|
41
|
+
return;
|
42
|
+
|
43
|
+
while ((m = sub->msgList.head) != NULL)
|
44
|
+
{
|
45
|
+
sub->msgList.head = m->next;
|
46
|
+
natsMsg_Destroy(m);
|
47
|
+
}
|
48
|
+
|
49
|
+
NATS_FREE(sub->subject);
|
50
|
+
NATS_FREE(sub->queue);
|
51
|
+
|
52
|
+
if (sub->deliverMsgsThread != NULL)
|
53
|
+
{
|
54
|
+
natsThread_Detach(sub->deliverMsgsThread);
|
55
|
+
natsThread_Destroy(sub->deliverMsgsThread);
|
56
|
+
}
|
57
|
+
natsTimer_Destroy(sub->timeoutTimer);
|
58
|
+
natsCondition_Destroy(sub->cond);
|
59
|
+
natsMutex_Destroy(sub->mu);
|
60
|
+
|
61
|
+
natsConn_release(sub->conn);
|
62
|
+
|
63
|
+
NATS_FREE(sub);
|
64
|
+
}
|
65
|
+
|
66
|
+
void
|
67
|
+
natsSub_retain(natsSubscription *sub)
|
68
|
+
{
|
69
|
+
natsSub_Lock(sub);
|
70
|
+
|
71
|
+
sub->refs++;
|
72
|
+
|
73
|
+
natsSub_Unlock(sub);
|
74
|
+
}
|
75
|
+
void
|
76
|
+
|
77
|
+
natsSub_release(natsSubscription *sub)
|
78
|
+
{
|
79
|
+
int refs = 0;
|
80
|
+
|
81
|
+
if (sub == NULL)
|
82
|
+
return;
|
83
|
+
|
84
|
+
natsSub_Lock(sub);
|
85
|
+
|
86
|
+
refs = --(sub->refs);
|
87
|
+
|
88
|
+
natsSub_Unlock(sub);
|
89
|
+
|
90
|
+
if (refs == 0)
|
91
|
+
_freeSubscription(sub);
|
92
|
+
}
|
93
|
+
|
94
|
+
// _deliverMsgs is used to deliver messages to asynchronous subscribers.
|
95
|
+
void
|
96
|
+
natsSub_deliverMsgs(void *arg)
|
97
|
+
{
|
98
|
+
natsSubscription *sub = (natsSubscription*) arg;
|
99
|
+
natsConnection *nc = sub->conn;
|
100
|
+
natsMsgHandler mcb = sub->msgCb;
|
101
|
+
void *mcbClosure = sub->msgCbClosure;
|
102
|
+
uint64_t delivered;
|
103
|
+
uint64_t max;
|
104
|
+
natsMsg *msg;
|
105
|
+
int64_t timeout;
|
106
|
+
natsStatus s = NATS_OK;
|
107
|
+
|
108
|
+
// This just servers as a barrier for the creation of this thread.
|
109
|
+
natsConn_Lock(nc);
|
110
|
+
natsConn_Unlock(nc);
|
111
|
+
|
112
|
+
natsSub_Lock(sub);
|
113
|
+
timeout = sub->timeout;
|
114
|
+
natsSub_Unlock(sub);
|
115
|
+
|
116
|
+
while (true)
|
117
|
+
{
|
118
|
+
natsSub_Lock(sub);
|
119
|
+
|
120
|
+
s = NATS_OK;
|
121
|
+
while (((msg = sub->msgList.head) == NULL) && !(sub->closed) && (s != NATS_TIMEOUT))
|
122
|
+
{
|
123
|
+
sub->inWait++;
|
124
|
+
if (timeout != 0)
|
125
|
+
s = natsCondition_TimedWait(sub->cond, sub->mu, timeout);
|
126
|
+
else
|
127
|
+
natsCondition_Wait(sub->cond, sub->mu);
|
128
|
+
sub->inWait--;
|
129
|
+
}
|
130
|
+
|
131
|
+
if (sub->closed)
|
132
|
+
{
|
133
|
+
natsSub_Unlock(sub);
|
134
|
+
break;
|
135
|
+
}
|
136
|
+
|
137
|
+
// Will happen with timeout subscription
|
138
|
+
if (msg == NULL)
|
139
|
+
{
|
140
|
+
natsSub_Unlock(sub);
|
141
|
+
// If subscription timed-out, invoke callback with NULL message.
|
142
|
+
if (s == NATS_TIMEOUT)
|
143
|
+
(*mcb)(nc, sub, NULL, mcbClosure);
|
144
|
+
continue;
|
145
|
+
}
|
146
|
+
|
147
|
+
delivered = ++(sub->delivered);
|
148
|
+
|
149
|
+
sub->msgList.head = msg->next;
|
150
|
+
|
151
|
+
if (sub->msgList.tail == msg)
|
152
|
+
sub->msgList.tail = NULL;
|
153
|
+
|
154
|
+
sub->msgList.msgs--;
|
155
|
+
sub->msgList.bytes -= msg->dataLen;
|
156
|
+
|
157
|
+
msg->next = NULL;
|
158
|
+
|
159
|
+
// Capture this under lock.
|
160
|
+
max = sub->max;
|
161
|
+
|
162
|
+
natsSub_Unlock(sub);
|
163
|
+
|
164
|
+
if ((max == 0) || (delivered <= max))
|
165
|
+
{
|
166
|
+
(*mcb)(nc, sub, msg, mcbClosure);
|
167
|
+
}
|
168
|
+
else
|
169
|
+
{
|
170
|
+
// We need to destroy the message since the user can't do it
|
171
|
+
natsMsg_Destroy(msg);
|
172
|
+
}
|
173
|
+
|
174
|
+
// Don't do 'else' because we need to remove when we have hit
|
175
|
+
// the max (after the callback returns).
|
176
|
+
if ((max > 0) && (delivered >= max))
|
177
|
+
{
|
178
|
+
// If we have hit the max for delivered msgs, remove sub.
|
179
|
+
natsConn_removeSubscription(nc, sub, true);
|
180
|
+
break;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
natsSub_release(sub);
|
185
|
+
}
|
186
|
+
|
187
|
+
void
|
188
|
+
natsSub_close(natsSubscription *sub, bool connectionClosed)
|
189
|
+
{
|
190
|
+
natsMsgDlvWorker *ldw = NULL;
|
191
|
+
|
192
|
+
natsSub_Lock(sub);
|
193
|
+
|
194
|
+
SUB_DLV_WORKER_LOCK(sub);
|
195
|
+
|
196
|
+
if (!(sub->closed))
|
197
|
+
{
|
198
|
+
sub->closed = true;
|
199
|
+
sub->connClosed = connectionClosed;
|
200
|
+
|
201
|
+
if (sub->libDlvWorker != NULL)
|
202
|
+
{
|
203
|
+
// If this is a subscription with timeout, stop the timer.
|
204
|
+
if (sub->timeout != 0)
|
205
|
+
natsTimer_Stop(sub->timeoutTimer);
|
206
|
+
|
207
|
+
// Post a control message to wake-up the worker which will
|
208
|
+
// ensure that all pending messages for this subscription
|
209
|
+
// are removed and the subscription will ultimately be
|
210
|
+
// released in the worker thread.
|
211
|
+
natsLib_msgDeliveryPostControlMsg(sub);
|
212
|
+
}
|
213
|
+
else
|
214
|
+
natsCondition_Broadcast(sub->cond);
|
215
|
+
}
|
216
|
+
|
217
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
218
|
+
|
219
|
+
natsSub_Unlock(sub);
|
220
|
+
}
|
221
|
+
|
222
|
+
static void
|
223
|
+
_asyncTimeoutCb(natsTimer *timer, void* closure)
|
224
|
+
{
|
225
|
+
natsSubscription *sub = (natsSubscription*) closure;
|
226
|
+
|
227
|
+
// Should not happen, but in case
|
228
|
+
if (sub->libDlvWorker == NULL)
|
229
|
+
return;
|
230
|
+
|
231
|
+
SUB_DLV_WORKER_LOCK(sub);
|
232
|
+
|
233
|
+
// If the subscription is closed, or if we are prevented from posting
|
234
|
+
// a "timeout" control message, do nothing.
|
235
|
+
if (!sub->closed && !sub->timedOut && !sub->timeoutSuspended)
|
236
|
+
{
|
237
|
+
// Prevent from scheduling another control message while we are not
|
238
|
+
// done with previous one.
|
239
|
+
sub->timedOut = true;
|
240
|
+
|
241
|
+
// Set the timer to a very high value, it will be reset from the
|
242
|
+
// worker thread.
|
243
|
+
natsTimer_Reset(sub->timeoutTimer, 60*60*1000);
|
244
|
+
|
245
|
+
// Post a control message to the worker thread.
|
246
|
+
natsLib_msgDeliveryPostControlMsg(sub);
|
247
|
+
}
|
248
|
+
|
249
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
250
|
+
}
|
251
|
+
|
252
|
+
static void
|
253
|
+
_asyncTimeoutStopCb(natsTimer *timer, void* closure)
|
254
|
+
{
|
255
|
+
natsSubscription *sub = (natsSubscription*) closure;
|
256
|
+
|
257
|
+
natsSub_release(sub);
|
258
|
+
}
|
259
|
+
|
260
|
+
natsStatus
|
261
|
+
natsSub_create(natsSubscription **newSub, natsConnection *nc, const char *subj,
|
262
|
+
const char *queueGroup, int64_t timeout, natsMsgHandler cb, void *cbClosure)
|
263
|
+
{
|
264
|
+
natsStatus s = NATS_OK;
|
265
|
+
natsSubscription *sub = NULL;
|
266
|
+
|
267
|
+
sub = (natsSubscription*) NATS_CALLOC(1, sizeof(natsSubscription));
|
268
|
+
if (sub == NULL)
|
269
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
270
|
+
|
271
|
+
s = natsMutex_Create(&(sub->mu));
|
272
|
+
if (s != NATS_OK)
|
273
|
+
{
|
274
|
+
NATS_FREE(sub);
|
275
|
+
return NATS_UPDATE_ERR_STACK(s);
|
276
|
+
}
|
277
|
+
|
278
|
+
natsConn_retain(nc);
|
279
|
+
|
280
|
+
sub->refs = 1;
|
281
|
+
sub->conn = nc;
|
282
|
+
sub->timeout = timeout;
|
283
|
+
sub->msgCb = cb;
|
284
|
+
sub->msgCbClosure = cbClosure;
|
285
|
+
sub->msgsLimit = nc->opts->maxPendingMsgs;
|
286
|
+
sub->bytesLimit = sub->msgsLimit * 1024;
|
287
|
+
|
288
|
+
if (sub->bytesLimit <= 0)
|
289
|
+
return nats_setError(NATS_INVALID_ARG, "Invalid bytes limit of %d", sub->bytesLimit);
|
290
|
+
|
291
|
+
sub->subject = NATS_STRDUP(subj);
|
292
|
+
if (sub->subject == NULL)
|
293
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
294
|
+
|
295
|
+
if ((s == NATS_OK) && (queueGroup != NULL) && (strlen(queueGroup) > 0))
|
296
|
+
{
|
297
|
+
sub->queue = NATS_STRDUP(queueGroup);
|
298
|
+
if (sub->queue == NULL)
|
299
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
300
|
+
}
|
301
|
+
if (s == NATS_OK)
|
302
|
+
s = natsCondition_Create(&(sub->cond));
|
303
|
+
if ((s == NATS_OK) && (cb != NULL))
|
304
|
+
{
|
305
|
+
if (!(nc->opts->libMsgDelivery))
|
306
|
+
{
|
307
|
+
// Let's not rely on the created thread acquiring the lock that
|
308
|
+
// would make it safe to retain only on success.
|
309
|
+
_retain(sub);
|
310
|
+
|
311
|
+
// If we have an async callback, start up a sub specific
|
312
|
+
// thread to deliver the messages.
|
313
|
+
s = natsThread_Create(&(sub->deliverMsgsThread), natsSub_deliverMsgs,
|
314
|
+
(void*) sub);
|
315
|
+
if (s != NATS_OK)
|
316
|
+
_release(sub);
|
317
|
+
}
|
318
|
+
else
|
319
|
+
{
|
320
|
+
_retain(sub);
|
321
|
+
s = natsLib_msgDeliveryAssignWorker(sub);
|
322
|
+
if ((s == NATS_OK) && (timeout > 0))
|
323
|
+
{
|
324
|
+
_retain(sub);
|
325
|
+
s = natsTimer_Create(&sub->timeoutTimer, _asyncTimeoutCb,
|
326
|
+
_asyncTimeoutStopCb, timeout, (void*) sub);
|
327
|
+
if (s != NATS_OK)
|
328
|
+
_release(sub);
|
329
|
+
}
|
330
|
+
if (s != NATS_OK)
|
331
|
+
_release(sub);
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
if (s == NATS_OK)
|
336
|
+
*newSub = sub;
|
337
|
+
else
|
338
|
+
natsSub_release(sub);
|
339
|
+
|
340
|
+
return NATS_UPDATE_ERR_STACK(s);
|
341
|
+
}
|
342
|
+
|
343
|
+
/*
|
344
|
+
* Expresses interest in the given subject. The subject can have wildcards
|
345
|
+
* (partial:*, full:>). Messages will be delivered to the associated
|
346
|
+
* natsMsgHandler. If no natsMsgHandler is given, the subscription is a
|
347
|
+
* synchronous subscription and can be polled via natsSubscription_NextMsg().
|
348
|
+
*/
|
349
|
+
natsStatus
|
350
|
+
natsConnection_Subscribe(natsSubscription **sub, natsConnection *nc, const char *subject,
|
351
|
+
natsMsgHandler cb, void *cbClosure)
|
352
|
+
{
|
353
|
+
natsStatus s;
|
354
|
+
|
355
|
+
if (cb == NULL)
|
356
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
357
|
+
|
358
|
+
s = natsConn_subscribe(sub, nc, subject, NULL, 0, cb, cbClosure);
|
359
|
+
|
360
|
+
return NATS_UPDATE_ERR_STACK(s);
|
361
|
+
}
|
362
|
+
|
363
|
+
/*
|
364
|
+
* Similar to natsConnection_Subscribe() except that a timeout is given.
|
365
|
+
* If the subscription has not receive any message for the given timeout,
|
366
|
+
* the callback is invoked with a `NULL` message. The subscription can
|
367
|
+
* then be destroyed, if not, the callback will be invoked again when
|
368
|
+
* a message is received or the subscription times-out again.
|
369
|
+
*/
|
370
|
+
natsStatus
|
371
|
+
natsConnection_SubscribeTimeout(natsSubscription **sub, natsConnection *nc, const char *subject,
|
372
|
+
int64_t timeout, natsMsgHandler cb, void *cbClosure)
|
373
|
+
{
|
374
|
+
natsStatus s;
|
375
|
+
|
376
|
+
if ((cb == NULL) || (timeout <= 0))
|
377
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
378
|
+
|
379
|
+
s = natsConn_subscribe(sub, nc, subject, NULL, timeout, cb, cbClosure);
|
380
|
+
|
381
|
+
return NATS_UPDATE_ERR_STACK(s);
|
382
|
+
}
|
383
|
+
|
384
|
+
|
385
|
+
/*
|
386
|
+
* natsSubscribeSync is syntactic sugar for natsSubscribe(&sub, nc, subject, NULL).
|
387
|
+
*/
|
388
|
+
natsStatus
|
389
|
+
natsConnection_SubscribeSync(natsSubscription **sub, natsConnection *nc, const char *subject)
|
390
|
+
{
|
391
|
+
natsStatus s;
|
392
|
+
|
393
|
+
s = natsConn_subscribe(sub, nc, subject, NULL, 0, NULL, NULL);
|
394
|
+
|
395
|
+
return NATS_UPDATE_ERR_STACK(s);
|
396
|
+
}
|
397
|
+
|
398
|
+
/*
|
399
|
+
* Creates an asynchronous queue subscriber on the given subject.
|
400
|
+
* All subscribers with the same queue name will form the queue group and
|
401
|
+
* only one member of the group will be selected to receive any given
|
402
|
+
* message asynchronously.
|
403
|
+
*/
|
404
|
+
natsStatus
|
405
|
+
natsConnection_QueueSubscribe(natsSubscription **sub, natsConnection *nc,
|
406
|
+
const char *subject, const char *queueGroup,
|
407
|
+
natsMsgHandler cb, void *cbClosure)
|
408
|
+
{
|
409
|
+
natsStatus s;
|
410
|
+
|
411
|
+
if ((queueGroup == NULL) || (strlen(queueGroup) == 0) || (cb == NULL))
|
412
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
413
|
+
|
414
|
+
s = natsConn_subscribe(sub, nc, subject, queueGroup, 0, cb, cbClosure);
|
415
|
+
|
416
|
+
return NATS_UPDATE_ERR_STACK(s);
|
417
|
+
}
|
418
|
+
|
419
|
+
/*
|
420
|
+
* Similar to natsConnection_QueueSubscribe() except that a timeout is given.
|
421
|
+
* If the subscription has not receive any message for the given timeout,
|
422
|
+
* the callback is invoked with a `NULL` message. The subscription can
|
423
|
+
* then be destroyed, if not, the callback will be invoked again when
|
424
|
+
* a message is received or the subscription times-out again.
|
425
|
+
*/
|
426
|
+
natsStatus
|
427
|
+
natsConnection_QueueSubscribeTimeout(natsSubscription **sub, natsConnection *nc,
|
428
|
+
const char *subject, const char *queueGroup,
|
429
|
+
int64_t timeout, natsMsgHandler cb, void *cbClosure)
|
430
|
+
{
|
431
|
+
natsStatus s;
|
432
|
+
|
433
|
+
if ((queueGroup == NULL) || (strlen(queueGroup) == 0) || (cb == NULL)
|
434
|
+
|| (timeout <= 0))
|
435
|
+
{
|
436
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
437
|
+
}
|
438
|
+
|
439
|
+
s = natsConn_subscribe(sub, nc, subject, queueGroup, timeout, cb, cbClosure);
|
440
|
+
|
441
|
+
return NATS_UPDATE_ERR_STACK(s);
|
442
|
+
}
|
443
|
+
|
444
|
+
/*
|
445
|
+
* Similar to natsQueueSubscribe except that the subscription is synchronous.
|
446
|
+
*/
|
447
|
+
natsStatus
|
448
|
+
natsConnection_QueueSubscribeSync(natsSubscription **sub, natsConnection *nc,
|
449
|
+
const char *subject, const char *queueGroup)
|
450
|
+
{
|
451
|
+
natsStatus s;
|
452
|
+
|
453
|
+
if ((queueGroup == NULL) || (strlen(queueGroup) == 0))
|
454
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
455
|
+
|
456
|
+
s = natsConn_subscribe(sub, nc, subject, queueGroup, 0, NULL, NULL);
|
457
|
+
|
458
|
+
return NATS_UPDATE_ERR_STACK(s);
|
459
|
+
}
|
460
|
+
|
461
|
+
/*
|
462
|
+
* By default, messages that arrive are not immediately delivered. This
|
463
|
+
* generally improves performance. However, in case of request-reply,
|
464
|
+
* this delay has a negative impact. In such case, call this function
|
465
|
+
* to have the subscriber be notified immediately each time a message
|
466
|
+
* arrives.
|
467
|
+
*
|
468
|
+
* DEPRECATED
|
469
|
+
*/
|
470
|
+
natsStatus
|
471
|
+
natsSubscription_NoDeliveryDelay(natsSubscription *sub)
|
472
|
+
{
|
473
|
+
if (sub == NULL)
|
474
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
475
|
+
|
476
|
+
return NATS_OK;
|
477
|
+
}
|
478
|
+
|
479
|
+
|
480
|
+
/*
|
481
|
+
* Return the next message available to a synchronous subscriber or block until
|
482
|
+
* one is available. A timeout can be used to return when no message has been
|
483
|
+
* delivered.
|
484
|
+
*/
|
485
|
+
natsStatus
|
486
|
+
natsSubscription_NextMsg(natsMsg **nextMsg, natsSubscription *sub, int64_t timeout)
|
487
|
+
{
|
488
|
+
natsStatus s = NATS_OK;
|
489
|
+
natsConnection *nc = NULL;
|
490
|
+
natsMsg *msg = NULL;
|
491
|
+
bool removeSub = false;
|
492
|
+
int64_t target = 0;
|
493
|
+
|
494
|
+
if ((sub == NULL) || (nextMsg == NULL))
|
495
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
496
|
+
|
497
|
+
natsSub_Lock(sub);
|
498
|
+
|
499
|
+
if (sub->connClosed)
|
500
|
+
{
|
501
|
+
natsSub_Unlock(sub);
|
502
|
+
|
503
|
+
return nats_setDefaultError(NATS_CONNECTION_CLOSED);
|
504
|
+
}
|
505
|
+
if (sub->closed)
|
506
|
+
{
|
507
|
+
if ((sub->max > 0) && (sub->delivered >= sub->max))
|
508
|
+
s = NATS_MAX_DELIVERED_MSGS;
|
509
|
+
else
|
510
|
+
s = NATS_INVALID_SUBSCRIPTION;
|
511
|
+
|
512
|
+
natsSub_Unlock(sub);
|
513
|
+
|
514
|
+
return nats_setDefaultError(s);
|
515
|
+
}
|
516
|
+
if (sub->msgCb != NULL)
|
517
|
+
{
|
518
|
+
natsSub_Unlock(sub);
|
519
|
+
|
520
|
+
return nats_setDefaultError(NATS_ILLEGAL_STATE);
|
521
|
+
}
|
522
|
+
if (sub->slowConsumer)
|
523
|
+
{
|
524
|
+
sub->slowConsumer = false;
|
525
|
+
natsSub_Unlock(sub);
|
526
|
+
|
527
|
+
return nats_setDefaultError(NATS_SLOW_CONSUMER);
|
528
|
+
}
|
529
|
+
|
530
|
+
nc = sub->conn;
|
531
|
+
|
532
|
+
if (timeout > 0)
|
533
|
+
{
|
534
|
+
sub->inWait++;
|
535
|
+
|
536
|
+
while ((sub->msgList.msgs == 0)
|
537
|
+
&& (s != NATS_TIMEOUT)
|
538
|
+
&& !(sub->closed))
|
539
|
+
{
|
540
|
+
if (target == 0)
|
541
|
+
target = nats_Now() + timeout;
|
542
|
+
|
543
|
+
s = natsCondition_AbsoluteTimedWait(sub->cond, sub->mu, target);
|
544
|
+
if (s != NATS_OK)
|
545
|
+
s = nats_setDefaultError(s);
|
546
|
+
}
|
547
|
+
|
548
|
+
sub->inWait--;
|
549
|
+
|
550
|
+
if (sub->closed)
|
551
|
+
s = nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
552
|
+
}
|
553
|
+
else
|
554
|
+
{
|
555
|
+
s = (sub->msgList.msgs == 0 ? NATS_TIMEOUT : NATS_OK);
|
556
|
+
if (s != NATS_OK)
|
557
|
+
s = nats_setDefaultError(s);
|
558
|
+
}
|
559
|
+
|
560
|
+
if (s == NATS_OK)
|
561
|
+
{
|
562
|
+
msg = sub->msgList.head;
|
563
|
+
|
564
|
+
sub->msgList.head = msg->next;
|
565
|
+
|
566
|
+
if (sub->msgList.tail == msg)
|
567
|
+
sub->msgList.tail = NULL;
|
568
|
+
|
569
|
+
sub->msgList.msgs--;
|
570
|
+
sub->msgList.bytes -= msg->dataLen;
|
571
|
+
|
572
|
+
msg->next = NULL;
|
573
|
+
|
574
|
+
sub->delivered++;
|
575
|
+
if (sub->max > 0)
|
576
|
+
{
|
577
|
+
if (sub->delivered > sub->max)
|
578
|
+
s = nats_setDefaultError(NATS_MAX_DELIVERED_MSGS);
|
579
|
+
else if (sub->delivered == sub->max)
|
580
|
+
removeSub = true;
|
581
|
+
}
|
582
|
+
}
|
583
|
+
if (s == NATS_OK)
|
584
|
+
*nextMsg = msg;
|
585
|
+
|
586
|
+
natsSub_Unlock(sub);
|
587
|
+
|
588
|
+
if (removeSub)
|
589
|
+
natsConn_removeSubscription(nc, sub, true);
|
590
|
+
|
591
|
+
return NATS_UPDATE_ERR_STACK(s);
|
592
|
+
}
|
593
|
+
|
594
|
+
static natsStatus
|
595
|
+
_unsubscribe(natsSubscription *sub, int max)
|
596
|
+
{
|
597
|
+
natsStatus s = NATS_OK;
|
598
|
+
natsConnection *nc = NULL;
|
599
|
+
|
600
|
+
if (sub == NULL)
|
601
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
602
|
+
|
603
|
+
natsSub_Lock(sub);
|
604
|
+
|
605
|
+
if (sub->connClosed)
|
606
|
+
s = NATS_CONNECTION_CLOSED;
|
607
|
+
else if (sub->closed)
|
608
|
+
s = NATS_INVALID_SUBSCRIPTION;
|
609
|
+
|
610
|
+
if (s != NATS_OK)
|
611
|
+
{
|
612
|
+
natsSub_Unlock(sub);
|
613
|
+
return nats_setDefaultError(s);
|
614
|
+
}
|
615
|
+
|
616
|
+
nc = sub->conn;
|
617
|
+
_retain(sub);
|
618
|
+
|
619
|
+
natsSub_Unlock(sub);
|
620
|
+
|
621
|
+
s = natsConn_unsubscribe(nc, sub, max);
|
622
|
+
|
623
|
+
natsSub_release(sub);
|
624
|
+
|
625
|
+
return NATS_UPDATE_ERR_STACK(s);
|
626
|
+
}
|
627
|
+
|
628
|
+
/*
|
629
|
+
* Removes interest on the subject. Asynchronous subscription may still have
|
630
|
+
* a callback in progress, in that case, the subscription will still be valid
|
631
|
+
* until the callback returns.
|
632
|
+
*/
|
633
|
+
natsStatus
|
634
|
+
natsSubscription_Unsubscribe(natsSubscription *sub)
|
635
|
+
{
|
636
|
+
natsStatus s = _unsubscribe(sub, 0);
|
637
|
+
return NATS_UPDATE_ERR_STACK(s);
|
638
|
+
}
|
639
|
+
|
640
|
+
/*
|
641
|
+
* This call issues an automatic natsSubscription_Unsubscribe that is
|
642
|
+
* processed by the server when 'max' messages have been received.
|
643
|
+
* This can be useful when sending a request to an unknown number
|
644
|
+
* of subscribers.
|
645
|
+
*/
|
646
|
+
natsStatus
|
647
|
+
natsSubscription_AutoUnsubscribe(natsSubscription *sub, int max)
|
648
|
+
{
|
649
|
+
natsStatus s = _unsubscribe(sub, max);
|
650
|
+
return NATS_UPDATE_ERR_STACK(s);
|
651
|
+
}
|
652
|
+
|
653
|
+
/*
|
654
|
+
* Returns the number of queued messages in the client for this subscription.
|
655
|
+
*/
|
656
|
+
natsStatus
|
657
|
+
natsSubscription_QueuedMsgs(natsSubscription *sub, uint64_t *queuedMsgs)
|
658
|
+
{
|
659
|
+
natsStatus s;
|
660
|
+
int msgs = 0;
|
661
|
+
|
662
|
+
if (queuedMsgs == NULL)
|
663
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
664
|
+
|
665
|
+
s = natsSubscription_GetPending(sub, &msgs, NULL);
|
666
|
+
if (s == NATS_OK)
|
667
|
+
*queuedMsgs = (uint64_t) msgs;
|
668
|
+
|
669
|
+
return s;
|
670
|
+
}
|
671
|
+
|
672
|
+
natsStatus
|
673
|
+
natsSubscription_GetPending(natsSubscription *sub, int *msgs, int *bytes)
|
674
|
+
{
|
675
|
+
if (sub == NULL)
|
676
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
677
|
+
|
678
|
+
natsSub_Lock(sub);
|
679
|
+
|
680
|
+
if (sub->closed)
|
681
|
+
{
|
682
|
+
natsSub_Unlock(sub);
|
683
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
684
|
+
}
|
685
|
+
|
686
|
+
SUB_DLV_WORKER_LOCK(sub);
|
687
|
+
|
688
|
+
if (msgs != NULL)
|
689
|
+
*msgs = sub->msgList.msgs;
|
690
|
+
|
691
|
+
if (bytes != NULL)
|
692
|
+
*bytes = sub->msgList.bytes;
|
693
|
+
|
694
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
695
|
+
|
696
|
+
natsSub_Unlock(sub);
|
697
|
+
|
698
|
+
return NATS_OK;
|
699
|
+
}
|
700
|
+
|
701
|
+
natsStatus
|
702
|
+
natsSubscription_SetPendingLimits(natsSubscription *sub, int msgLimit, int bytesLimit)
|
703
|
+
{
|
704
|
+
if (sub == NULL)
|
705
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
706
|
+
|
707
|
+
if ((msgLimit == 0) || (bytesLimit == 0))
|
708
|
+
return nats_setError(NATS_INVALID_ARG, "%s",
|
709
|
+
"Limits must be either > 0 or negative to specify no limit");
|
710
|
+
|
711
|
+
natsSub_Lock(sub);
|
712
|
+
|
713
|
+
if (sub->closed)
|
714
|
+
{
|
715
|
+
natsSub_Unlock(sub);
|
716
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
717
|
+
}
|
718
|
+
|
719
|
+
SUB_DLV_WORKER_LOCK(sub);
|
720
|
+
|
721
|
+
sub->msgsLimit = msgLimit;
|
722
|
+
sub->bytesLimit = bytesLimit;
|
723
|
+
|
724
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
725
|
+
|
726
|
+
natsSub_Unlock(sub);
|
727
|
+
|
728
|
+
return NATS_OK;
|
729
|
+
}
|
730
|
+
|
731
|
+
natsStatus
|
732
|
+
natsSubscription_GetPendingLimits(natsSubscription *sub, int *msgLimit, int *bytesLimit)
|
733
|
+
{
|
734
|
+
if (sub == NULL)
|
735
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
736
|
+
|
737
|
+
natsSub_Lock(sub);
|
738
|
+
|
739
|
+
if (sub->closed)
|
740
|
+
{
|
741
|
+
natsSub_Unlock(sub);
|
742
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
743
|
+
}
|
744
|
+
|
745
|
+
SUB_DLV_WORKER_LOCK(sub);
|
746
|
+
|
747
|
+
if (msgLimit != NULL)
|
748
|
+
*msgLimit = sub->msgsLimit;
|
749
|
+
|
750
|
+
if (bytesLimit != NULL)
|
751
|
+
*bytesLimit = sub->bytesLimit;
|
752
|
+
|
753
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
754
|
+
|
755
|
+
natsSub_Unlock(sub);
|
756
|
+
|
757
|
+
return NATS_OK;
|
758
|
+
}
|
759
|
+
|
760
|
+
natsStatus
|
761
|
+
natsSubscription_GetDelivered(natsSubscription *sub, int64_t *msgs)
|
762
|
+
{
|
763
|
+
if ((sub == NULL) || (msgs == NULL))
|
764
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
765
|
+
|
766
|
+
natsSub_Lock(sub);
|
767
|
+
|
768
|
+
if (sub->closed)
|
769
|
+
{
|
770
|
+
natsSub_Unlock(sub);
|
771
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
772
|
+
}
|
773
|
+
|
774
|
+
SUB_DLV_WORKER_LOCK(sub);
|
775
|
+
|
776
|
+
*msgs = (int64_t) sub->delivered;
|
777
|
+
|
778
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
779
|
+
|
780
|
+
natsSub_Unlock(sub);
|
781
|
+
|
782
|
+
return NATS_OK;
|
783
|
+
}
|
784
|
+
|
785
|
+
natsStatus
|
786
|
+
natsSubscription_GetDropped(natsSubscription *sub, int64_t *msgs)
|
787
|
+
{
|
788
|
+
if ((sub == NULL) || (msgs == NULL))
|
789
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
790
|
+
|
791
|
+
natsSub_Lock(sub);
|
792
|
+
|
793
|
+
if (sub->closed)
|
794
|
+
{
|
795
|
+
natsSub_Unlock(sub);
|
796
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
797
|
+
}
|
798
|
+
|
799
|
+
SUB_DLV_WORKER_LOCK(sub);
|
800
|
+
|
801
|
+
*msgs = sub->dropped;
|
802
|
+
|
803
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
804
|
+
|
805
|
+
natsSub_Unlock(sub);
|
806
|
+
|
807
|
+
return NATS_OK;
|
808
|
+
}
|
809
|
+
|
810
|
+
natsStatus
|
811
|
+
natsSubscription_GetMaxPending(natsSubscription *sub, int *msgs, int *bytes)
|
812
|
+
{
|
813
|
+
if (sub == NULL)
|
814
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
815
|
+
|
816
|
+
natsSub_Lock(sub);
|
817
|
+
|
818
|
+
if (sub->closed)
|
819
|
+
{
|
820
|
+
natsSub_Unlock(sub);
|
821
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
822
|
+
}
|
823
|
+
|
824
|
+
SUB_DLV_WORKER_LOCK(sub);
|
825
|
+
|
826
|
+
if (msgs != NULL)
|
827
|
+
*msgs = sub->msgsMax;
|
828
|
+
|
829
|
+
if (bytes != NULL)
|
830
|
+
*bytes = sub->bytesMax;
|
831
|
+
|
832
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
833
|
+
|
834
|
+
natsSub_Unlock(sub);
|
835
|
+
|
836
|
+
return NATS_OK;
|
837
|
+
}
|
838
|
+
|
839
|
+
natsStatus
|
840
|
+
natsSubscription_ClearMaxPending(natsSubscription *sub)
|
841
|
+
{
|
842
|
+
if (sub == NULL)
|
843
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
844
|
+
|
845
|
+
natsSub_Lock(sub);
|
846
|
+
|
847
|
+
if (sub->closed)
|
848
|
+
{
|
849
|
+
natsSub_Unlock(sub);
|
850
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
851
|
+
}
|
852
|
+
|
853
|
+
SUB_DLV_WORKER_LOCK(sub);
|
854
|
+
|
855
|
+
sub->msgsMax = 0;
|
856
|
+
sub->bytesMax = 0;
|
857
|
+
|
858
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
859
|
+
|
860
|
+
natsSub_Unlock(sub);
|
861
|
+
|
862
|
+
return NATS_OK;
|
863
|
+
}
|
864
|
+
|
865
|
+
natsStatus
|
866
|
+
natsSubscription_GetStats(natsSubscription *sub,
|
867
|
+
int *pendingMsgs,
|
868
|
+
int *pendingBytes,
|
869
|
+
int *maxPendingMsgs,
|
870
|
+
int *maxPendingBytes,
|
871
|
+
int64_t *deliveredMsgs,
|
872
|
+
int64_t *droppedMsgs)
|
873
|
+
{
|
874
|
+
if (sub == NULL)
|
875
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
876
|
+
|
877
|
+
natsSub_Lock(sub);
|
878
|
+
|
879
|
+
if (sub->closed)
|
880
|
+
{
|
881
|
+
natsSub_Unlock(sub);
|
882
|
+
return nats_setDefaultError(NATS_INVALID_SUBSCRIPTION);
|
883
|
+
}
|
884
|
+
|
885
|
+
SUB_DLV_WORKER_LOCK(sub);
|
886
|
+
|
887
|
+
if (pendingMsgs != NULL)
|
888
|
+
*pendingMsgs = sub->msgList.msgs;
|
889
|
+
|
890
|
+
if (pendingBytes != NULL)
|
891
|
+
*pendingBytes = sub->msgList.bytes;
|
892
|
+
|
893
|
+
if (maxPendingMsgs != NULL)
|
894
|
+
*maxPendingMsgs = sub->msgsMax;
|
895
|
+
|
896
|
+
if (maxPendingBytes != NULL)
|
897
|
+
*maxPendingBytes = sub->bytesMax;
|
898
|
+
|
899
|
+
if (deliveredMsgs != NULL)
|
900
|
+
*deliveredMsgs = (int) sub->delivered;
|
901
|
+
|
902
|
+
if (droppedMsgs != NULL)
|
903
|
+
*droppedMsgs = sub->dropped;
|
904
|
+
|
905
|
+
SUB_DLV_WORKER_UNLOCK(sub);
|
906
|
+
|
907
|
+
natsSub_Unlock(sub);
|
908
|
+
|
909
|
+
return NATS_OK;
|
910
|
+
}
|
911
|
+
|
912
|
+
/*
|
913
|
+
* Returns a boolean indicating whether the subscription is still active.
|
914
|
+
* This will return false if the subscription has already been closed,
|
915
|
+
* or auto unsubscribed.
|
916
|
+
*/
|
917
|
+
bool
|
918
|
+
natsSubscription_IsValid(natsSubscription *sub)
|
919
|
+
{
|
920
|
+
bool valid = false;
|
921
|
+
|
922
|
+
if (sub == NULL)
|
923
|
+
return false;
|
924
|
+
|
925
|
+
natsSub_Lock(sub);
|
926
|
+
|
927
|
+
valid = !(sub->closed);
|
928
|
+
|
929
|
+
natsSub_Unlock(sub);
|
930
|
+
|
931
|
+
return valid;
|
932
|
+
}
|
933
|
+
|
934
|
+
/*
|
935
|
+
* Destroys the subscription object, freeing up memory.
|
936
|
+
* If not already done, this call will removes interest on the subject.
|
937
|
+
*/
|
938
|
+
void
|
939
|
+
natsSubscription_Destroy(natsSubscription *sub)
|
940
|
+
{
|
941
|
+
bool doUnsub = false;
|
942
|
+
|
943
|
+
if (sub == NULL)
|
944
|
+
return;
|
945
|
+
|
946
|
+
natsSub_Lock(sub);
|
947
|
+
|
948
|
+
doUnsub = !(sub->closed);
|
949
|
+
|
950
|
+
natsSub_Unlock(sub);
|
951
|
+
|
952
|
+
if (doUnsub)
|
953
|
+
(void) natsSubscription_Unsubscribe(sub);
|
954
|
+
|
955
|
+
natsSub_release(sub);
|
956
|
+
}
|