NAME
Fugu::JSONSocket - newline-delimited JSON over a UNIX socket
SYNOPSIS
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;
DESCRIPTION
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
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
connectreads that line andgreetingreturns it. The default is off.
connect
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
disconnect closes the socket and drops the buffer. The method is idempotent.
request
request($hashref) encodes, sends, and reads one reply.
send_message
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
read_message reads one line and decodes it.
read_line
read_line reads one line without its terminator, and does not decode it.
is_connected
is_connected reports if the socket is open.
exists
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
greeting returns the decoded greeting, for a connection that asked for one. It is undef otherwise.
path
path returns the socket path.
error
error returns the most recent failure.
RETURN VALUES
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.
EXAMPLES
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};
}
ERRORS
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.
SEE ALSO
Fugu::Imsg, IO::Socket::UNIX, JSON::PP
AUTHORS
Dick Olsson <hi@senzilla.io>
CAVEATS
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.