ConnectionManager: Disable hard limit in favor of twiddled hammering values.
[thrasher.git] / perl / lib / Net / REPL / Base.pm
blob57ede17dcfdb79d0aff64fae997689743f4e98bf
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;
25 use IO::Socket;
27 =head3 lv_receive()
29 Read and return one length/value encoded string from the file handle.
31 Dies if an error (like the socket closing unexpectedly) occurs during
32 the read call. Returns a partial string or undef if the read is merely
33 incomplete.
35 =cut
37 sub lv_receive {
38 my ($self) = @_;
40 my $total_length = unpack('N', $self->_read_fh(4));
41 if (not defined($total_length)) {
42 return;
44 # $self->debug('Incoming message:', $total_length);
45 my $message = $self->_read_fh($total_length);
46 return unpack('a*', $message);
49 sub _read_fh {
50 my ($self, $length) = @_;
52 my $data;
53 my $result = sysread($self->{'fh'}, $data, $length);
54 if (not defined($result)) {
55 $self->debug("REPL PID $$ reading: $!")
57 return $data;
61 =head3 lv_send($message)
63 Encode $message as a length/value string and write it to the file handle.
65 =cut
67 sub lv_send {
68 my ($self, $message) = @_;
70 my $length = length($message);
71 my $initial = pack('N', $length);
72 $self->{'fh'}->send($initial . $message);
73 $self->{'fh'}->flush();
76 =head3 debug(@words)
78 Write words to the debug log according to the current debug level.
80 The default implementation writes to STDERR and uses the debug level
81 as a boolean (i.e., 0 or other false values disable it).
83 =cut
85 sub debug {
86 my ($self, @words) = @_;
88 if ($self->{'debug'}) {
89 print STDERR join(' ', 'REPL:', @words) . "\n";
93 =head3 formatted_eval($code)
95 Eval the Perl $code and return the Dumper'd or serialized result.
97 =cut
99 # TODO: integrate with Devel::REPL
100 sub formatted_eval {
101 my ($self, $input) = @_;
103 my @output;
104 do {
105 local $SIG{'__DIE__'} = 'DEFAULT';
106 @output = eval('sub { ' . $input . '}->();');
108 # TODO: should this also pass through warnings?
109 if ($@) {
110 return $@;
112 else {
113 my $dumper = Data::Dumper->new(\@output);
114 $dumper->Deparse(1);
115 return $dumper->Dump();
119 ### Internal methods
121 sub _create_socket {
122 my ($self, %socket_args) = @_;
124 my $domain = $socket_args{'Domain'};
125 if (not defined($domain)) {
126 die('Socket "Domain" argument is mandatory');
129 my $pkg = $IO::Socket::domain2pkg[$domain];
130 if (defined($pkg)) {
131 eval("use $pkg;");
133 return IO::Socket->new(
134 %socket_args,