Remote REPL for debugging a Thrasher daemon.
[thrasher.git] / perl / lib / Net / REPL / Base.pm
blob6e902966e1f70a69a6c62802d9ef030b88cabe12
1 package Net::REPL::Base;
2 use strict;
3 use warnings;
5 =pod
7 =head1 NAME
9 Net::REPL::Base - Utilities for REPL clients and servers.
11 =head1 DESCRIPTION
13 This contains the protocol implementation and various other simple
14 utilities.
16 The REPL protocol uses length/value strings. A value is encoded to one
17 of these strings by concatenating its 32-bit unsigned big-endian
18 length with the value as a bytestring.
20 =head2 Methods
22 =cut
24 use Data::Dumper;
26 =head3 lv_receive()
28 Read and return one length/value encoded string from the file handle.
30 Dies if an error (like the socket closing unexpectedly) occurs during
31 the read call. Returns a partial string or undef if the read is merely
32 incomplete.
34 =cut
36 sub lv_receive {
37 my ($self) = @_;
39 my $total_length = unpack('N', $self->_read_or_die(4));
40 if (not defined($total_length)) {
41 return;
43 # $self->debug('Incoming message:', $total_length);
44 my $message = $self->_read_or_die($total_length);
45 return unpack('a*', $message);
48 sub _read_or_die {
49 my ($self, $length) = @_;
51 my $data;
52 my $result = sysread($self->{'fh'}, $data, $length);
53 if (not defined($result)) {
54 die("REPL PID $$: $!");
56 return $data;
60 =head3 lv_send($message)
62 Encode $message as a length/value string and write it to the file handle.
64 =cut
66 sub lv_send {
67 my ($self, $message) = @_;
69 my $length = length($message);
70 my $initial = pack('N', $length);
71 $self->{'fh'}->send($initial . $message);
72 $self->{'fh'}->flush();
75 =head3 debug(@words)
77 Write words to the debug log according to the current debug level.
79 The default implementation writes to STDERR and uses the debug level
80 as a boolean (i.e., 0 or other false values disable it).
82 =cut
84 sub debug {
85 my ($self, @words) = @_;
87 if ($self->{'debug'}) {
88 print STDERR join(' ', 'REPL:', @words) . "\n";
92 =head3 formatted_eval($code)
94 Eval the Perl $code and return the Dumper'd or serialized result.
96 =cut
98 # TODO: integrate with Devel::REPL
99 sub formatted_eval {
100 my ($self, $input) = @_;
102 my @output = eval('sub { ' . $input . '}->();');
103 # TODO: should this also pass through warnings?
104 if ($@) {
105 return $@;
107 else {
108 my $dumper = Data::Dumper->new(\@output);
109 $dumper->Deparse(1);
110 return $dumper->Dump();