NAME
App::FileSync::Transport::Local - run the server as a local child process
SYNOPSIS
my $transport = App::FileSync::Transport::Local->new(
root => '/srv/filesync', repo => 'docs', client => 'laptop',
);
my $connection = App::FileSync::Protocol->new(in => $transport->reader, out => $transport->writer);
...
$transport->close;
METHODS
new
Purpose: start a server for one session.
Args: root (the server root), repo, client, optional role (default client) and server_bin (default FILESYNC_SERVER_BIN, then a bin/filesync-server found above this module, then filesync-server on the PATH).
Returns: the transport.
Side Effects: starts $^X server_bin --root ... --repo ... --client ... --role .... The child's standard error is the parent's, never the protocol pipe: sharing it would put diagnostics into the protocol stream.
Usage:
my $transport = App::FileSync::Transport::Local->new(%args);
EXAMPLE
my $t = App::FileSync::Transport::Local->new(root => $root, repo => 'docs', client => 'test-1');
print {$t->writer} ...;
API SPECIFICATION
INPUT
{
root => { type => 'string', min => 1 },
repo => { type => 'string', min => 1 },
client => { type => 'string', min => 1 },
role => { type => 'string', optional => 1 },
server_bin => { type => 'string', optional => 1 },
}
OUTPUT
{ type => 'object', isa => 'App::FileSync::Transport::Local' }
MESSAGES
Key Meaning Resolution
transport.missing root, repo or client absent pass it
FORMAL SPECIFICATION
new(a) ⇒ ∃ child • argv(child) = ⟨perl, bin, --root, a.root, --repo, a.repo, --client, a.client, --role, role⟩
reader
Documented with "writer" below.
writer
Purpose: the pipes to and from the server.
Args: none.
Returns: the read handle (server's stdout) or write handle (its stdin).
Side Effects: none.
Usage:
my $in = $transport->reader;
EXAMPLE
App::FileSync::Protocol->new(in => $t->reader, out => $t->writer);
API SPECIFICATION
INPUT
[ { name => 'self', type => 'object' } ]
OUTPUT
{ type => 'object' }
MESSAGES
None.
FORMAL SPECIFICATION
reader = self.reader ; writer = self.writer
close
Purpose: end the session's process.
Args: none.
Returns: 1. Repeated calls do nothing.
Side Effects: closes both pipes (the server sees end of file) and reaps the child.
Usage:
$transport->close;
EXAMPLE
$transport->close; # safe to call twice
API SPECIFICATION
INPUT
[ { name => 'self', type => 'object' } ]
OUTPUT
{ type => 'integer', memberof => [ 1 ] }
MESSAGES
None.
FORMAL SPECIFICATION
closed' = 1 ∧ child ¬in; processes'
error_text
Purpose: what the transport itself said, for when the protocol failed.
Args: none.
Returns: an empty string: the local server writes its diagnostics to this process's own standard error, which the user already sees.
Side Effects: none.
Usage:
my $text = $transport->error_text;
EXAMPLE
print $transport->error_text, "\n";
API SPECIFICATION
INPUT
[ { name => 'self', type => 'object' } ]
OUTPUT
{ type => 'string' }
MESSAGES
None.
FORMAL SPECIFICATION
error_text = ""
LIMITATIONS
The child runs with this process's privileges: a local transport cannot enforce the separation an SSH forced command gives, so anyone who can run it can write the server root directly anyway.
AUTHOR
Nigel Horne, <njh at nigelhorne.com>
LICENCE AND COPYRIGHT
Copyright 2026 Nigel Horne.
Usage is subject to the GPL2 licence terms. If you use it, please let me know.