ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/Debug.pm
Revision: 1.3
Committed: Thu Jul 30 03:41:56 2009 UTC (14 years, 11 months ago) by root
Branch: MAIN
CVS Tags: rel-5_28, rel-5_29, rel-5_21, rel-5_24, rel-5_26, rel-5_27, rel-5_12, rel-5_1, rel-5_0, rel-5_3, rel-5_2, rel-5_22, rel-5_261, rel-5_201, rel-5_202, rel-5_11, rel-5_23, rel-5_31, rel-5_01, rel-5_111, rel-5_112, rel-5_271, rel-5_251, rel-4_91, rel-4_9
Changes since 1.2: +2 -2 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     AnyEvent::Debug - debugging utilities for AnyEvent
4    
5     =head1 SYNOPSIS
6    
7     use AnyEvent::Debug;
8    
9     # create an interactive shell into the program
10     my $shell = AnyEvent::Debug::shell "unix/", "/home/schmorp/myshell";
11     # then on the shell: "socat readline /home/schmorp/myshell"
12    
13     =head1 DESCRIPTION
14    
15     This module provides functionality hopefully useful for debugging.
16    
17     At the moment, "only" an interactive shell is implemented. This shell
18     allows you to interactively "telnet into" your program and execute Perl
19     code, e.g. to look at global variables.
20    
21     =head1 FUNCTIONS
22    
23     =over 4
24    
25     =cut
26    
27     package AnyEvent::Debug;
28    
29     use Errno ();
30    
31     use AnyEvent (); BEGIN { AnyEvent::common_sense }
32     use AnyEvent::Util ();
33     use AnyEvent::Socket ();
34    
35     =item $shell = AnyEvent;::Debug::shell $host, $service
36    
37     This function binds on the given host and service port and returns a
38     shell object, whcih determines the lifetime of the shell. Any number
39     of conenctions are accepted on the port, and they will give you a very
40     primitive shell that simply executes every line you enter.
41    
42     All commands will be executed "blockingly" with the socket C<select>ed for
43     output. For a less "blocking" interface see L<Coro::Debug>.
44    
45     The commands will be executed in the C<AnyEvent::Debug::shell> package,
46     which is initially empty and up to use by all shells. Code is evaluated
47     under C<use strict 'subs'>.
48    
49     Consider the beneficial aspects of using more global (our) variables than
50     local ones (my) in package scope: Earlier all my modules tended to hide
51     internal variables inside C<my> variables, so users couldn't accidentally
52     access them. Having interactive access to your programs changed that:
53     having internal variables still in the global scope means you can debug
54     them easier.
55    
56     As no authenticsation is done, in most cases it is best not to use a TCP
57     port, but a unix domain socket, whcih cna be put wherever youc an access
58     it, but not others:
59    
60     our $SHELL = AnyEvent::Debug::shell "unix/", "/home/schmorp/shell";
61    
62     Then you can use a tool to connect to the shell, such as the ever
63     versatile C<socat>, which in addition can give you readline support:
64    
65     socat readline /home/schmorp/shell
66     # or:
67     cd /home/schmorp; socat readline unix:shell
68    
69     Socat can even give you a persistent history:
70    
71     socat readline,history=.anyevent-history unix:shell
72    
73     Binding on C<127.0.0.1> (or C<::1>) might be a less secure but sitll not
74     totally insecure (on single-user machines) alternative to let you use
75     other tools, such as telnet:
76    
77     our $SHELL = AnyEvent::Debug::shell "127.1", "1357";
78    
79     And then:
80    
81     telnet localhost 1357
82    
83     =cut
84    
85     sub shell($$) {
86     AnyEvent::Socket::tcp_server $_[0], $_[1], sub {
87     my ($fh, $host, $port) = @_;
88    
89 root 1.2 syswrite $fh, "Welcome, $host:$port!\015\012> ";
90 root 1.1 my $rbuf;
91 root 1.3 my $rw; $rw = AE::io $fh, 0, sub {
92 root 1.1 my $len = sysread $fh, $rbuf, 1024, length $rbuf;
93    
94     if (defined $len ? $len == 0 : $! != Errno::EAGAIN) {
95     undef $rw;
96     } else {
97     while ($rbuf =~ s/^(.*)\015?\012//) {
98     my $line = $1;
99    
100     AnyEvent::Util::fh_nonblocking $fh, 0;
101    
102     if ($line =~ /^\s*exit\b/) {
103     syswrite $fh, "sorry, no... if you want to execute exit, try CORE::exit.\015\012";
104     } else {
105     package AnyEvent::Debug::shell;
106    
107     no strict 'vars';
108     my $old_stdout = select $fh;
109     local $| = 1;
110    
111     my @res = eval $line;
112    
113     select $old_stdout;
114     syswrite $fh, "$@" if $@;
115     syswrite $fh, "\015\012";
116    
117     if (@res > 1) {
118     syswrite $fh, "$_: $res[$_]\015\012" for 0 .. $#res;
119     } elsif (@res == 1) {
120     syswrite $fh, "$res[0]\015\012";
121     }
122     }
123    
124     syswrite $fh, "> ";
125     AnyEvent::Util::fh_nonblocking $fh, 1;
126     }
127     }
128 root 1.3 };
129 root 1.1 }
130     }
131    
132     1;
133    
134     =back
135    
136     =head1 AUTHOR
137    
138     Marc Lehmann <schmorp@schmorp.de>
139     http://home.schmorp.de/
140    
141     =cut
142