Cliente AC para o sistema de mensagens NATS.
Acesse aqui a documentação on-line e verifique as perguntas mais frequentes.
Esta implementação do cliente NATS é fortemente baseada no cliente NATS GO. Há suporte para Mac OS/X, Linux e Windows (embora não tenhamos matriz de suporte de plataforma específica).
Existem vários gerenciadores de pacotes com biblioteca cliente NATS C disponíveis. Se você conhece algum que não esteja nesta lista, envie um PR para adicioná-lo!
Primeiro, baixe o código fonte:
git clone [email protected]:nats-io/nats.c.git .
Para construir a biblioteca, use CMake. Observe que, por padrão, a API de streaming do NATS será criada e incluída na biblioteca do NATS. Veja abaixo se você não deseja construir APIs relacionadas ao Streaming.
Certifique-se de que o CMake esteja adicionado ao seu caminho. Se estiver compilando no Windows, abra um shell de comando no menu Ferramentas do Visual Studio e selecione o shell de comando apropriado (x64 ou x86 para compilações de 64 ou 32 bits, respectivamente). Provavelmente, você também precisará executar isso com privilégios de administrador.
Crie um diretório build
(qualquer nome funcionaria) a partir da árvore de origem raiz e cd
nele. Em seguida, emita este comando pela primeira vez:
cmake ..
Em algumas arquiteturas, você pode encontrar um erro de compilação para mutex.co
porque não há suporte para a instrução assembler que usamos para render ao girar tentando adquirir um bloqueio.
Você pode receber este tipo de erro de compilação:
/tmp/cc1Yp7sD.s: Assembler messages:
/tmp/cc1Yp7sD.s:302: Error: selected processor does not support ARM mode `yield'
src/CMakeFiles/nats_static.dir/build.make:542: recipe for target 'src/CMakeFiles/nats_static.dir/unix/mutex.c.o' failed
Se for esse o caso, você pode resolver isso habilitando o sinalizador NATS_BUILD_NO_SPIN
(ou use -DNATS_NO_SPIN
se você compilar sem CMake):
cmake .. -DNATS_BUILD_NO_SPIN=ON
Se você já construiu a biblioteca anteriormente, pode ser necessário fazer um make clean
ou simplesmente excluir e recriar o diretório de construção antes de executar o comando cmake.
Para construir no Windows, você precisaria selecionar o gerador de construção. Por exemplo, para selecionar nmake
, você executaria:
cmake .. -G "NMake Makefiles"
Executar cmake -h
forneceria a lista de opções possíveis e todos os nomes dos geradores.
Alternativamente, você pode executar a versão GUI. A partir desse mesmo shell de comando de construção , inicie a GUI:
c:program files (x86)CMakebincmake-gui.exe
Se você começou com um diretório de compilação vazio, precisará selecionar a origem e o diretório de compilação e clicar em Configure
. Aqui, você poderá selecionar na caixa suspensa o nome do gerador de compilação. Quando terminar, clique em Generate
. Em seguida, você pode voltar ao shell de comando ou ao Visual Studio e compilar.
Para modificar algumas das opções de construção, você precisa editar o cache e reconstruir.
make edit_cache
Observe que se você construir no Windows e tiver selecionado "NMake Makefiles", substitua todas as referências a seguir para make
por nmake
.
A edição do cache permite selecionar o tipo de compilação (Debug, Release, etc), a arquitetura (64 ou 32 bits) e assim por diante.
O alvo padrão irá construir tudo, ou seja, as bibliotecas NATS estáticas e compartilhadas e também os exemplos e o programa de teste. Cada um está localizado em seus respectivos diretórios no diretório de construção: src
, examples
e test
.
make install
Copiará as bibliotecas estáticas e compartilhadas na pasta install/lib
e os cabeçalhos públicos em install/include
.
Por padrão, a biblioteca é construída com suporte TLS. Você pode desabilitar isso no cmake gui make edit_cache
e mudar a opção NATS_BUILD_WITH_TLS
para OFF
, ou passar a opção diretamente para o comando cmake
:
cmake .. -DNATS_BUILD_WITH_TLS=OFF
A partir da 2.0.0
, ao construir com suporte TLS/SSL, o nome de host esperado do certificado do servidor é sempre verificado. Significa que o nome do host fornecido na(s) URL(s) ou através da opção natsOptions_SetExpectedHostname()
será utilizado para verificar o nome do host presente no certificado. Antes da 2.0.0
, o nome do host seria verificado apenas se a opção natsOptions_SetExpectedHostname()
fosse invocada.
Embora recomendemos deixar o novo comportamento padrão, você pode restaurar o comportamento anterior construindo a biblioteca com esta opção desativada:
cmake .. -DNATS_BUILD_TLS_FORCE_HOST_VERIFY=OFF
O cliente NATS C é construído usando APIs da biblioteca OpenSSL. Por padrão, usamos APIs 3.0+
. Como o OpenSSL 1.0.2
não é mais suportado, começando com a versão NATS C Client v3.6.0
, a variável CMake NATS_BUILD_TLS_USE_OPENSSL_1_1_API
agora está definida como ON
por padrão (se você estiver configurando um novo ambiente) e usará APIs OpenSSL de 1.1+
/ APIs 3.0+
. Você ainda poderá compilar com a biblioteca OpenSSL 1.0.2
definindo esta opção CMake como OFF
:
cmake .. -DNATS_BUILD_TLS_USE_OPENSSL_1_1_API=OFF
A variável NATS_BUILD_TLS_USE_OPENSSL_1_1_API
está obsoleta, o que significa que no futuro esta opção será simplesmente removida e apenas APIs OpenSSL 3.0+
serão usadas. O código na biblioteca que usa APIs OpenSSL mais antigas também será removido.
Observe que a variável NATS_BUILD_WITH_TLS_CLIENT_METHOD
que estava obsoleta na v2.0.0
agora foi removida.
Como o cliente NATS C se vincula dinamicamente à biblioteca OpenSSL, você precisa ter certeza de que está executando seu aplicativo em uma biblioteca OpenSSL 1.1+/3.0+.
Se quiser vincular à biblioteca OpenSSL estática, você precisa excluir o CMakeCache.txt
e regenerá-lo com a opção adicional:
rm CMakeCache.txt
cmake .. <build options that you may already use> -DNATS_BUILD_OPENSSL_STATIC_LIBS=ON
Em seguida, chame make
(ou equivalente dependendo da sua plataforma) e isso deve garantir que a biblioteca (e exemplos e/ou executável do conjunto de testes) esteja vinculada à biblioteca OpenSSL, se ela tiver sido encontrada pelo CMake.
Ao construir a biblioteca com suporte a Streaming, a biblioteca NATS usa a biblioteca libprotobuf-c. Quando cmake é executado pela primeira vez (ou após remover CMakeCache.txt
e chamar cmake ..
novamente), ele está procurando pela biblioteca libprotobuf-c. Se não encontrar, uma mensagem será impressa e o processo de construção falhará. O CMake procura a biblioteca nos diretórios onde as bibliotecas normalmente são encontradas. No entanto, se quiser especificar um diretório específico onde a biblioteca está localizada, você precisa fazer o seguinte:
cmake .. -DNATS_PROTOBUF_DIR=<my libprotobuf-c directory>
A biblioteca estática será usada por padrão. Se você quiser mudar isso, ou se a biblioteca não tiver o nome esperado, você precisa fazer o seguinte:
# Use the library named mylibproto.so located at /my/location
cmake .. -DNATS_PROTOBUF_LIBRARY=/my/location/mylibproto.so
Os dois poderiam ser combinados se o cabeçalho de inclusão estiver localizado em um diretório diferente
# Use the library named mylibproto.so located at /my/location and the directory protobuf-c/ containing protobuf-c.h located at /my/other/location
cmake .. -DNATS_PROTOBUF_LIBRARY=/my/location/mylibproto.so -DNATS_PROTOBUF_DIR=/my/other/location
Se você não quiser criar APIs de streaming NATS para serem incluídas na biblioteca NATS:
cmake .. -DNATS_BUILD_STREAMING=OFF
Ao utilizar os novos recursos de segurança do NATS 2.0, a biblioteca precisa assinar algum “nonce” enviado pelo servidor durante uma conexão ou reconexão. Usamos assinatura de chave pública Ed25519. A biblioteca vem com algum código para realizar a assinatura. Na maioria dos casos, tudo bem, mas se o desempenho for um problema (especialmente se você planeja usar muito a função natsConnection_Sign()
), você terá a opção de construir com a biblioteca Libsodium.
Siga as instruções sobre como instalar a biblioteca libsodium aqui.
No macOS, você poderia usar brew
:
brew install libsodium
No Linux, você poderia usar apt-get
apt-get install libsodium-dev
Uma vez instalado, você pode reconstruir o cliente NATS C habilitando primeiro o uso da biblioteca libsodium:
cmake .. -DNATS_BUILD_USE_SODIUM=ON
Se você tiver a biblioteca libsodium instalada em um local não padrão que o CMake não consegue encontrar, você pode especificar o local deste diretório:
cmake .. -DNATS_BUILD_USE_SODIUM=ON -DNATS_SODIUM_DIR=/my/path/to/libsodium
Nas plataformas onde valgrind
está disponível, você pode executar os testes com verificações de memória. Aqui está um exemplo:
make test ARGS="-T memcheck"
Ou você pode invocar diretamente o programa ctest
:
ctest -T memcheck -V -I 1,4
O comando acima executaria os testes com valgrind
( -T memcheck
), com saída detalhada ( -V
) e executaria os testes de 1 a 4 ( -I 1,4
).
Se você adicionar um teste a test/test.c
, será necessário adicioná-lo ao arquivo list_test.txt
. Cada entrada contém apenas o nome do teste, a função deve ser nomeada de forma idêntica, com um prefixo test_
. A lista está em ordem alfabética, mas não precisa estar, você pode adicionar em qualquer lugar.
Se você estiver adicionando um benchmark, ele deverá ser adicionado ao list_bench.txt
. Esses testes são rotulados de forma diferente ( -L 'bench'
) e executados separadamente no CI.
Você precisa executar novamente cmake
para que as alterações tenham efeito:
cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ivan/nats.c/build
Você pode usar as seguintes variáveis de ambiente para influenciar o comportamento do conjunto de testes.
Ao executar com verificação de memória, as alterações de tempo e o desempenho geral são mais lentos. A variável a seguir permite que o testsuite ajuste alguns dos valores usados durante o teste:
export NATS_TEST_VALGRIND=yes
No Windows, seria set
em vez de export
.
Ao executar os testes no modo detalhado, a variável de ambiente a seguir permite ver a saída do servidor dentro do próprio teste. Sem esta opção, a saída do servidor é silenciada:
export NATS_TEST_KEEP_SERVER_OUTPUT=yes
Se você quiser alterar o nome do executável do servidor padrão ( nats-server.exe
) ou especificar um local específico, use esta variável de ambiente:
set NATS_TEST_SERVER_EXE=c:testnats-server.exe
A API pública foi documentada usando Doxygen.
Para gerar a documentação, acesse o diretório doc
e digite o seguinte comando:
doxygen DoxyFile.NATS.Client
Se você alternar a compilação das APIs de streaming e a documentação não corresponder mais ao que está sendo compilado, você poderá atualizar a documentação alternando o sinalizador de compilação NATS_UPDATE_DOC
e reconstruir a documentação.
No diretório de construção:
cmake .. -DNATS_UPDATE_DOC=ON
make
cd <nats.c root dir>/doc
doxygen DoxyFile.NATS.Client
A documentação gerada estará localizada no diretório html
. Para ver a documentação, aponte seu navegador para o arquivo index.html
nesse diretório.
Acesse aqui para obter a documentação on-line.
O código-fonte também está bastante documentado.
Esta seção lista mudanças importantes, como avisos de descontinuação, etc...
2.0.0
Esta versão introduz os conceitos de segurança utilizados pelo NATS Server 2.0.0
e, portanto, alinha-se com a versão do servidor. Novas APIs foram introduzidas, mas a mudança mais importante é o novo comportamento padrão com conexões TLS:
Ao estabelecer uma conexão segura, o nome do host do certificado do servidor agora é sempre verificado, independentemente de o usuário ter invocado natsOptions_SetExpectedHostname()
. Isso pode interromper aplicativos que, por exemplo, usavam um IP para se conectar a um servidor que tinha apenas o nome do host no certificado. Isso pode ser resolvido alterando seu aplicativo para usar o nome do host na URL ou fazendo uso de natsOptions_SetExpectedHostname()
. Se isso não for possível, você poderá restaurar o comportamento antigo construindo a biblioteca com o novo comportamento desabilitado. Consulte #tls-support para obter mais informações.
Este repositório costumava incluir bibliotecas pré-compiladas de libprotobuf-c para macOS, Linux e Windows junto com os arquivos de cabeçalho (no diretório /pbuf
). Agora removemos este diretório e exigimos que o usuário instale a biblioteca libprotobuf-c separadamente. Consulte as instruções de construção para especificar o local da biblioteca se o CMake não conseguir encontrá-la diretamente.
1.8.0
natsConnStatus
foram prefixados com NATS_CONN_STATUS_
. Se o seu aplicativo não estiver usando nenhuma referência de valor original, como CONNECTED
ou CLOSED
, etc., não há nada que você precise fazer. Se fizer isso, você tem duas opções:NATS_BUILD_NO_PREFIX_CONNSTS
. Isso pode ser feito desta forma no diretório de construção: cmake .. -DNATS_BUILD_NO_PREFIX_CONNSTS=ON
O diretório examples/getstarted
possui um conjunto de exemplos simples que são totalmente funcionais, mas muito simples. O objetivo é demonstrar como é fácil usar a API.
Um conjunto mais complexo de exemplos está no diretório examples/
e também pode ser usado para avaliar a biblioteca cliente.
Observe que, para simplificar, a verificação de erros não é realizada aqui.
natsConnection * nc = NULL ;
natsSubscription * sub = NULL ;
natsMsg * msg = NULL ;
// Connects to the default NATS Server running locally
natsConnection_ConnectTo ( & nc , NATS_DEFAULT_URL );
// Connects to a server with username and password
natsConnection_ConnectTo ( & nc , "nats://ivan:secret@localhost:4222" );
// Connects to a server with token authentication
natsConnection_ConnectTo ( & nc , "nats://myTopSecretAuthenticationToken@localhost:4222" );
// Simple publisher, sending the given string to subject "foo"
natsConnection_PublishString ( nc , "foo" , "hello world" );
// Publish binary data. Content is not interpreted as a string.
char data [] = { 1 , 2 , 0 , 4 , 5 };
natsConnection_Publish ( nc , "foo" , ( const void * ) data , 5 );
// Simple asynchronous subscriber on subject foo, invoking message
// handler 'onMsg' when messages are received, and not providing a closure.
natsConnection_Subscribe ( & sub , nc , "foo" , onMsg , NULL );
// Simple synchronous subscriber
natsConnection_SubscribeSync ( & sub , nc , "foo" );
// Using a synchronous subscriber, gets the first message available, waiting
// up to 1000 milliseconds (1 second)
natsSubscription_NextMsg ( & msg , sub , 1000 );
// Destroy any message received (asynchronously or synchronously) or created
// by your application. Note that if 'msg' is NULL, the call has no effect.
natsMsg_Destroy ( msg );
// Unsubscribing
natsSubscription_Unsubscribe ( sub );
// Destroying the subscription (this will release the object, which may
// result in freeing the memory). After this call, the object must no
// longer be used.
natsSubscription_Destroy ( sub );
// Publish requests to the given reply subject:
natsConnection_PublishRequestString ( nc , "foo" , "bar" , "help!" );
// Sends a request (internally creates an inbox) and Auto-Unsubscribe the
// internal subscriber, which means that the subscriber is unsubscribed
// when receiving the first response from potentially many repliers.
// This call will wait for the reply for up to 1000 milliseconds (1 second).
natsConnection_RequestString ( & reply , nc , "foo" , "help" , 1000 );
// Closing a connection (but not releasing the connection object)
natsConnection_Close ( nc );
// When done with the object, free the memory. Note that this call
// closes the connection first, in other words, you could have simply
// this call instead of natsConnection_Close() followed by the destroy
// call.
natsConnection_Destroy ( nc );
// Message handler
void
onMsg ( natsConnection * nc , natsSubscription * sub , natsMsg * msg , void * closure )
{
// Prints the message, using the message getters:
printf ( "Received msg: %s - %.*sn" ,
natsMsg_GetSubject ( msg ),
natsMsg_GetDataLength ( msg ),
natsMsg_GetData ( msg ));
// Don't forget to destroy the message!
natsMsg_Destroy ( msg );
}
O suporte para JetStream começa com a versão v3.0.0
da biblioteca e o NATS Server v2.2.0+
, embora a obtenção de códigos de erro específicos do JetStream exija o servidor na versão v2.3.0+
. Algumas das opções de configuração só estão disponíveis a partir v2.3.3
, por isso recomendamos que você use a versão mais recente do servidor NATS para ter uma experiência melhor.
Veja exemplos chamados js-xxx.c
no diretório de examples
para ver exemplos de como usar a API. Os novos objetos e APIs estão totalmente documentados na documentação online.
// Connect to NATS
natsConnection_Connect ( & conn , opts );
// Initialize and set some JetStream options
jsOptions jsOpts ;
jsOptions_Init ( & jsOpts );
jsOpts . PublishAsync . MaxPending = 256 ;
// Create JetStream Context
natsConnection_JetStream ( & js , conn , & jsOpts );
// Simple Stream Publisher
js_Publish ( & pa , js , "ORDERS.scratch" , ( const void * ) "hello" , 5 , NULL , & jerr );
// Simple Async Stream Publisher
for ( i = 0 ; i < 500 ; i ++ )
{
js_PublishAsync ( js , "ORDERS.scratch" , ( const void * ) "hello" , 5 , NULL );
}
// Wait for up to 5 seconds to receive all publish acknowledgments.
jsPubOptions_Init ( & jsPubOpts );
jsPubOpts . MaxWait = 5000 ;
js_PublishAsyncComplete ( js , & jsPubOpts );
// One can get the list of all pending publish async messages,
// to either resend them or simply destroy them.
natsMsgList pending ;
s = js_PublishAsyncGetPendingList ( & pending , js );
if ( s == NATS_OK )
{
int i ;
for ( i = 0 ; i < pending . Count ; i ++ )
{
// There could be a decision to resend these messages or not.
if ( your_decision_to_resend ( pending . Msgs [ i ]))
{
// If the call is successful, pending.Msgs[i] will be set
// to NULL so destroying the pending list will not destroy
// this message since the library has taken ownership back.
js_PublishMsgAsync ( js , & ( pending . Msgs [ i ]), NULL );
}
}
// Destroy the pending list object and all messages still in that list.
natsMsgList_Destroy ( & pending );
}
// To create an asynchronous ephemeral consumer
js_Subscribe ( & sub , js , "foo" , myMsgHandler , myClosure , & jsOpts , NULL , & jerr );
// Same but use a subscription option to ask the callback to not do auto-ack.
jsSubOptions so ;
jsSubOptions_Init ( & so );
so . ManualAck = true;
js_Subscribe ( & sub , js , "foo" , myMsgHandler , myClosure , & jsOpts , & so , & jerr );
// Or to bind to an existing specific stream/durable:
jsSubOptions_Init ( & so );
so . Stream = "MY_STREAM" ;
so . Consumer = "my_durable" ;
js_Subscribe ( & sub , js , "foo" , myMsgHandler , myClosure , & jsOpts , & so , & jerr );
// Synchronous subscription:
js_SubscribeSync ( & sub , js , "foo" , & jsOpts , & so , & jerr );
jsStreamConfig cfg ;
// Connect to NATS
natsConnection_Connect ( & conn , opts );
// Create JetStream Context
natsConnection_JetStream ( & js , conn , NULL );
// Initialize the configuration structure.
jsStreamConfig_Init ( & cfg );
// Provide a name
cfg . Name = "ORDERS" ;
// Array of subjects and its size
cfg . Subjects = ( const char * [ 1 ]){ "ORDERS.*" };
cfg . SubjectsLen = 1 ;
// Create a Stream. If you are not interested in the returned jsStreamInfo object,
// you can pass NULL.
js_AddStream ( NULL , js , & cfg , NULL , & jerr );
// Update a Stream
cfg . MaxBytes = 8 ;
js_UpdateStream ( NULL , js , & cfg , NULL , & jerr );
// Delete a Stream
js_DeleteStream ( js , "ORDERS" , NULL , & jerr );
RECURSO EXPERIMENTAL! Reservamo-nos o direito de alterar a API sem necessariamente alterar a versão principal da biblioteca.
Um armazenamento KeyValue é uma visão materializada baseada em JetStream. Um bucket é um stream e as chaves são assuntos dentro desse stream.
Alguns recursos exigem o NATS Server v2.6.2
, portanto, recomendamos que você use a versão mais recente do NATS Server para ter uma experiência melhor.
Os novos objetos e APIs estão totalmente documentados na documentação online.
Exemplo de como criar uma loja KeyValue:
jsCtx * js = NULL ;
kvStore * kv = NULL ;
kvConfig kvc ;
// Assume we got a JetStream context in `js`...
kvConfig_Init ( & kvc );
kvc . Bucket = "KVS" ;
kvc . History = 10 ;
s = js_CreateKeyValue ( & kv , js , & kvc );
// Do some stuff...
// This is to free the memory used by `kv` object,
// not delete the KeyValue store in the server
kvStore_Destroy ( kv );
Isso mostra como "vincular" a um existente:
jsCtx * js = NULL ;
kvStore * kv = NULL ;
// Assume we got a JetStream context in `js`...
s = js_KeyValue ( & kv , ks , "KVS" );
// Do some stuff...
// This is to free the memory used by `kv` object,
// not delete the KeyValue store in the server
kvStore_Destroy ( kv );
Veja como excluir um armazenamento KeyValue no servidor:
jsCtx * js = NULL ;
// Assume we got a JetStream context in `js`...
s = js_DeleteKeyValue ( js , "KVS" );
É assim que se coloca um valor para uma determinada chave:
kvStore * kv = NULL ;
uint64_t rev = 0 ;
// Assume we got a kvStore...
s = kvStore_PutString ( & rev , kv , "MY_KEY" , "my value" );
// If the one does not care about getting the revision, pass NULL:
s = kvStore_PutString ( NULL , kv , "MY_KEY" , "my value" );
O exemplo acima coloca um valor para uma determinada chave, mas se, em vez disso, alguém quiser ter certeza de que o valor será colocado para a chave somente se ela nunca existiu antes, alguém chamaria:
// Same note than before: if "rev" is not needed, pass NULL:
s = kvStore_CreateString ( & rev , kv , "MY_KEY" , "my value" );
Pode-se atualizar uma chave se e somente se a última revisão no servidor corresponder àquela passada para esta API:
// This would update the key "MY_KEY" with the value "my updated value" only if the current revision (sequence number) for this key is 10.
s = kvStore_UpdateString ( & rev , kv , "MY_KEY" , "my updated value" , 10 );
Veja como obter uma chave:
kvStore * kv = NULL ;
kvEntry * e = NULL ;
// Assume we got a kvStore...
s = kvStore_Get ( & e , kv , "MY_KEY" );
// Then we can get some fields from the entry:
printf ( "Key value: %sn" , kvEntry_ValueString ( e ));
// Once done with the entry, we need to destroy it to release memory.
// This is NOT deleting the key from the server.
kvEntry_Destroy ( e );
Veja como limpar uma chave:
kvStore * kv = NULL ;
// Assume we got a kvStore...
s = kvStore_Purge ( kv , "MY_KEY" );
Isso excluirá a chave no servidor:
kvStore * kv = NULL ;
// Assume we got a kvStore...
s = kvStore_Delete ( kv , "MY_KEY" );
Para criar um "observador" para uma determinada chave:
kvWatcher * w = NULL ;
kvWatchOptions o ;
// Assume we got a kvStore...
// Say that we are not interested in getting the
// delete markers...
// Initialize a kvWatchOptions object:
kvWatchOptions_Init ( & o );
o . IgnoreDeletes = true;
// Create the watcher
s = kvStore_Watch ( & w , kv , "foo.*" , & o );
// Check for error..
// Now get updates:
while ( some_condition )
{
kvEntry * e = NULL ;
// Wait for the next update for up to 5 seconds
s = kvWatcher_Next ( & e , w , 5000 );
// Do something with the entry...
// Destroy to release memory
kvEntry_Destroy ( e );
}
// When done with the watcher, it needs to be destroyed to release memory:
kvWatcher_Destroy ( w );
Para obter o histórico de uma chave:
kvEntryList l ;
int i ;
// The list is defined on the stack and will be initilized/updated by this call:
s = kvStore_History ( & l , kv , "MY_KEY" , NULL );
for ( i = 0 ; i < l . Count ; i ++ )
{
kvEntry * e = l . Entries [ i ];
// Do something with the entry...
}
// When done with the list, call this to free entries and the content of the list.
kvEntryList_Destroy ( & l );
// In order to set a timeout to get the history, we need to do so through options:
kvWatchOptions o ;
kvWatchOptions_Init ( & o );
o . Timeout = 5000 ; // 5 seconds.
s = kvStore_History ( & l , kv , "MY_KEY" , & o );
É assim que você obteria as chaves de um bucket:
kvKeysList l ;
int i ;
// If no option is required, pass NULL as the last argument.
s = kvStore_Keys ( & l , kv , NULL );
// Check error..
// Go over all keys:
for ( i = 0 ; i < l . Count ; i ++ )
printf ( "Key: %sn" , l . Keys [ i ]);
// When done, list need to be destroyed.
kvKeysList_Destroy ( & l );
// If option need to be specified:
kvWatchOptions o ;
kvWatchOptions_Init ( & o );
o . Timeout = 5000 ; // 5 seconds.
s = kvStore_Keys ( & l , kv , & o );
Os cabeçalhos estão disponíveis ao conectar-se a servidores na versão 2.2.0+.
Eles se parecem muito com cabeçalhos http. Eles são um mapa de pares chave/valor, sendo o valor uma matriz de strings.
Os cabeçalhos permitem que os usuários adicionem metainformações sobre uma mensagem sem interferir na carga útil da mensagem.
Observe que se um aplicativo tentar enviar uma mensagem com cabeçalho quando conectado a um servidor que não os entende, a chamada de publicação retornará o erro NATS_NO_SERVER_SUPPORT
.
Existe uma API para saber se o servidor atualmente conectado suporta cabeçalhos:
natsStatus s = natsConnection_HasHeaderSupport ( conn );
if ( s == NATS_NO_SERVER_SUPPORT )
// deal with server not supporting this feature.
Se o servidor entende os cabeçalhos, mas está prestes a entregar a mensagem a um cliente que não entende, os cabeçalhos são removidos para que os clientes mais antigos ainda possam receber a mensagem. É importante ter todos os clientes e servidores em uma versão que suporte cabeçalhos se os aplicativos dependerem de cabeçalhos.
Para obter mais detalhes sobre a API de cabeçalhos, consulte o exemplo: examples/getstarted/headers.c
.
O curinga *
corresponde a qualquer token, em qualquer nível do assunto:
natsConnection_Subscribe ( & sub , nc , "foo.*.baz" , onMsg , NULL );
Este assinante receberia mensagens enviadas para:
No entanto, não receberia mensagens em:
O curinga >
corresponde a qualquer comprimento de falha de um assunto e só pode ser o último token.
natsConnection_Subscribe ( & sub , nc , "foo.>" , onMsg , NULL );
Este assinante receberia qualquer mensagem enviada para:
No entanto, não receberia mensagens enviadas em:
Publicar sobre este assunto faria com que os dois assinantes acima recebessem a mensagem:
natsConnection_PublishString ( nc , "foo.bar.baz" , "got it?" );
Todas as assinaturas com o mesmo nome de fila formarão um grupo de filas. Cada mensagem será entregue a apenas um assinante por grupo de filas, usando a semática da fila. Você pode ter quantos grupos de filas desejar. Os assinantes normais continuarão funcionando conforme o esperado.
natsConnection_QueueSubscribe ( & sub , nc , "foo" , "job_workers" , onMsg , NULL );
(Observe que a biblioteca precisa ser construída com suporte a TLS - que é por padrão - para que essas APIs funcionem. Consulte o capítulo Build sobre como construir com ou sem TLS para obter mais detalhes).
Uma conexão SSL/TLS é configurada por meio do uso de natsOptions
. Dependendo do nível de segurança desejado, pode ser tão simples quanto definir o booleano seguro como verdadeiro na chamada natsOptions_SetSecure()
.
Mesmo com segurança total (cliente verificando certificado de servidor e servidor exigindo certificados de cliente), a configuração envolve apenas algumas chamadas.
// Here is the minimum to create a TLS/SSL connection:
// Create an options object.
natsOptions_Create ( & opts );
// Set the secure flag.
natsOptions_SetSecure ( opts , true);
// You may not need this, but suppose that the server certificate
// is self-signed and you would normally provide the root CA, but
// don't want to. You can disable the server certificate verification
// like this:
natsOptions_SkipServerVerification ( opts , true);
// Connect now...
natsConnection_Connect ( & nc , opts );
// That's it! On success you will have a secure connection with the server!
(...)
// This example shows what it takes to have a full SSL configuration,
// including server expected's hostname, root CA, client certificates
// and specific ciphers to use.
// Create an options object.
natsOptions_Create ( & opts );
// Set the secure flag.
natsOptions_SetSecure ( opts , true);
// For a server with a trusted chain built into the client host,
// simply designate the server name that is expected. Without this
// call, the server certificate is still verified, but not the
// hostname.
natsOptions_SetExpectedHostname ( opts , "localhost" );
// Instead, if you are using a self-signed cert and need to load in the CA.
natsOptions_LoadCATrustedCertificates ( opts , caCertFileName );
// If the server requires client certificates, provide them along with the
// private key, all in one call.
natsOptions_LoadCertificatesChain ( opts , certChainFileName , privateKeyFileName );
// You can also specify preferred ciphers if you want.
natsOptions_SetCiphers ( opts , "-ALL:HIGH" );
// Then simply pass the options object to the connect call:
natsConnection_Connect ( & nc , opts );
// That's it! On success you will have a secure connection with the server!