NAME

POE::Component::Server::JSONUnix::Client - POE client for POE::Component::Server::JSONUnix

SYNOPSIS

use POE;
use POE::Component::Server::JSONUnix::Client;

my $client = POE::Component::Server::JSONUnix::Client->spawn(
    socket_path => '/tmp/app.sock',
    auto_auth   => 1,
    on_auth     => sub {
        my ($client, $response) = @_;
        die $response->{error} if $response->{status} ne 'ok';

        $client->call(
            command  => 'whoami',
            callback => sub {
                my ($response) = @_;
                print "I am $response->{result}{username}\n";
                $client->shutdown;
            },
        );
    },
);

$poe_kernel->run;

DESCRIPTION

An event-driven client for POE::Component::Server::JSONUnix. It connects to the server's Unix domain socket, frames requests as newline-delimited JSON, assigns each request an id, and dispatches each response back to the caller by matching the echoed id -- so any number of requests may be in flight at once.

It also knows how to complete the server's Unix-ownership authentication challenge (see "authenticate").

CONSTRUCTOR

spawn

my $client = POE::Component::Server::JSONUnix::Client->spawn(%args);

Creates the client's POE session and returns the client object. Recognised arguments:

socket_path

Required. Filesystem path of the server's Unix domain socket.

alias

POE session alias. Defaults to json_unix_client. Set this if you run more than one client in a single process.

auto_connect

Connect immediately from spawn. Defaults to true. When false, call "connect" yourself.

auto_auth

Run "authenticate" automatically as soon as the connection is up. Defaults to false. The outcome is delivered to on_auth.

request_timeout

Default per-request timeout in seconds. A request that receives no response in time is answered locally with {status => 'error', error => 'request timed out'}. No timeout by default. Can be overridden per request.

on_connect

Code reference called as $cb->($client) once the connection is established.

on_auth

Code reference called as $cb->($client, $response) when an auto_auth handshake completes (successfully or not).

on_disconnect

Code reference called as $cb->($client, $reason) when the connection is lost or closed.

on_error

Code reference called as $cb->($operation, $errnum, $errstr) on connect and I/O errors. A normal EOF from the server is not reported here (it is reported via on_disconnect).

on_notice

Code reference called as $cb->($client, $response) for any server message that cannot be matched to a pending request. This happens when:

  • the message has no id at all -- e.g. the server's error response to a request it could not parse an id out of, or an unsolicited message pushed by a server-side handler;

  • the id is one this client is no longer waiting on -- most notably a response that arrives after its timeout already fired locally (see "call"), or a duplicate response to a request that was already answered.

Unmatched messages are dropped silently if this is not set. A response delivered here is never also delivered to the original request's callback or event -- each request is answered exactly once.

METHODS

connect

$client->connect;

Begin connecting to the server. A no-op if already connected or connecting. Completion is signalled through on_connect (or on_error on failure). May be called again after a disconnect.

disconnect

$client->disconnect;

Drop the connection. Every request still awaiting a response is answered locally with an error.

shutdown

$client->shutdown;

Disconnect, release the session alias, and let the session end.

call

my $request_id = $client->call(
    command  => 'add',
    args     => { numbers => [ 1, 2, 3 ] },
    callback => sub { my ($response) = @_; ... },
);

Send a request. Returns the id assigned to it.

With neither callback nor event the request is fire-and-forget: it is sent, and its response is discarded when it arrives.

Every request is eventually answered exactly once: by the server, by the timeout, or with a local error if the connection is (or comes) down. Requests made while a connection attempt is in progress are queued and sent once it completes.

Arguments:

command

Required. The command name. cmd is accepted as an alias.

args

Arbitrary payload for the command's handler.

callback

Code reference invoked as $cb->($response, $context) with the full decoded response envelope, e.g. {id => 7, status => 'ok', result => {...}}.

event

Instead of callback, the name of an event to post back to the calling session, with the response as ARG0 and $context as ARG1. The requesting session is kept alive (via a reference count) until the response arrives. Must be used from inside a running POE session; session may be given to direct the event elsewhere.

context

An opaque value handed back with the response, for correlating state on your side.

timeout

Per-request timeout in seconds, overriding request_timeout.

A note on timeouts: a timeout is a local judgement, not a cancellation. The server knows nothing about it and may still be working on the request; there is no protocol message to withdraw one. When a timeout fires, the request's callback or event receives {status => 'error', error => 'request timed out', id => $id} and the request is forgotten. If the server's real response shows up later, it no longer matches anything pending and is routed to on_notice (carrying its id, so it can still be recognised there) -- it will never be delivered to the original callback or event, which have already been answered. Set on_notice if late results matter to you; otherwise they are dropped.

authenticate

$client->authenticate(
    callback => sub {
        my ($response) = @_;
        # {status => 'ok', result => {uid => 1000, username => 'alice'}}
    },
);

Perform the server's Unix-ownership challenge: call auth_start, write the returned cookie to a fresh file in the server's temp_dir (the OS stamps the file with this process's effective UID, which is the proof the server checks), then call auth_verify and clean the file up.

Takes the same callback / event / context arguments as "call". The response delivered is the auth_verify response on success, or a synthesised {status => 'error', ...} envelope if any step fails. After success, "authenticated", "uid" and "username" reflect the verified identity.

connected

True while a connection to the server is up.

authenticated

True after a successful "authenticate" on the current connection.

uid

username

The verified identity, or undef before authentication. Cleared on disconnect.

groups

Array reference of the verified user's group names, or undef before authentication. Empty unless the server has a permission policy configured (only then does its auth_verify report groups). Cleared on disconnect.

AUTHENTICATION

The server's user verification scheme proves which Unix user is on the other end of the socket by file ownership rather than by password. This component implements the client half:

2. Create a fresh file in temp_dir (via File::Temp) containing the cookie. The kernel records this process's effective UID as the file's owner. The file is created with mode 0644 so a server running as a different unprivileged user can read it -- the proof lies in the file's ownership, not in keeping its contents secret.

Run it explicitly with "authenticate", or set auto_auth to have it happen on every (re)connect. Note that authentication state lives on the connection: after a disconnect and reconnect the handshake must be performed again, which auto_auth handles for you.

The client and server must share a filesystem (and the same temp_dir) for this to work -- which is the natural state of affairs for a Unix-socket pair.

SEE ALSO

POE::Component::Server::JSONUnix, POE, POE::Wheel::SocketFactory, POE::Wheel::ReadWrite, JSON::MaybeXS.

AUTHOR

Zane C. Bowers-Hadley, <vvelox at vvelox.net>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2026 by Zane C. Bowers-Hadley.

This is free software, licensed under:

The GNU Lesser General Public License, Version 2.1, February 1999