Fugu

Fugu::JSONSocket(3p) Perl Library Manual Fugu::JSONSocket(3p)

Fugu::JSONSocket - newline-delimited JSON over a UNIX socket

    use Fugu::JSONSocket;
    my $client = Fugu::JSONSocket->new(
        path     => '/tmp/qmp.sock',
        timeout  => 10,
        greeting => 1,
    );
    $client->connect or die $client->error . "\n";
    my $reply = $client->request({ execute => 'query-status' });
    $client->disconnect;

Fugu::JSONSocket is a client for a protocol of one JSON object for each line, in both directions. qemu(1) speaks this on its machine-protocol and guest-agent sockets, and so does every other program that wanted a protocol without inventing a framing.

The codec is JSON::PP, which is core Perl. Thus a program that only talks to a local socket needs nothing installed.

Every read has a wall-clock deadline. The "Timeout" of IO::Socket governs its own connect and accept only, so a bare "readline" blocks for ever against a peer that stopped answering on an open socket.

Bytes after a newline stay buffered. Thus a reply that shares a segment with the one after it is not lost.

new(%args) creates a client. The method does not open the socket. Call "connect".

These are the arguments:

"path"
The UNIX socket. This argument is necessary.
"timeout"
The deadline for one read, in seconds. The default is 10.
"greeting"
Read one line at connect. A protocol that announces itself before it takes a command sets this. Then "connect" reads that line and "greeting" returns it. The default is off.

"connect" opens the socket, and reads the greeting when the caller asked for one. A second call on an open connection is a success that does nothing.

"disconnect" closes the socket and drops the buffer. The method is idempotent.

request($hashref) encodes, sends, and reads one reply.

send_message($hashref) encodes and writes one message with its newline. Use this, and then "read_message", for a protocol whose replies do not pair one to one with its requests.

"read_message" reads one line and decodes it.

"read_line" reads one line without its terminator, and does not decode it.

"is_connected" reports if the socket is open.

"exists" reports if the socket file is there. A peer that has not started is not an error, so a caller can test before it connects.

"greeting" returns the decoded greeting, for a connection that asked for one. It is "undef" otherwise.

"path" returns the socket path.

"error" returns the most recent failure.

"connect" and "send_message" return 1 on success and "undef" on failure.

"request" and "read_message" return the decoded value, or "undef". "read_line" returns a string, or "undef". Every failure puts its reason in "error".

"disconnect" returns the object. "is_connected" and "exists" return 1 or 0.

This example builds a command set over the client:

    sub query_status ($self)
    {
        my $reply = $self->{socket}->request({ execute => 'query-status' });
        return if !defined $reply || exists $reply->{error};
        return $reply->{return};
    }

"new" dies when "path" is absent or empty. That is a programming error.

No other method dies. A missing socket, a peer that closed the connection, a timeout, and a line that is not JSON all report through the return value and "error".

A write error and an end of file both close the connection. A later call reports "not connected" until the caller connects again.

Fugu::Imsg, IO::Socket::UNIX, JSON::PP

Dick Olsson <hi@senzilla.io>

The module is a client. It does not listen and does not accept.

A reply must be one line. A peer that pretty-prints its JSON across several lines does not work with this module, and no such peer exists among the protocols it was written for.

The timeout bounds one read. A reply that arrives in pieces resets nothing: the deadline covers the whole line.

2026-10-16 OpenBSD