git subrepo clone (merge) --branch=v3.6.1 https://github.com/nats-io/nats.c.git deps/nats.c

subrepo:
  subdir:   "deps/nats.c"
  merged:   "66cec7f"
upstream:
  origin:   "https://github.com/nats-io/nats.c.git"
  branch:   "v3.6.1"
  commit:   "66cec7f"
git-subrepo:
  version:  "0.4.6"
  commit:   "b8b46501e"
This commit is contained in:
2023-08-15 00:19:51 -07:00
parent 5bc936a09f
commit 79a45fd2e3
558 changed files with 151795 additions and 0 deletions

89
deps/nats.c/examples/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,89 @@
if(NOT NATS_BUILD_EXAMPLES)
return()
endif()
if(NOT NATS_BUILD_STATIC_EXAMPLES AND NOT NATS_BUILD_LIB_SHARED)
MESSAGE(FATAL_ERROR
"Building examples require shared library, or run CMake with -DNATS_BUILD_STATIC_EXAMPLES=ON")
endif()
# We need this directory to build the examples
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/examples)
if(NATS_BUILD_LIBUV_EXAMPLE AND LIBUV_DIR)
include_directories(${LIBUV_DIR}/include)
endif()
if(NATS_BUILD_LIBEVENT_EXAMPLE AND LIBEVENT_DIR)
include_directories(${LIBEVENT_DIR}/include)
endif()
if(WIN32)
set(LIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX})
else()
if(NATS_BUILD_STATIC_EXAMPLES)
set(LIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX})
else()
set(LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
endif()
endif()
# Get all the .c files in the examples directory
file(GLOB EXAMPLES_SOURCES RELATIVE ${PROJECT_SOURCE_DIR}/examples *.c)
if(NOT NATS_BUILD_STATIC_EXAMPLES)
add_definitions(-Dnats_IMPORTS)
endif()
# For each file...
foreach(examples_src ${EXAMPLES_SOURCES})
# Remove the suffix so that it becomes the executable name
string(REPLACE ".c" "" examplename ${examples_src})
set(exampleexe "nats-${examplename}")
set(buildExample OFF)
set(NATS_ASYNC_IO_LIB "")
if(examplename MATCHES "libuv")
if(NATS_BUILD_LIBUV_EXAMPLE)
set(buildExample ON)
if(LIBUV_DIR)
set(NATS_ASYNC_IO_LIB ${LIBUV_DIR}/lib/libuv${LIB_SUFFIX})
else()
set(NATS_ASYNC_IO_LIB uv)
endif()
endif()
elseif(examplename MATCHES "libevent")
if(NATS_BUILD_LIBEVENT_EXAMPLE)
set(buildExample ON)
if(LIBEVENT_DIR)
if(WIN32)
set(NATS_ASYNC_IO_LIB ${LIBEVENT_DIR}/lib/event${LIB_SUFFIX})
else()
set(NATS_ASYNC_IO_LIB ${LIBEVENT_DIR}/lib/libevent${LIB_SUFFIX} ${LIBEVENT_DIR}/lib/libevent_pthreads${LIB_SUFFIX})
endif()
else()
set(NATS_ASYNC_IO_LIB event)
if(UNIX)
list(APPEND NATS_ASYNC_IO_LIB event_pthreads)
endif()
endif()
endif()
else()
set(buildExample ON)
endif()
if(buildExample)
# Build the executable
add_executable(${exampleexe} ${PROJECT_SOURCE_DIR}/examples/${examples_src})
# Link
if(NATS_BUILD_STATIC_EXAMPLES)
target_link_libraries(${exampleexe} nats_static ${NATS_EXTRA_LIB} ${NATS_ASYNC_IO_LIB})
else()
target_link_libraries(${exampleexe} nats ${NATS_EXTRA_LIB} ${NATS_ASYNC_IO_LIB})
endif()
endif()
endforeach()

94
deps/nats.c/examples/asynctimeout.c vendored Normal file
View File

@@ -0,0 +1,94 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = ""\
"-gd use global message delivery thread pool\n" \
"-queue use a queue subscriber with this name\n" \
"-timeout <ms> timeout in milliseconds (default is 10sec)\n" \
"-count number of expected messages\n";
static volatile bool done = false;
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
// This callback will be invoked with a NULL message when the
// subscription times out.
if (print && (msg != NULL))
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if ((msg == NULL) || (++count == total))
{
printf("%s, destroying subscription\n",
(msg == NULL ? "Subscription timed-out" : "All messages received"));
natsSubscription_Destroy(sub);
done = true;
}
// It is safe to call natsMsg_Destroy() with a NULL message.
natsMsg_Destroy(msg);
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatus s;
opts = parseArgs(argc, argv, usage);
printf("Listening asynchronously on '%s' with a timeout of %d ms.\n",
subj, (int) timeout);
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
{
if (name != NULL)
s = natsConnection_QueueSubscribeTimeout(&sub, conn, subj, name,
timeout, onMsg, NULL);
else
s = natsConnection_SubscribeTimeout(&sub, conn, subj,
timeout, onMsg, NULL);
}
// Check every half a second for end of test.
while ((s == NATS_OK) && !done)
{
nats_Sleep(500);
}
if (s != NATS_OK)
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
// Do not destroy subscription since it is done in the callback
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

171
deps/nats.c/examples/connect.c vendored Normal file
View File

@@ -0,0 +1,171 @@
// Copyright 2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
if (print)
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
count++;
natsMsg_Destroy(msg);
}
static void
connectedCB(natsConnection *nc, void *closure)
{
char url[256];
natsConnection_GetConnectedUrl(nc, url, sizeof(url));
printf("Connected to %s\n", url);
}
static void
closedCB(natsConnection *nc, void *closure)
{
bool *closed = (bool*)closure;
const char *err = NULL;
natsConnection_GetLastError(nc, &err);
printf("Connect failed: %s\n", err);
*closed = true;
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
bool closed = false;
natsStatus s;
opts = parseArgs(argc, argv, "");
// Set a max (re)connect attempts of 50 with a delay of 100 msec.
// Total time will then be around 5 seconds.
s = natsOptions_SetMaxReconnect(opts, 50);
if (s == NATS_OK)
s = natsOptions_SetReconnectWait(opts, 100);
// Instruct the library to block the connect call for that
// long until it can get a connection or fails.
if (s == NATS_OK)
s = natsOptions_SetRetryOnFailedConnect(opts, true, NULL, NULL);
if (s != NATS_OK)
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
exit(1);
}
printf("Ensure no server is running, attempt to connect...\n");
// If the server is not running, this will block for about 5 seconds.
start = nats_Now();
s = natsConnection_Connect(&conn, opts);
elapsed = nats_Now() - start;
printf("natsConnection_Connect call took %" PRId64 " ms and returned: %s\n", elapsed, natsStatus_GetText(s));
// Close/destroy the connection in case you had a server running...
natsConnection_Destroy(conn);
conn = NULL;
// Now reduce the count, set a connected callback to allow
// connect to be done asynchronously and a closed callback
// to show that if connect fails, the callback is invoked.
s = natsOptions_SetMaxReconnect(opts, 10);
if (s == NATS_OK)
s = natsOptions_SetRetryOnFailedConnect(opts, true, connectedCB, NULL);
if (s == NATS_OK)
s = natsOptions_SetClosedCB(opts, closedCB, (void*)&closed);
if (s != NATS_OK)
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
exit(1);
}
printf("\n\n");
printf("Ensure no server is running, attempt to connect with async connect...\n");
// Start the connect. If no server is running, it should return
// NATS_NOT_YET_CONNECTED.
s = natsConnection_Connect(&conn, opts);
printf("natsConnection_Connect call returned: %s\n", natsStatus_GetText(s));
// Wait for the closed callback to be invoked
while (!closed)
nats_Sleep(100);
// Destroy the connection object
natsConnection_Destroy(conn);
conn = NULL;
// Now change the options to increase the attempts again.
s = natsOptions_SetMaxReconnect(opts, 10);
if (s == NATS_OK)
s = natsOptions_SetReconnectWait(opts, 1000);
// Remove the closed CB for this test
if (s == NATS_OK)
s = natsOptions_SetClosedCB(opts, NULL, NULL);
if (s != NATS_OK)
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
exit(1);
}
printf("\n\n");
printf("Ensure no server is running, attempt to connect with async connect...\n");
s = natsConnection_Connect(&conn, opts);
printf("Connect returned: %s\n", natsStatus_GetText(s));
// Create a subscription and send a message...
s = natsConnection_Subscribe(&sub, conn, subj, onMsg, NULL);
if (s == NATS_OK)
s = natsConnection_Publish(conn, "foo", (const void*)"hello", 5);
printf("\nStart a server now...\n\n");
// Wait for the connect to succeed and message to be received.
while ((s == NATS_OK) && (count != 1))
nats_Sleep(100);
printf("Received %d message\n", (int) count);
// Destroy all our objects to avoid report of memory leak
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

433
deps/nats.c/examples/examples.h vendored Normal file
View File

@@ -0,0 +1,433 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef EXAMPLES_H_
#define EXAMPLES_H_
#include <nats.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#define strcasecmp _stricmp
#define strdup _strdup
#else
#include <strings.h>
#include <signal.h>
#endif
#define STATS_IN 0x1
#define STATS_OUT 0x2
#define STATS_COUNT 0x4
#define MAX_SERVERS (10)
bool async = true;
const char *subj = "foo";
const char *payload= "hello";
const char *name = "worker";
int64_t total = 1000000;
volatile int64_t count = 0;
volatile int64_t dropped = 0;
int64_t start = 0;
volatile int64_t elapsed = 0;
bool print = false;
int64_t timeout = 10000; // 10 seconds.
natsOptions *opts = NULL;
const char *certFile = NULL;
const char *keyFile = NULL;
const char *cluster = "test-cluster";
const char *clientID = "client";
const char *qgroup = NULL;
const char *durable = NULL;
bool deliverAll = false;
bool deliverLast = true;
uint64_t deliverSeq = 0;
bool unsubscribe = false;
const char *stream = NULL;
bool pull = false;
bool flowctrl = false;
static natsStatus
printStats(int mode, natsConnection *conn, natsSubscription *sub,
natsStatistics *stats)
{
natsStatus s = NATS_OK;
uint64_t inMsgs = 0;
uint64_t inBytes = 0;
uint64_t outMsgs = 0;
uint64_t outBytes = 0;
uint64_t reconnected = 0;
int pending = 0;
int64_t delivered = 0;
int64_t sdropped = 0;
s = natsConnection_GetStats(conn, stats);
if (s == NATS_OK)
s = natsStatistics_GetCounts(stats, &inMsgs, &inBytes,
&outMsgs, &outBytes, &reconnected);
if ((s == NATS_OK) && (sub != NULL))
{
s = natsSubscription_GetStats(sub, &pending, NULL, NULL, NULL,
&delivered, &sdropped);
// Since we use AutoUnsubscribe(), when the max has been reached,
// the subscription is automatically closed, so this call would
// return "Invalid Subscription". Ignore this error.
if (s == NATS_INVALID_SUBSCRIPTION)
{
s = NATS_OK;
pending = 0;
}
}
if (s == NATS_OK)
{
if (mode & STATS_IN)
{
printf("In Msgs: %9" PRIu64 " - "\
"In Bytes: %9" PRIu64 " - ", inMsgs, inBytes);
}
if (mode & STATS_OUT)
{
printf("Out Msgs: %9" PRIu64 " - "\
"Out Bytes: %9" PRIu64 " - ", outMsgs, outBytes);
}
if (mode & STATS_COUNT)
{
printf("Delivered: %9" PRId64 " - ", delivered);
printf("Pending: %5d - ", pending);
printf("Dropped: %5" PRId64 " - ", sdropped);
}
printf("Reconnected: %3" PRIu64 "\n", reconnected);
}
return s;
}
static void
printPerf(const char *perfTxt)
{
if ((start > 0) && (elapsed == 0))
elapsed = nats_Now() - start;
if (elapsed <= 0)
printf("\nNot enough messages or too fast to report performance!\n");
else
printf("\n%s %" PRId64 " messages in "\
"%" PRId64 " milliseconds (%d msgs/sec)\n",
perfTxt, count, elapsed, (int)((count * 1000) / elapsed));
}
static void
printUsageAndExit(const char *progName, const char *usage)
{
printf("\nUsage: %s [options]\n\nThe options are:\n\n"\
"-h prints the usage\n" \
"-s server url(s) (list of comma separated nats urls)\n" \
"-tls use secure (SSL/TLS) connection\n" \
"-tlscacert trusted certificates file\n" \
"-tlscert client certificate (PEM format only)\n" \
"-tlskey client private key file (PEM format only)\n" \
"-tlsciphers ciphers suite\n"
"-tlshost server certificate's expected hostname\n" \
"-tlsskip skip server certificate verification\n" \
"-creds user credentials chained file\n" \
"-subj subject (default is 'foo')\n" \
"-print for consumers, print received messages (default is false)\n" \
"-wd write deadline in milliseconds\n" \
"%s\n",
progName, usage);
natsOptions_Destroy(opts);
nats_Close();
exit(1);
}
static natsStatus
parseUrls(const char *urls, natsOptions *gopts)
{
char *serverUrls[MAX_SERVERS];
int num = 0;
natsStatus s = NATS_OK;
char *urlsCopy = NULL;
char *commaPos = NULL;
char *ptr = NULL;
urlsCopy = strdup(urls);
if (urlsCopy == NULL)
return NATS_NO_MEMORY;
memset(serverUrls, 0, sizeof(serverUrls));
ptr = urlsCopy;
do
{
if (num == MAX_SERVERS)
{
s = NATS_INSUFFICIENT_BUFFER;
break;
}
serverUrls[num++] = ptr;
commaPos = strchr(ptr, ',');
if (commaPos != NULL)
{
ptr = (char*)(commaPos + 1);
*(commaPos) = '\0';
}
else
{
ptr = NULL;
}
} while (ptr != NULL);
if (s == NATS_OK)
s = natsOptions_SetServers(gopts, (const char**) serverUrls, num);
free(urlsCopy);
return s;
}
static natsOptions*
parseArgs(int argc, char **argv, const char *usage)
{
natsStatus s = NATS_OK;
bool urlsSet = false;
int i;
if (natsOptions_Create(&opts) != NATS_OK)
s = NATS_NO_MEMORY;
for (i=1; (i<argc) && (s == NATS_OK); i++)
{
if ((strcasecmp(argv[i], "-h") == 0)
|| (strcasecmp(argv[i], "-help") == 0))
{
printUsageAndExit(argv[0], usage);
}
else if (strcasecmp(argv[i], "-s") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
s = parseUrls(argv[++i], opts);
if (s == NATS_OK)
urlsSet = true;
}
else if (strcasecmp(argv[i], "-tls") == 0)
{
s = natsOptions_SetSecure(opts, true);
}
else if (strcasecmp(argv[i], "-tlscacert") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
s = natsOptions_LoadCATrustedCertificates(opts, argv[++i]);
}
else if (strcasecmp(argv[i], "-tlscert") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
certFile = argv[++i];
}
else if (strcasecmp(argv[i], "-tlskey") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
keyFile = argv[++i];
}
else if (strcasecmp(argv[i], "-tlsciphers") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
s = natsOptions_SetCiphers(opts, argv[++i]);
}
else if (strcasecmp(argv[i], "-tlshost") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
s = natsOptions_SetExpectedHostname(opts, argv[++i]);
}
else if (strcasecmp(argv[i], "-tlsskip") == 0)
{
s = natsOptions_SkipServerVerification(opts, true);
}
else if (strcasecmp(argv[i], "-sync") == 0)
{
async = false;
pull = false;
}
else if (strcasecmp(argv[i], "-subj") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
subj = argv[++i];
}
else if (strcasecmp(argv[i], "-print") == 0)
{
print = true;
}
else if ((strcasecmp(argv[i], "-name") == 0) ||
(strcasecmp(argv[i], "-queue") == 0))
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
name = argv[++i];
}
else if (strcasecmp(argv[i], "-count") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
total = atol(argv[++i]);
}
else if (strcasecmp(argv[i], "-txt") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
payload = argv[++i];
}
else if (strcasecmp(argv[i], "-timeout") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
timeout = atol(argv[++i]);
}
else if (strcasecmp(argv[i], "-gd") == 0)
{
s = natsOptions_UseGlobalMessageDelivery(opts, true);
}
else if (strcasecmp(argv[i], "-c") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
cluster = argv[++i];
}
else if (strcasecmp(argv[i], "-id") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
clientID = argv[++i];
}
else if (strcasecmp(argv[i], "-last") == 0)
{
deliverLast = true;
}
else if (strcasecmp(argv[i], "-all") == 0)
{
deliverAll = true;
}
else if (strcasecmp(argv[i], "-seq") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
deliverSeq = atol(argv[++i]);
}
else if (strcasecmp(argv[i], "-durable") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
durable = argv[++i];
}
else if (strcasecmp(argv[i], "-qgroup") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
qgroup = argv[++i];
}
else if (strcasecmp(argv[i], "-unsubscribe") == 0)
{
unsubscribe = true;
}
else if (strcasecmp(argv[i], "-creds") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
s = natsOptions_SetUserCredentialsFromFiles(opts, argv[++i], NULL);
}
else if (strcasecmp(argv[i], "-wd") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
s = natsOptions_SetWriteDeadline(opts, atol(argv[++i]));
}
else if (strcasecmp(argv[i], "-stream") == 0)
{
if (i + 1 == argc)
printUsageAndExit(argv[0], usage);
stream = argv[++i];
}
else if (strcasecmp(argv[i], "-pull") == 0)
{
async = false;
pull = true;
}
else if (strcasecmp(argv[i], "-fc") == 0)
{
flowctrl = true;
}
else
{
printf("Unknown option: '%s'\n", argv[i]);
printUsageAndExit(argv[0], usage);
}
}
if ((s == NATS_OK) && ((certFile != NULL) || (keyFile != NULL)))
s = natsOptions_LoadCertificatesChain(opts, certFile, keyFile);
if ((s == NATS_OK) && !urlsSet)
s = parseUrls(NATS_DEFAULT_URL, opts);
if (s != NATS_OK)
{
printf("Error parsing arguments: %u - %s\n",
s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
natsOptions_Destroy(opts);
nats_Close();
exit(1);
}
return opts;
}
#endif /* EXAMPLES_H_ */

View File

@@ -0,0 +1,33 @@
if(NOT NATS_BUILD_EXAMPLES)
return()
endif()
# We need this directory to build the examples
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/examples/getstarted)
# Get all the .c files in the examples directory
file(GLOB EXAMPLES_SOURCES RELATIVE ${PROJECT_SOURCE_DIR}/examples/getstarted *.c)
if(NOT NATS_BUILD_STATIC_EXAMPLES)
add_definitions(-Dnats_IMPORTS)
endif()
# For each file...
foreach(examples_src ${EXAMPLES_SOURCES})
# Remove the suffix so that it becomes the executable name
string(REPLACE ".c" "" examplename ${examples_src})
set(exampleexe "${examplename}")
# Build the executable
add_executable(${exampleexe} ${PROJECT_SOURCE_DIR}/examples/getstarted/${examples_src})
# Link
if(NATS_BUILD_STATIC_EXAMPLES)
target_link_libraries(${exampleexe} nats_static ${NATS_EXTRA_LIB})
else()
target_link_libraries(${exampleexe} nats ${NATS_EXTRA_LIB})
endif()
endforeach()

View File

@@ -0,0 +1,69 @@
// Copyright 2017-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
// Need to destroy the message!
natsMsg_Destroy(msg);
// Notify the main thread that we are done.
*(bool *)(closure) = true;
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsSubscription *sub = NULL;
natsStatus s;
volatile bool done = false;
printf("Listening on subject 'foo'\n");
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
if (s == NATS_OK)
{
// Creates an asynchronous subscription on subject "foo".
// When a message is sent on subject "foo", the callback
// onMsg() will be invoked by the client library.
// You can pass a closure as the last argument.
s = natsConnection_Subscribe(&sub, conn, "foo", onMsg, (void*) &done);
}
if (s == NATS_OK)
{
for (;!done;) {
nats_Sleep(100);
}
}
// Anything that is created need to be destroyed
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

View File

@@ -0,0 +1,135 @@
// Copyright 2020-2021 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsSubscription *sub = NULL;
natsMsg *msg = NULL;
natsMsg *rmsg = NULL;
natsStatus s;
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
// Create a message
if (s == NATS_OK)
s = natsMsg_Create(&msg, "foo", NULL, "body", 4);
// Create a header by setting a key/value
if (s == NATS_OK)
s = natsMsgHeader_Set(msg, "My-Key1", "value1");
// Let's set a new key
if (s == NATS_OK)
s = natsMsgHeader_Set(msg, "My-Key2", "value2");
// Here we add a value to the first key
if (s == NATS_OK)
s = natsMsgHeader_Add(msg, "My-Key1", "value3");
// Adding yet another key
if (s == NATS_OK)
s = natsMsgHeader_Set(msg, "My-Key3", "value4");
// Remove a key
if (s == NATS_OK)
s = natsMsgHeader_Delete(msg, "My-Key3");
// Let's print all the keys that are currently set
if (s == NATS_OK)
{
const char* *keys = NULL;
int nkeys = 0;
int i;
s = natsMsgHeader_Keys(msg, &keys, &nkeys);
for (i=0; (s == NATS_OK) && (i<nkeys); i++)
{
// To get all values that are associated with a key
const char* *values = NULL;
int nvalues = 0;
int j;
s = natsMsgHeader_Values(msg, keys[i], &values, &nvalues);
for (j=0; (s == NATS_OK) && (j < nvalues); j++)
printf("Key: '%s' Value: '%s'\n", keys[i], values[j]);
// We need to free the returned array of pointers.
free((void*) values);
}
// We need to free the returned array of pointers.
free((void*) keys);
}
// Create a subscription that we will use to receive this message
if (s == NATS_OK)
s = natsConnection_SubscribeSync(&sub, conn, "foo");
// Now publish the message
if (s == NATS_OK)
s = natsConnection_PublishMsg(conn, msg);
// We should receive it
if (s == NATS_OK)
s = natsSubscription_NextMsg(&rmsg, sub, 1000);
// Now let's check some headers from the received message
if (s == NATS_OK)
{
const char *val = NULL;
// Notice that calling natsMsgHeader_Get() on a key that has
// several values will return the first entry.
s = natsMsgHeader_Get(rmsg, "My-Key1", &val);
if (s == NATS_OK)
printf("For key 'My-Key1', got value: '%s'\n", val);
// If we lookup for a key that does not exist, we get NATS_NOT_FOUND.
if (s == NATS_OK)
{
s = natsMsgHeader_Get(rmsg, "key-does-not-exist", &val);
if (s == NATS_NOT_FOUND)
s = NATS_OK;
else
printf("Should not have found that key!\n");
}
// Same for delete
if (s == NATS_OK)
{
s = natsMsgHeader_Delete(rmsg, "key-does-not-exist");
if (s == NATS_NOT_FOUND)
s = NATS_OK;
else
printf("Should not have found that key!\n");
}
}
// Anything that is created need to be destroyed
natsMsg_Destroy(msg);
natsMsg_Destroy(rmsg);
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

View File

@@ -0,0 +1,48 @@
// Copyright 2017-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsStatus s;
printf("Publishes a message on subject 'foo'\n");
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
if (s == NATS_OK)
{
const char data[] = {104, 101, 108, 108, 111, 33};
// Publishes the sequence of bytes on subject "foo".
s = natsConnection_Publish(conn, "foo", data, sizeof(data));
}
// Anything that is created need to be destroyed
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

View File

@@ -0,0 +1,56 @@
// Copyright 2017-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsMsg *msg = NULL;
natsStatus s;
printf("Publishes a message on subject 'foo'\n");
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
if (s == NATS_OK)
{
const char data[] = {104, 101, 108, 108, 111, 33};
// Creates a message for subject "foo", no reply, and
// with the given payload.
s = natsMsg_Create(&msg, "foo", NULL, data, sizeof(data));
}
if (s == NATS_OK)
{
// Publishes the message on subject "foo".
s = natsConnection_PublishMsg(conn, msg);
}
// Anything that is created need to be destroyed
natsMsg_Destroy(msg);
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

View File

@@ -0,0 +1,47 @@
// Copyright 2017-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsStatus s;
printf("Publishes a message on subject 'foo'\n");
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
if (s == NATS_OK)
{
// This is a convenient function to send a message on "foo"
// as a string.
s = natsConnection_PublishString(conn, "foo", "hello!");
}
// Anything that is created need to be destroyed
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

View File

@@ -0,0 +1,76 @@
// Copyright 2017-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
// Sends a reply
if (natsMsg_GetReply(msg) != NULL)
{
natsConnection_PublishString(nc, natsMsg_GetReply(msg),
"here's some help");
}
// Need to destroy the message!
natsMsg_Destroy(msg);
// Notify the main thread that we are done.
*(bool *)(closure) = true;
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsSubscription *sub = NULL;
natsStatus s;
volatile bool done = false;
printf("Listening for requests on subject 'help'\n");
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
if (s == NATS_OK)
{
// Creates an asynchronous subscription on subject "help",
// waiting for a request. If a message arrives on this
// subject, the callback onMsg() will be invoked and it
// will send a reply.
s = natsConnection_Subscribe(&sub, conn, "help", onMsg, (void*) &done);
}
if (s == NATS_OK)
{
for (;!done;) {
nats_Sleep(100);
}
}
// Anything that is created need to be destroyed
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

View File

@@ -0,0 +1,60 @@
// Copyright 2017-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsMsg *reply= NULL;
natsStatus s;
printf("Publishes a message on subject 'help'\n");
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
if (s == NATS_OK)
{
// Sends a request on "help" and expects a reply.
// Will wait only for a given number of milliseconds,
// say for 5 seconds in this example.
s = natsConnection_RequestString(&reply, conn, "help",
"really need some", 5000);
}
if (s == NATS_OK)
{
// If we are here, we should have received the reply
printf("Received reply: %.*s\n",
natsMsg_GetDataLength(reply),
natsMsg_GetData(reply));
// Need to destroy the message!
natsMsg_Destroy(reply);
}
// Anything that is created need to be destroyed
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

View File

@@ -0,0 +1,64 @@
// Copyright 2017-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <nats.h>
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsSubscription *sub = NULL;
natsMsg *msg = NULL;
natsStatus s;
printf("Listening on subject 'foo'\n");
// Creates a connection to the default NATS URL
s = natsConnection_ConnectTo(&conn, NATS_DEFAULT_URL);
if (s == NATS_OK)
{
// Creates an synchronous subscription on subject "foo".
s = natsConnection_SubscribeSync(&sub, conn, "foo");
}
if (s == NATS_OK)
{
// With synchronous subscriptions, one need to poll
// using this function. A timeout is used to instruct
// how long we are willing to wait. The wait is in milliseconds.
// So here, we are going to wait for 5 seconds.
s = natsSubscription_NextMsg(&msg, sub, 5000);
}
if (s == NATS_OK)
{
// If we are here, we should have received a message.
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
// Need to destroy the message!
natsMsg_Destroy(msg);
}
// Anything that is created need to be destroyed
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
// If there was an error, print a stack trace and exit
if (s != NATS_OK)
{
nats_PrintLastErrorStack(stderr);
exit(2);
}
return 0;
}

201
deps/nats.c/examples/js-pub.c vendored Normal file
View File

@@ -0,0 +1,201 @@
// Copyright 2021 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = ""\
"-stream stream name (default is 'foo')\n" \
"-txt text to send (default is 'hello')\n" \
"-count number of messages to send\n" \
"-sync publish synchronously (default is async)\n";
static void
_jsPubErr(jsCtx *js, jsPubAckErr *pae, void *closure)
{
int *errors = (int*) closure;
printf("Error: %u - Code: %u - Text: %s\n", pae->Err, pae->ErrCode, pae->ErrText);
printf("Original message: %.*s\n", natsMsg_GetDataLength(pae->Msg), natsMsg_GetData(pae->Msg));
*errors = (*errors + 1);
// If we wanted to resend the original message, we would do something like that:
//
// js_PublishMsgAsync(js, &(pae->Msg), NULL);
//
// Note that we use `&(pae->Msg)` so that the library set it to NULL if it takes
// ownership, and the library will not destroy the message when this callback returns.
// No need to destroy anything, everything is handled by the library.
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsStatistics *stats = NULL;
natsOptions *opts = NULL;
jsCtx *js = NULL;
jsOptions jsOpts;
jsErrCode jerr = 0;
natsStatus s;
int dataLen=0;
volatile int errors = 0;
bool delStream = false;
opts = parseArgs(argc, argv, usage);
dataLen = (int) strlen(payload);
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
s = jsOptions_Init(&jsOpts);
if (s == NATS_OK)
{
if (async)
{
jsOpts.PublishAsync.ErrHandler = _jsPubErr;
jsOpts.PublishAsync.ErrHandlerClosure = (void*) &errors;
}
s = natsConnection_JetStream(&js, conn, &jsOpts);
}
if (s == NATS_OK)
{
jsStreamInfo *si = NULL;
// First check if the stream already exists.
s = js_GetStreamInfo(&si, js, stream, NULL, &jerr);
if (s == NATS_NOT_FOUND)
{
jsStreamConfig cfg;
// Since we are the one creating this stream, we can delete at the end.
delStream = true;
// Initialize the configuration structure.
jsStreamConfig_Init(&cfg);
cfg.Name = stream;
// Set the subject
cfg.Subjects = (const char*[1]){subj};
cfg.SubjectsLen = 1;
// Make it a memory stream.
cfg.Storage = js_MemoryStorage;
// Add the stream,
s = js_AddStream(&si, js, &cfg, NULL, &jerr);
}
if (s == NATS_OK)
{
printf("Stream %s has %" PRIu64 " messages (%" PRIu64 " bytes)\n",
si->Config->Name, si->State.Msgs, si->State.Bytes);
// Need to destroy the returned stream object.
jsStreamInfo_Destroy(si);
}
}
if (s == NATS_OK)
s = natsStatistics_Create(&stats);
if (s == NATS_OK)
{
printf("\nSending %" PRId64 " messages to subject '%s'\n", total, stream);
start = nats_Now();
}
for (count = 0; (s == NATS_OK) && (count < total); count++)
{
if (async)
s = js_PublishAsync(js, subj, (const void*) payload, dataLen, NULL);
else
{
jsPubAck *pa = NULL;
s = js_Publish(&pa, js, subj, (const void*) payload, dataLen, NULL, &jerr);
if (s == NATS_OK)
{
if (pa->Duplicate)
printf("Got a duplicate message! Sequence=%" PRIu64 "\n", pa->Sequence);
jsPubAck_Destroy(pa);
}
}
}
if ((s == NATS_OK) && async)
{
jsPubOptions jsPubOpts;
jsPubOptions_Init(&jsPubOpts);
// Let's set it to 30 seconds, if getting "Timeout" errors,
// this may need to be increased based on the number of messages
// being sent.
jsPubOpts.MaxWait = 30000;
s = js_PublishAsyncComplete(js, &jsPubOpts);
if (s == NATS_TIMEOUT)
{
// Let's get the list of pending messages. We could resend,
// etc, but for now, just destroy them.
natsMsgList list;
js_PublishAsyncGetPendingList(&list, js);
natsMsgList_Destroy(&list);
}
}
if (s == NATS_OK)
{
jsStreamInfo *si = NULL;
elapsed = nats_Now() - start;
printStats(STATS_OUT, conn, NULL, stats);
printPerf("Sent");
if (errors != 0)
printf("There were %d asynchronous errors\n", errors);
// Let's report some stats after the run
s = js_GetStreamInfo(&si, js, stream, NULL, &jerr);
if (s == NATS_OK)
{
printf("\nStream %s has %" PRIu64 " messages (%" PRIu64 " bytes)\n",
si->Config->Name, si->State.Msgs, si->State.Bytes);
jsStreamInfo_Destroy(si);
}
}
if (delStream && (js != NULL))
{
printf("\nDeleting stream %s: ", stream);
s = js_DeleteStream(js, stream, NULL, &jerr);
if (s == NATS_OK)
printf("OK!");
printf("\n");
}
if (s != NATS_OK)
{
printf("Error: %u - %s - jerr=%u\n", s, natsStatus_GetText(s), jerr);
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
jsCtx_Destroy(js);
natsStatistics_Destroy(stats);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

236
deps/nats.c/examples/js-sub.c vendored Normal file
View File

@@ -0,0 +1,236 @@
// Copyright 2021 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = ""\
"-gd use global message delivery thread pool\n" \
"-sync receive synchronously (default is asynchronous)\n" \
"-pull use pull subscription\n" \
"-fc enable flow control\n" \
"-count number of expected messages\n";
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
if (print)
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
if (start == 0)
start = nats_Now();
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if (++count == total)
elapsed = nats_Now() - start;
// Since this is auto-ack callback, we don't need to ack here.
natsMsg_Destroy(msg);
}
static void
asyncCb(natsConnection *nc, natsSubscription *sub, natsStatus err, void *closure)
{
printf("Async error: %u - %s\n", err, natsStatus_GetText(err));
natsSubscription_GetDropped(sub, (int64_t*) &dropped);
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsStatistics *stats = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsMsg *msg = NULL;
jsCtx *js = NULL;
jsErrCode jerr = 0;
jsOptions jsOpts;
jsSubOptions so;
natsStatus s;
bool delStream = false;
opts = parseArgs(argc, argv, usage);
printf("Created %s subscription on '%s'.\n",
(pull ? "pull" : (async ? "asynchronous" : "synchronous")), subj);
s = natsOptions_SetErrorHandler(opts, asyncCb, NULL);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
s = jsOptions_Init(&jsOpts);
if (s == NATS_OK)
s = jsSubOptions_Init(&so);
if (s == NATS_OK)
{
so.Stream = stream;
so.Consumer = durable;
if (flowctrl)
{
so.Config.FlowControl = true;
so.Config.Heartbeat = (int64_t)1E9;
}
}
if (s == NATS_OK)
s = natsConnection_JetStream(&js, conn, &jsOpts);
if (s == NATS_OK)
{
jsStreamInfo *si = NULL;
// First check if the stream already exists.
s = js_GetStreamInfo(&si, js, stream, NULL, &jerr);
if (s == NATS_NOT_FOUND)
{
jsStreamConfig cfg;
// Since we are the one creating this stream, we can delete at the end.
delStream = true;
// Initialize the configuration structure.
jsStreamConfig_Init(&cfg);
cfg.Name = stream;
// Set the subject
cfg.Subjects = (const char*[1]){subj};
cfg.SubjectsLen = 1;
// Make it a memory stream.
cfg.Storage = js_MemoryStorage;
// Add the stream,
s = js_AddStream(&si, js, &cfg, NULL, &jerr);
}
if (s == NATS_OK)
{
printf("Stream %s has %" PRIu64 " messages (%" PRIu64 " bytes)\n",
si->Config->Name, si->State.Msgs, si->State.Bytes);
// Need to destroy the returned stream object.
jsStreamInfo_Destroy(si);
}
}
if (s == NATS_OK)
{
if (pull)
s = js_PullSubscribe(&sub, js, subj, durable, &jsOpts, &so, &jerr);
else if (async)
s = js_Subscribe(&sub, js, subj, onMsg, NULL, &jsOpts, &so, &jerr);
else
s = js_SubscribeSync(&sub, js, subj, &jsOpts, &so, &jerr);
}
if (s == NATS_OK)
s = natsSubscription_SetPendingLimits(sub, -1, -1);
if (s == NATS_OK)
s = natsStatistics_Create(&stats);
if ((s == NATS_OK) && pull)
{
natsMsgList list;
int i;
for (count = 0; (s == NATS_OK) && (count < total); )
{
s = natsSubscription_Fetch(&list, sub, 1024, 5000, &jerr);
if (s != NATS_OK)
break;
if (start == 0)
start = nats_Now();
count += (int64_t) list.Count;
for (i=0; (s == NATS_OK) && (i<list.Count); i++)
s = natsMsg_Ack(list.Msgs[i], &jsOpts);
natsMsgList_Destroy(&list);
}
}
else if ((s == NATS_OK) && async)
{
while (s == NATS_OK)
{
if (count + dropped == total)
break;
nats_Sleep(1000);
}
}
else if (s == NATS_OK)
{
for (count = 0; (s == NATS_OK) && (count < total); count++)
{
s = natsSubscription_NextMsg(&msg, sub, 5000);
if (s != NATS_OK)
break;
if (start == 0)
start = nats_Now();
s = natsMsg_Ack(msg, &jsOpts);
natsMsg_Destroy(msg);
}
}
if (s == NATS_OK)
{
printStats(STATS_IN|STATS_COUNT, conn, sub, stats);
printPerf("Received");
}
if (s == NATS_OK)
{
jsStreamInfo *si = NULL;
// Let's report some stats after the run
s = js_GetStreamInfo(&si, js, stream, NULL, &jerr);
if (s == NATS_OK)
{
printf("\nStream %s has %" PRIu64 " messages (%" PRIu64 " bytes)\n",
si->Config->Name, si->State.Msgs, si->State.Bytes);
jsStreamInfo_Destroy(si);
}
if (delStream)
{
printf("\nDeleting stream %s: ", stream);
s = js_DeleteStream(js, stream, NULL, &jerr);
if (s == NATS_OK)
printf("OK!");
printf("\n");
}
}
else
{
printf("Error: %u - %s - jerr=%u\n", s, natsStatus_GetText(s), jerr);
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
jsCtx_Destroy(js);
natsStatistics_Destroy(stats);
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

147
deps/nats.c/examples/libevent-pub.c vendored Normal file
View File

@@ -0,0 +1,147 @@
// Copyright 2016-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "adapters/libevent.h"
#include "examples.h"
#ifndef WIN32
#include <pthread.h>
#define THREAD_T pthread_t
#define THREAD_FN void *
#define THREAD_RETURN() return (NULL)
#define THREAD_START(threadvar, fn, arg) \
pthread_create(&(threadvar), NULL, fn, arg)
#define THREAD_JOIN(th) pthread_join(th, NULL)
#else
#include <process.h>
#define THREAD_T HANDLE
#define THREAD_FN unsigned __stdcall
#define THREAD_RETURN() return (0)
#define THREAD_START(threadvar, fn, arg) do { \
uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \
(threadvar) = (HANDLE) threadhandle; \
} while (0)
#define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
#endif
static const char *usage = ""\
"-txt text to send (default is 'hello')\n" \
"-count number of messages to send\n";
typedef struct
{
natsConnection *conn;
natsStatus status;
} threadInfo;
static THREAD_FN
pubThread(void *arg)
{
threadInfo *info = (threadInfo*) arg;
natsStatus s = NATS_OK;
for (count = 0; (s == NATS_OK) && (count < total); count++)
s = natsConnection_PublishString(info->conn, subj, payload);
if (s == NATS_OK)
s = natsConnection_Flush(info->conn);
natsConnection_Close(info->conn);
info->status = s;
if (s != NATS_OK)
nats_PrintLastErrorStack(stderr);
THREAD_RETURN();
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatus s = NATS_OK;
struct event_base *evLoop= NULL;
THREAD_T pub;
threadInfo info;
nats_Open(-1);
opts = parseArgs(argc, argv, usage);
printf("Sending %" PRId64 " messages to subject '%s'\n", total, subj);
// One time initialization of things that we need.
natsLibevent_Init();
// Create a loop.
evLoop = event_base_new();
if (evLoop == NULL)
s = NATS_ERR;
// Indicate which loop and callbacks to use once connected.
if (s == NATS_OK)
s = natsOptions_SetEventLoop(opts, (void*) evLoop,
natsLibevent_Attach,
natsLibevent_Read,
natsLibevent_Write,
natsLibevent_Detach);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
start = nats_Now();
if (s == NATS_OK)
{
info.conn = conn;
info.status = NATS_OK;
THREAD_START(pub, pubThread, (void*) &info);
}
if (s == NATS_OK)
{
event_base_dispatch(evLoop);
THREAD_JOIN(pub);
s = info.status;
}
if (s == NATS_OK)
{
printPerf("Sent");
}
else
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
if (evLoop != NULL)
event_base_free(evLoop);
// To silence reports of memory still in used with valgrind
nats_Close();
libevent_global_shutdown();
return 0;
}

115
deps/nats.c/examples/libevent-sub.c vendored Normal file
View File

@@ -0,0 +1,115 @@
// Copyright 2016-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "adapters/libevent.h"
#include "examples.h"
static const char *usage = ""\
"-gd use global message delivery thread pool\n" \
"-count number of expected messages\n";
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
if (print)
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
natsMsg_Destroy(msg);
if (start == 0)
start = nats_Now();
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if (++count == total)
{
elapsed = nats_Now() - start;
natsConnection_Close(nc);
}
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatus s = NATS_OK;
struct event_base *evLoop= NULL;
nats_Open(-1);
opts = parseArgs(argc, argv, usage);
printf("Listening on '%s'.\n", subj);
// One time initialization of things that we need.
natsLibevent_Init();
// Create a loop.
evLoop = event_base_new();
if (evLoop == NULL)
s = NATS_ERR;
// Indicate which loop and callbacks to use once connected.
if (s == NATS_OK)
s = natsOptions_SetEventLoop(opts, (void*) evLoop,
natsLibevent_Attach,
natsLibevent_Read,
natsLibevent_Write,
natsLibevent_Detach);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
s = natsConnection_Subscribe(&sub, conn, subj, onMsg, NULL);
// For maximum performance, set no limit on the number of pending messages.
if (s == NATS_OK)
s = natsSubscription_SetPendingLimits(sub, -1, -1);
// Run the event loop.
// This call will return when the connection is closed (either after
// receiving all messages, or disconnected and unable to reconnect).
if (s == NATS_OK)
event_base_dispatch(evLoop);
if (s == NATS_OK)
{
printPerf("Received");
}
else
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
if (evLoop != NULL)
event_base_free(evLoop);
// To silence reports of memory still in used with valgrind
nats_Close();
libevent_global_shutdown();
return 0;
}

135
deps/nats.c/examples/libuv-pub.c vendored Normal file
View File

@@ -0,0 +1,135 @@
// Copyright 2016-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "adapters/libuv.h"
#include "examples.h"
static const char *usage = ""\
"-txt text to send (default is 'hello')\n" \
"-count number of messages to send\n";
typedef struct
{
natsConnection *conn;
natsStatus status;
} threadInfo;
static void
pubThread(void *arg)
{
threadInfo *info = (threadInfo*) arg;
natsStatus s = NATS_OK;
for (count = 0; (s == NATS_OK) && (count < total); count++)
s = natsConnection_PublishString(info->conn, subj, payload);
if (s == NATS_OK)
s = natsConnection_Flush(info->conn);
natsConnection_Close(info->conn);
info->status = s;
// Since this is a user-thread, call this function to release
// possible thread-local memory allocated by the library.
nats_ReleaseThreadMemory();
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatus s = NATS_OK;
uv_loop_t *uvLoop= NULL;
uv_thread_t pub;
threadInfo info;
opts = parseArgs(argc, argv, usage);
printf("Sending %" PRId64 " messages to subject '%s'\n", total, subj);
// One time initialization of things that we need.
natsLibuv_Init();
// Create a loop.
uvLoop = uv_default_loop();
if (uvLoop != NULL)
{
// Libuv is not thread-safe. Almost all calls to libuv need to
// occur from the thread where the loop is running. NATS library
// may have to call into the event loop from different threads.
// This call allows natsLibuv APIs to know if they are executing
// from the event loop thread or not.
natsLibuv_SetThreadLocalLoop(uvLoop);
}
else
{
s = NATS_ERR;
}
// Indicate which loop and callbacks to use once connected.
if (s == NATS_OK)
s = natsOptions_SetEventLoop(opts, (void*) uvLoop,
natsLibuv_Attach,
natsLibuv_Read,
natsLibuv_Write,
natsLibuv_Detach);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
start = nats_Now();
if (s == NATS_OK)
{
info.conn = conn;
info.status = NATS_OK;
if (uv_thread_create(&pub, pubThread, (void*) &info) != 0)
s = NATS_ERR;
}
if (s == NATS_OK)
{
uv_run(uvLoop, UV_RUN_DEFAULT);
uv_thread_join(&pub);
s = info.status;
}
if (s == NATS_OK)
{
printPerf("Sent");
}
else
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
if (uvLoop != NULL)
uv_loop_close(uvLoop);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

125
deps/nats.c/examples/libuv-sub.c vendored Normal file
View File

@@ -0,0 +1,125 @@
// Copyright 2016-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "adapters/libuv.h"
#include "examples.h"
static const char *usage = ""\
"-gd use global message delivery thread pool\n" \
"-count number of expected messages\n";
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
if (print)
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
natsMsg_Destroy(msg);
if (start == 0)
start = nats_Now();
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if (++count == total)
{
elapsed = nats_Now() - start;
natsConnection_Close(nc);
}
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatus s = NATS_OK;
uv_loop_t *uvLoop= NULL;
opts = parseArgs(argc, argv, usage);
printf("Listening on '%s'.\n", subj);
// One time initialization of things that we need.
natsLibuv_Init();
// Create a loop.
uvLoop = uv_default_loop();
if (uvLoop != NULL)
{
// Libuv is not thread-safe. Almost all calls to libuv need to
// occur from the thread where the loop is running. NATS library
// may have to call into the event loop from different threads.
// This call allows natsLibuv APIs to know if they are executing
// from the event loop thread or not.
natsLibuv_SetThreadLocalLoop(uvLoop);
}
else
{
s = NATS_ERR;
}
// Indicate which loop and callbacks to use once connected.
if (s == NATS_OK)
s = natsOptions_SetEventLoop(opts, (void*) uvLoop,
natsLibuv_Attach,
natsLibuv_Read,
natsLibuv_Write,
natsLibuv_Detach);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
s = natsConnection_Subscribe(&sub, conn, subj, onMsg, NULL);
// For maximum performance, set no limit on the number of pending messages.
if (s == NATS_OK)
s = natsSubscription_SetPendingLimits(sub, -1, -1);
// Run the event loop.
// This call will return when the connection is closed (either after
// receiving all messages, or disconnected and unable to reconnect).
if (s == NATS_OK)
{
uv_run(uvLoop, UV_RUN_DEFAULT);
}
if (s == NATS_OK)
{
printPerf("Received");
}
else
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
if (uvLoop != NULL)
uv_loop_close(uvLoop);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

67
deps/nats.c/examples/publisher.c vendored Normal file
View File

@@ -0,0 +1,67 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = ""\
"-txt text to send (default is 'hello')\n" \
"-count number of messages to send\n";
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsStatistics *stats = NULL;
natsOptions *opts = NULL;
natsStatus s;
int dataLen=0;
opts = parseArgs(argc, argv, usage);
printf("Sending %" PRId64 " messages to subject '%s'\n", total, subj);
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
s = natsStatistics_Create(&stats);
if (s == NATS_OK)
start = nats_Now();
dataLen = (int) strlen(payload);
for (count = 0; (s == NATS_OK) && (count < total); count++)
s = natsConnection_Publish(conn, subj, (const void*) payload, dataLen);
if (s == NATS_OK)
s = natsConnection_FlushTimeout(conn, 1000);
if (s == NATS_OK)
{
printStats(STATS_OUT, conn, NULL, stats);
printPerf("Sent");
}
else
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsStatistics_Destroy(stats);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

144
deps/nats.c/examples/queuegroup.c vendored Normal file
View File

@@ -0,0 +1,144 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = "" \
"-gd use global message delivery thread pool\n" \
"-name queue name (default is 'worker')\n" \
"-count number of expected messages\n";
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
// If 'print' is on, the server is likely to break the connection
// since the client library will become a slow consumer.
if (print)
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
if (start == 0)
start = nats_Now();
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if (++count == total)
elapsed = nats_Now() - start;
natsMsg_Destroy(msg);
}
static void
asyncCb(natsConnection *nc, natsSubscription *sub, natsStatus err, void *closure)
{
printf("Async error: %u - %s\n", err, natsStatus_GetText(err));
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatistics *stats = NULL;
natsMsg *msg = NULL;
natsStatus s;
opts = parseArgs(argc, argv, usage);
printf("Listening %ssynchronously on '%s' with name '%s'.\n",
(async ? "a" : ""), subj, name);
s = natsOptions_SetErrorHandler(opts, asyncCb, NULL);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
{
if (async)
s = natsConnection_QueueSubscribe(&sub, conn, subj, name, onMsg, NULL);
else
s = natsConnection_QueueSubscribeSync(&sub, conn, subj, name);
}
// For maximum performance, set no limit on the number of pending messages.
if (s == NATS_OK)
s = natsSubscription_SetPendingLimits(sub, -1, -1);
if (s == NATS_OK)
s = natsSubscription_AutoUnsubscribe(sub, (int) total);
if (s == NATS_OK)
s = natsStatistics_Create(&stats);
if ((s == NATS_OK) && async)
{
while (s == NATS_OK)
{
s = printStats(STATS_IN|STATS_COUNT,conn, sub, stats);
if (count == total)
break;
if (s == NATS_OK)
nats_Sleep(1000);
}
}
else if (s == NATS_OK)
{
int64_t last = 0;
for (count = 0; (s == NATS_OK) && (count < total); count++)
{
s = natsSubscription_NextMsg(&msg, sub, 10000);
if (s != NATS_OK)
break;
if (start == 0)
start = nats_Now();
if (nats_Now() - last >= 1000)
{
s = printStats(STATS_IN|STATS_COUNT,conn, sub, stats);
last = nats_Now();
}
natsMsg_Destroy(msg);
}
}
if (s == NATS_OK)
{
printStats(STATS_IN|STATS_COUNT,conn, sub, stats);
printPerf("Received");
}
else
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsStatistics_Destroy(stats);
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

160
deps/nats.c/examples/replier.c vendored Normal file
View File

@@ -0,0 +1,160 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = "" \
"-gd use global message delivery thread pool\n" \
"-sync receive synchronously (default is asynchronous)\n" \
"-count number of expected requests\n";
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
if (print)
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
if (start == 0)
start = nats_Now();
natsConnection_PublishString(nc, natsMsg_GetReply(msg),
"here's some help");
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if (++count == total)
elapsed = nats_Now() - start;
natsMsg_Destroy(msg);
}
static void
asyncCb(natsConnection *nc, natsSubscription *sub, natsStatus err, void *closure)
{
if (print)
printf("Async error: %u - %s\n", err, natsStatus_GetText(err));
natsSubscription_GetDropped(sub, (int64_t*) &dropped);
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatistics *stats = NULL;
natsMsg *msg = NULL;
natsStatus s;
opts = parseArgs(argc, argv, usage);
printf("Listening %ssynchronously for requests on '%s'\n",
(async ? "a" : ""), subj);
s = natsOptions_SetErrorHandler(opts, asyncCb, NULL);
// Since the replier is sending one message at a time, reduce
// latency by making Publish calls send data right away
// instead of buffering them.
if (s == NATS_OK)
s = natsOptions_SetSendAsap(opts, true);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
{
if (async)
s = natsConnection_Subscribe(&sub, conn, subj, onMsg, NULL);
else
s = natsConnection_SubscribeSync(&sub, conn, subj);
}
// For maximum performance, set no limit on the number of pending messages.
if (s == NATS_OK)
s = natsSubscription_SetPendingLimits(sub, -1, -1);
if (s == NATS_OK)
s = natsSubscription_AutoUnsubscribe(sub, (int) total);
if (s == NATS_OK)
s = natsStatistics_Create(&stats);
if ((s == NATS_OK) && async)
{
while (s == NATS_OK)
{
s = printStats(STATS_IN|STATS_COUNT,conn, sub, stats);
if (count + dropped == total)
break;
if (s == NATS_OK)
nats_Sleep(1000);
}
}
else if (s == NATS_OK)
{
int64_t last = 0;
for (count = 0; (s == NATS_OK) && (count < total); count++)
{
s = natsSubscription_NextMsg(&msg, sub, 10000);
if (s == NATS_OK)
s = natsConnection_PublishString(conn,
natsMsg_GetReply(msg),
"here's some help");
if (s == NATS_OK)
{
if (start == 0)
start = nats_Now();
if (nats_Now() - last >= 1000)
{
s = printStats(STATS_IN|STATS_COUNT,conn, sub, stats);
last = nats_Now();
}
}
natsMsg_Destroy(msg);
}
if (s == NATS_OK)
s = natsConnection_FlushTimeout(conn, 1000);
}
if (s == NATS_OK)
{
printStats(STATS_IN|STATS_COUNT,conn, sub, stats);
printPerf("Received");
}
else
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsStatistics_Destroy(stats);
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

87
deps/nats.c/examples/requestor.c vendored Normal file
View File

@@ -0,0 +1,87 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = "" \
"-txt text to send (default is 'hello')\n" \
"-count number of requests to send\n";
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsStatistics *stats = NULL;
natsOptions *opts = NULL;
natsMsg *reply = NULL;
int64_t last = 0;
natsStatus s;
opts = parseArgs(argc, argv, usage);
printf("Sending %" PRId64 " requests to subject '%s'\n", total, subj);
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
s = natsStatistics_Create(&stats);
if (s == NATS_OK)
start = nats_Now();
for (count = 0; (s == NATS_OK) && (count < total); count++)
{
s = natsConnection_RequestString(&reply, conn, subj, payload, 1000);
if (s != NATS_OK)
break;
if (print)
{
printf("Received reply: %s - %.*s\n",
natsMsg_GetSubject(reply),
natsMsg_GetDataLength(reply),
natsMsg_GetData(reply));
}
if (nats_Now() - last >= 1000)
{
s = printStats(STATS_OUT,conn, NULL, stats);
last = nats_Now();
}
natsMsg_Destroy(reply);
}
if (s == NATS_OK)
s = natsConnection_FlushTimeout(conn, 1000);
if (s == NATS_OK)
{
printStats(STATS_OUT, conn, NULL, stats);
printPerf("Sent");
}
else
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsStatistics_Destroy(stats);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}

View File

@@ -0,0 +1,29 @@
if(NOT NATS_BUILD_EXAMPLES)
return()
endif()
# We need this directory to build the examples
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/examples/stan)
# Get all the .c files in the examples directory
file(GLOB EXAMPLES_SOURCES RELATIVE ${PROJECT_SOURCE_DIR}/examples/stan *.c)
# For each file...
foreach(examples_src ${EXAMPLES_SOURCES})
# Remove the suffix so that it becomes the executable name
string(REPLACE ".c" "" examplename ${examples_src})
set(exampleexe "stan-${examplename}")
# Build the executable
add_executable(${exampleexe} ${PROJECT_SOURCE_DIR}/examples/stan/${examples_src})
# Link
if(NATS_BUILD_STATIC_EXAMPLES)
target_link_libraries(${exampleexe} nats_static ${NATS_EXTRA_LIB})
else()
target_link_libraries(${exampleexe} nats ${NATS_EXTRA_LIB})
endif()
endforeach()

127
deps/nats.c/examples/stan/pub-async.c vendored Normal file
View File

@@ -0,0 +1,127 @@
// Copyright 2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "../examples.h"
static const char *usage = ""\
"-txt text to send (default is 'hello')\n";
typedef struct __myPubMsgInfo
{
const char *payload;
int size;
char ID[30];
} myPubMsgInfo;
static volatile bool done = false;
static void
_pubAckHandler(const char *guid, const char *error, void *closure)
{
myPubMsgInfo *pubMsg = (myPubMsgInfo*) closure;
printf("Ack handler for message ID=%s Data=%.*s GUID=%s - ",
pubMsg->ID, pubMsg->size, pubMsg->payload, guid);
if (error != NULL)
printf("Error= %s\n", error);
else
printf("Success!\n");
// This is a good place to free the pubMsg info since
// we no longer need it.
free(pubMsg);
// Notify the main thread that we are done. This is
// not the proper way and you should use some locking.
done = true;
}
int main(int argc, char **argv)
{
natsStatus s;
stanConnOptions *connOpts = NULL;
stanConnection *sc = NULL;
myPubMsgInfo *pubMsg = NULL;
// This example demonstrates the use of the pubAckHandler closure
// to correlate published messages and their acks.
opts = parseArgs(argc, argv, usage);
printf("Sending 1 message to channel '%s'\n", subj);
// Now create STAN Connection Options and set the NATS Options.
s = stanConnOptions_Create(&connOpts);
if (s == NATS_OK)
s = stanConnOptions_SetNATSOptions(connOpts, opts);
// Create the Connection using the STAN Connection Options
if (s == NATS_OK)
s = stanConnection_Connect(&sc, cluster, clientID, connOpts);
// Once the connection is created, we can destroy the options
natsOptions_Destroy(opts);
stanConnOptions_Destroy(connOpts);
// Create an object that represents our message
if (s == NATS_OK)
{
pubMsg = (myPubMsgInfo*) calloc(1, sizeof(myPubMsgInfo));
if (pubMsg == NULL)
s = NATS_NO_MEMORY;
if (s == NATS_OK)
{
// Say we want to bind the data that we are going to send
// to some unique ID that we know about this message.
pubMsg->payload = payload;
pubMsg->size = (int)strlen(payload);
snprintf(pubMsg->ID, sizeof(pubMsg->ID), "%s:%d", "xyz", 234);
}
}
// We send the message and pass our message info as the closure
// for the pubAckHandler.
if (s == NATS_OK)
{
s = stanConnection_PublishAsync(sc, subj, pubMsg->payload, pubMsg->size,
_pubAckHandler, (void*) pubMsg);
// Note that if this call fails, then we need to free the pubMsg
// object here since it won't be passed to the ack handler.
if (s != NATS_OK)
free(pubMsg);
}
if (s == NATS_OK)
{
while (!done)
nats_Sleep(15);
}
if (s != NATS_OK)
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy the connection
stanConnection_Destroy(sc);
// To silence reports of memory still in-use with valgrind.
nats_Sleep(50);
nats_Close();
return 0;
}

143
deps/nats.c/examples/stan/pub.c vendored Normal file
View File

@@ -0,0 +1,143 @@
// Copyright 2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "../examples.h"
static const char *usage = ""\
"-txt text to send (default is 'hello')\n" \
"-count number of messages to send\n" \
"-sync publish synchronously (default is async)\n";
static volatile int ackCount = 0;
static volatile int errCount = 0;
static void
_pubAckHandler(const char *guid, const char *error, void *closure)
{
// This callback can be invoked by different threads for the
// same connection, so access should be protected. For this
// example, we don't.
ackCount++;
if (error != NULL)
{
printf("pub ack for guid:%s error=%s\n", guid, error);
errCount++;
}
}
static void
connectionLostCB(stanConnection *sc, const char *errTxt, void *closure)
{
bool *connLost = (bool*) closure;
printf("Connection lost: %s\n", errTxt);
*connLost = true;
}
int main(int argc, char **argv)
{
natsStatus s;
stanConnOptions *connOpts = NULL;
stanConnection *sc = NULL;
int len;
bool connLost = false;
opts = parseArgs(argc, argv, usage);
len = (int) strlen(payload);
printf("Sending %" PRId64 " messages to channel '%s'\n", total, subj);
// Now create STAN Connection Options and set the NATS Options.
s = stanConnOptions_Create(&connOpts);
if (s == NATS_OK)
s = stanConnOptions_SetNATSOptions(connOpts, opts);
// Set smaller ping intervals
if (s == NATS_OK)
s = stanConnOptions_SetPings(connOpts, 1, 5);
// Add a callback to be notified if the STAN connection is lost for good.
if (s == NATS_OK)
s = stanConnOptions_SetConnectionLostHandler(connOpts, connectionLostCB, (void*)&connLost);
/*
// To reduce MaxPubAcksInflight to 1000 and factor of 1.0
if (s == NATS_OK)
s = stanConnOptions_SetMaxPubAcksInflight(connOpts, 1000, 1.0);
*/
// Create the Connection using the STAN Connection Options
if (s == NATS_OK)
s = stanConnection_Connect(&sc, cluster, clientID, connOpts);
// Once the connection is created, we can destroy the options
natsOptions_Destroy(opts);
stanConnOptions_Destroy(connOpts);
if (s == NATS_OK)
start = nats_Now();
for (count = 0; (s == NATS_OK) && (count < total); count++)
{
if (async)
s = stanConnection_PublishAsync(sc, subj, (const void*) payload, len, _pubAckHandler, NULL);
else
s = stanConnection_Publish(sc, subj, (const void*) payload, len);
}
if (!connLost && (s == NATS_OK))
{
if (async)
{
while (ackCount != total)
nats_Sleep(15);
}
printPerf("Sent");
printf("Publish ack received: %d - with error: %d\n", ackCount, errCount);
}
// If the connection was created, try to close it
if (!connLost && (sc != NULL))
{
natsStatus closeSts = stanConnection_Close(sc);
if ((s == NATS_OK) && (closeSts != NATS_OK))
s = closeSts;
}
if (s != NATS_OK)
{
// If we finished before the end, let's wait a tiny
// bit to see if the failure is due to connection lost.
if (ackCount != total)
nats_Sleep(100);
// If connection was lost, the real reason is reported
// the the connectionLostCB callback.
if (!connLost)
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
}
// Destroy the connection
stanConnection_Destroy(sc);
// To silence reports of memory still in-use with valgrind.
nats_Sleep(50);
nats_Close();
return 0;
}

235
deps/nats.c/examples/stan/sub.c vendored Normal file
View File

@@ -0,0 +1,235 @@
// Copyright 2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "../examples.h"
static const char *usage = ""\
"-c cluster name (default \"test-cluster\")\n" \
"-id client ID (default \"client\"\n" \
"-count number of messages to receive\n" \
"-last deliver starting with last published message (default)\n" \
"-all deliver all available messages\n" \
"-seq deliver starting at given sequence number\n" \
"-durable durable subscription name\n" \
"-qgroup queue group name\n" \
"-unsubscribe unsubscribe the durable on exit\n";
static volatile bool done = false;
static void
onMsg(stanConnection *sc, stanSubscription *sub, const char *channel, stanMsg *msg, void *closure)
{
if (print)
printf("Received on [%s]: sequence:%" PRIu64 " data:%.*s timestamp:%" PRId64 " redelivered: %s\n",
channel,
stanMsg_GetSequence(msg),
stanMsg_GetDataLength(msg),
stanMsg_GetData(msg),
stanMsg_GetTimestamp(msg),
stanMsg_IsRedelivered(msg) ? "yes" : "no");
if (start == 0)
start = nats_Now();
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if (count == total-1)
{
natsStatus s;
elapsed = nats_Now() - start;
if (unsubscribe)
s = stanSubscription_Unsubscribe(sub);
else
s = stanSubscription_Close(sub);
if (s != NATS_OK)
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
}
/*
// If manual acknowledgment was selected, we would acknowledge
// the message this way:
stanSubscription_AckMsg(sub, msg);
*/
stanMsg_Destroy(msg);
// Increment only here so that when the main thread detects
// that the total has been sent, it does not start cleaning
// objects before we have closed the subscription and destroyed
// the last message. This is to reduce risk of valgrind reporting
// memory still in-use.
count++;
}
#if WIN32
static BOOL
sigHandler(DWORD fdwCtrlType)
{
if (fdwCtrlType==CTRL_C_EVENT)
{
done = true;
return TRUE;
}
return FALSE;
}
#else
static void
sigHandler(int ignored) {
done = true;
}
#endif
static void
connectionLostCB(stanConnection *sc, const char *errTxt, void *closure)
{
bool *connLost = (bool*) closure;
printf("Connection lost: %s\n", errTxt);
*connLost = true;
}
int main(int argc, char **argv)
{
natsStatus s;
stanConnOptions *connOpts = NULL;
stanSubOptions *subOpts = NULL;
stanConnection *sc = NULL;
stanSubscription *sub = NULL;
bool connLost = false;
opts = parseArgs(argc, argv, usage);
printf("Receiving %" PRId64 " messages from channel '%s'\n", total, subj);
// Now create STAN Connection Options and set the NATS Options.
s = stanConnOptions_Create(&connOpts);
if (s == NATS_OK)
s = stanConnOptions_SetNATSOptions(connOpts, opts);
// Add a callback to be notified if the STAN connection is lost for good.
if (s == NATS_OK)
s = stanConnOptions_SetConnectionLostHandler(connOpts, connectionLostCB, (void*)&connLost);
// Create the Connection using the STAN Connection Options
if (s == NATS_OK)
s = stanConnection_Connect(&sc, cluster, clientID, connOpts);
// Once connection is created, we can destroy opts and connOpts
natsOptions_Destroy(opts);
stanConnOptions_Destroy(connOpts);
if (s == NATS_OK)
s = stanSubOptions_Create(&subOpts);
// If durable
if ((s == NATS_OK) && (durable != NULL))
s = stanSubOptions_SetDurableName(subOpts, durable);
// Set position
if (s == NATS_OK)
{
if (deliverAll)
s = stanSubOptions_DeliverAllAvailable(subOpts);
else if (deliverLast)
s = stanSubOptions_StartWithLastReceived(subOpts);
else if (deliverSeq > 0)
s = stanSubOptions_StartAtSequence(subOpts, deliverSeq);
}
/*
// To manually acknowledge the messages, you would need to set this option
if (s == NATS_OK)
s = stanSubOptions_SetManualAckMode(subOpts, true);
// To change the number of MaxInflight messages, set this option.
// For instance, to receive a single message between each ACK, set
// the value to 1.
if (s == NATS_OK)
s = stanSubOptions_SetMaxInflight(subOpts, 1);
// To change the duration after which the server resends unacknowledged
// messages, use this option. For instance, cause re-delivery after 5 seconds:
if (s == NATS_OK)
s = stanSubOptions_SetAckWait(subOpts, 5000);
*/
// Create subscription
if (s == NATS_OK)
{
if (qgroup != NULL)
s = stanConnection_QueueSubscribe(&sub, sc, subj, qgroup, onMsg, NULL, subOpts);
else
s = stanConnection_Subscribe(&sub, sc, subj, onMsg, NULL, subOpts);
}
// Once subscription is created, we can destroy the subOpts object
stanSubOptions_Destroy(subOpts);
if (s == NATS_OK)
{
#if WIN32
SetConsoleCtrlHandler((PHANDLER_ROUTINE) sigHandler, TRUE);
#else
signal(SIGINT, sigHandler);
#endif
while (!done && !connLost && (count < total))
nats_Sleep(15);
if (!connLost)
printPerf("Received");
}
// If test was interrupted before receiving all expected messages,
// close or unsubscribe. Otherwise, this is done in the message
// callback.
if (!connLost && ((sub != NULL) && (count < total)))
{
if (unsubscribe)
s = stanSubscription_Unsubscribe(sub);
else
s = stanSubscription_Close(sub);
}
// If the connection was created, try to close it
if (!connLost && (sc != NULL))
{
natsStatus closeSts = stanConnection_Close(sc);
if ((s == NATS_OK) && (closeSts != NATS_OK))
s = closeSts;
}
if (s != NATS_OK)
{
printf("Error: %d - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy our objects
stanSubscription_Destroy(sub);
stanConnection_Destroy(sc);
// To silence reports of memory still in-use with valgrind.
nats_Sleep(50);
nats_Close();
return 0;
}

145
deps/nats.c/examples/subscriber.c vendored Normal file
View File

@@ -0,0 +1,145 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "examples.h"
static const char *usage = ""\
"-gd use global message delivery thread pool\n" \
"-sync receive synchronously (default is asynchronous)\n" \
"-count number of expected messages\n";
static void
onMsg(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
if (print)
printf("Received msg: %s - %.*s\n",
natsMsg_GetSubject(msg),
natsMsg_GetDataLength(msg),
natsMsg_GetData(msg));
if (start == 0)
start = nats_Now();
// We should be using a mutex to protect those variables since
// they are used from the subscription's delivery and the main
// threads. For demo purposes, this is fine.
if (++count == total)
elapsed = nats_Now() - start;
natsMsg_Destroy(msg);
}
static void
asyncCb(natsConnection *nc, natsSubscription *sub, natsStatus err, void *closure)
{
if (print)
printf("Async error: %u - %s\n", err, natsStatus_GetText(err));
natsSubscription_GetDropped(sub, (int64_t*) &dropped);
}
int main(int argc, char **argv)
{
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsSubscription *sub = NULL;
natsStatistics *stats = NULL;
natsMsg *msg = NULL;
natsStatus s;
opts = parseArgs(argc, argv, usage);
printf("Listening %ssynchronously on '%s'.\n",
(async ? "a" : ""), subj);
s = natsOptions_SetErrorHandler(opts, asyncCb, NULL);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
if (s == NATS_OK)
{
if (async)
s = natsConnection_Subscribe(&sub, conn, subj, onMsg, NULL);
else
s = natsConnection_SubscribeSync(&sub, conn, subj);
}
// For maximum performance, set no limit on the number of pending messages.
if (s == NATS_OK)
s = natsSubscription_SetPendingLimits(sub, -1, -1);
if (s == NATS_OK)
s = natsSubscription_AutoUnsubscribe(sub, (int) total);
if (s == NATS_OK)
s = natsStatistics_Create(&stats);
if ((s == NATS_OK) && async)
{
while (s == NATS_OK)
{
s = printStats(STATS_IN|STATS_COUNT, conn, sub, stats);
if (count + dropped == total)
break;
if (s == NATS_OK)
nats_Sleep(1000);
}
}
else if (s == NATS_OK)
{
int64_t last = 0;
for (count = 0; (s == NATS_OK) && (count < total); count++)
{
s = natsSubscription_NextMsg(&msg, sub, 10000);
if (s != NATS_OK)
break;
if (start == 0)
start = nats_Now();
if (nats_Now() - last >= 1000)
{
s = printStats(STATS_IN|STATS_COUNT, conn, sub, stats);
last = nats_Now();
}
natsMsg_Destroy(msg);
}
}
if (s == NATS_OK)
{
printStats(STATS_IN|STATS_COUNT,conn, sub, stats);
printPerf("Received");
}
else
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
}
// Destroy all our objects to avoid report of memory leak
natsStatistics_Destroy(stats);
natsSubscription_Destroy(sub);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
return 0;
}