EV-Nats

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN


  flush([$cb])
    Send PING as a write fence; the subsequent PONG guarantees all prior
    messages were processed by the server. If $cb is given, it is invoked
    when the PONG arrives. The callback receives a single argument: "undef"
    on success, or an error string (e.g. "disconnected") if the connection
    dropped before the PONG arrived.

  creds_file($path)
    Read a NATS ".creds" file and apply the embedded JWT and NKey seed via
    "jwt" and "nkey_seed". Apply this BEFORE "connect" so the credentials
    are available during the CONNECT handshake. Dies if the file is
    unreadable or missing either the "USER JWT" or "USER NKEY SEED" block.

  new_inbox
    Returns a fresh subject suitable for use as a private reply target
    ("_INBOX.<rand>.<n>"). Each call burns a slot from the same counter that
    "request" uses, so manual subscribers must treat the returned subject as
    opaque.

  subscription_count

eg/nkey_auth.pl  view on Meta::CPAN

#!/usr/bin/env perl
# NKey / credentials file authentication example
use strict;
use warnings;
use EV;
use EV::Nats;

# Method 1: credentials file (contains JWT + NKey seed).
# Apply creds_file BEFORE connect, so JWT/NKey are available during the
# initial CONNECT handshake.
if (my $creds = $ENV{NATS_CREDS}) {
    my $nats;
    $nats = EV::Nats->new(
        tls      => 1,
        on_error => sub { warn "error: @_\n" },
        on_connect => sub {
            print "connected with creds file\n";
            $nats->disconnect;

lib/EV/Nats.pm  view on Meta::CPAN

when the PONG arrives. The callback receives a single argument: C<undef>
on success, or an error string (e.g. C<"disconnected">) if the connection
dropped before the PONG arrived.

=head2 creds_file

    creds_file($path)

Read a NATS C<.creds> file and apply the embedded JWT and NKey seed
via L</jwt> and L</nkey_seed>. Apply this BEFORE C<connect> so the
credentials are available during the CONNECT handshake. Dies if the
file is unreadable or missing either the C<USER JWT> or
C<USER NKEY SEED> block.

=head2 new_inbox

Returns a fresh subject suitable for use as a private reply target
(C<_INBOX.E<lt>randE<gt>.E<lt>nE<gt>>). Each call burns a slot from
the same counter that L</request> uses, so manual subscribers must
treat the returned subject as opaque.

src/EV__Nats.xs  view on Meta::CPAN

                            PUTBACK;
                            PINNED_CALL_SV(self->on_ldm, G_DISCARD);
                            FREETMPS; LEAVE;
                        }
                    }
                }
            }
        }

        if (self->connecting) {
            /* tls_required: CONNECT would leak credentials over plaintext
               before the server could reject it; refuse instead */
            {
                const char *tr = nats_memfind(line + 5, len - 5, "\"tls_required\":", 15);
                if (tr) {
                    const char *tre = line + len;
                    int tls_active = 0;
                    tr += 15;
                    while (tr < tre && (*tr == ' ' || *tr == '\t')) tr++;
#ifdef HAVE_OPENSSL
                    tls_active = self->tls;

t/15_creds_file.t  view on Meta::CPAN

use Test::More;
use File::Temp qw(tempfile);
use EV::Nats;

plan skip_all => 'creds_file requires NKey support (build with OpenSSL)'
    unless EV::Nats::HAS_NKEY();

plan tests => 6;

# Sample seed/jwt strings copied from a real .creds file format. Not real
# credentials — random bytes that pass the regex shape only.
my $JWT  = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.payload.sig';
my $SEED = 'SUAFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKE';

sub write_creds {
    my ($content) = @_;
    my ($fh, $path) = tempfile(SUFFIX => '.creds', UNLINK => 1);
    print $fh $content;
    close $fh;
    $path;
}

t/17_mock_protocol.t  view on Meta::CPAN

        my ($c, $report) = @_;
        MockNats->send_info($c,
            '{"server_id":"fake","max_payload":1048576,"tls_required":true}');
        my $buf = MockNats->read_until($c, qr/CONNECT/, 3);
        print $report ($buf ? 'LEAKED' : 'NO-CONNECT') . "\n";
    })->start;

    my @errs;
    my $nats = EV::Nats->new(
        host => '127.0.0.1', port => $mock->port,
        user => 'u', pass => 'secret',   # credentials that must not leak
        reconnect => 0,
        on_error  => sub { push @errs, $_[0] },
    );
    run_guarded(6);
    my $verdict = $mock->report(5);
    $mock->stop;

    is $verdict, 'NO-CONNECT', 'no CONNECT on the wire for a tls_required server';
    ok((grep { /requires TLS/ } @errs), 'error explains the refusal')
        or diag "errors: @errs";



( run in 5.296 seconds using v1.01-cache-2.11-cpan-f0ff5d10edf )