ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Net-IRC3/samples/JSONConnection.pm
Revision: 1.2
Committed: Mon Dec 25 19:39:41 2006 UTC (19 years, 9 months ago) by elmex
Branch: MAIN
Changes since 1.1: +11 -6 lines
Log Message:
further improvements on the json irc client

File Contents

# User Rev Content
1 elmex 1.1 package SOMEConnection;
2     use strict;
3     use Socket;
4     use AnyEvent;
5     use IO::Socket::INET;
6    
7     sub new {
8     my $this = shift;
9     my $class = ref($this) || $this;
10     my $self = {@_};
11     bless $self, $class;
12     return $self;
13     }
14    
15     sub client_connect {
16     my ($self, $lid) = @_;
17     }
18    
19     sub client_disconnect {
20     my ($self, $lid) = @_;
21     }
22    
23     sub start_listener {
24     my ($self) = @_;
25    
26     my $sock = IO::Socket::INET->new(
27     Listen => 5,
28     ReuseAddr => 1,
29     Reuse => 1,
30     LocalPort => 1236,
31     Proto => 'tcp'
32     );
33    
34     $sock or die "Couldn't create listener: $!";
35    
36     $self->{listener} =
37     AnyEvent->io (poll => 'r', fh => $sock, cb => sub {
38     my $cl = $sock->accept ()
39     or die "couldn't accept client: $!";
40     binmode $cl;
41     $cl->autoflush (1);
42     $self->handle_client ($cl);
43     });
44     }
45    
46     sub write_data {
47     my ($self, $lid, $data) = @_;
48     return unless $self->{$lid . '_r'};
49    
50     my $cl = $self->{$lid}->{socket};
51     $self->{$lid}->{write_buffer} .= $data;
52    
53     unless ($self->{$lid . '_w'}) {
54     $self->{$lid . '_w'} =
55     AnyEvent->io (poll => 'w', fh => $cl, cb => sub {
56     if (my $data = $self->{$lid}->{write_buffer}) {
57     my $len = syswrite $cl, $data;
58     unless ($len) {
59     if (not defined $len) {
60     warn "error when writing data on $lid: $!";
61     return;
62     } else {
63     delete $self->{$lid . '_w'};
64     }
65     }
66    
67     if ($len == length $self->{$lid}->{write_buffer}) {
68     delete $self->{$lid . '_w'};
69     }
70    
71     $self->{$lid}->{write_buffer} = substr $self->{$lid}->{write_buffer}, $len;
72     }
73     });
74     }
75     }
76    
77     sub handle_client {
78     my ($self, $cl) = @_;
79     my ($chost, $cport) = ($cl->peerhost (), $cl->peerport ());
80     my $lid = "$chost:$cport";
81    
82     $self->{$lid}->{socket} = $cl;
83    
84     $self->{$lid . '_r'} =
85     AnyEvent->io (poll => 'r', fh => $cl, cb => sub {
86     my $res = sysread $cl, my $data, 1024;
87     if ($res) {
88     $self->{$lid}->{read_buffer} .= $data;
89     $self->handle_data ($lid, \$self->{$lid}->{read_buffer});
90     } else {
91     if (not defined $res) {
92     warn "error when receiving data on $lid: $!";
93     } else {
94     warn "got eof on $lid: $!";
95     }
96     $self->close_client ($lid);
97     }
98     });
99    
100     $self->client_connect ($lid);
101     }
102    
103     sub handle_data {
104     my ($self, $lid, $buf) = @_;
105     die "implement";
106     }
107    
108     sub close_client {
109     my ($self, $lid) = @_;
110     eval { delete $self->{$lid}->{socket} };
111     delete $self->{$lid . '_r'};
112     delete $self->{$lid . '_w'};
113     delete $self->{$lid};
114     $self->client_disconnect ($lid);
115     }
116    
117     package JSONConnection;
118     use strict;
119     our @ISA = qw/SOMEConnection/;
120     use JSON::Syck;
121    
122     our %CLIENTS;
123    
124     sub client_connect {
125     my ($self, $lid) = @_;
126     $CLIENTS{$lid} = 1;
127     $self->{connect_cb}->($self, $lid);
128     }
129    
130     sub client_disconnect {
131     my ($self, $lid) = @_;
132     delete $CLIENTS{$lid};
133     }
134    
135     sub broadcast {
136     my ($self, $data) = @_;
137     for (keys %CLIENTS) {
138     $self->send_data ($_, $data);
139     }
140     }
141    
142     sub send_data {
143     my ($self, $lid, $data) = @_;
144    
145     my $dump = JSON::Syck::Dump ($data);
146     $self->write_data ($lid, (length $dump) . " " . $dump . "\015\012");
147     }
148    
149     sub handle_data {
150     my ($self, $lid, $buf) = @_;
151    
152 elmex 1.2 while ($$buf =~ m/^(\s*(\d+) )(.*)$/s) {
153 elmex 1.1 my ($prefix, $len, $rembuf) = ($1, $2, $3);
154     if ((length $rembuf) >= $len) {
155     my $data = substr $rembuf, 0, $len;
156     substr $$buf, 0, (length $prefix) + (length $data), '';
157     $self->{packet_cb}->($self, $lid, JSON::Syck::Load ($data));
158 elmex 1.2 } else {
159     return
160 elmex 1.1 }
161     }
162     }
163    
164     package JSONClientConnection;
165     use strict;
166     use JSON::Syck;
167    
168     sub new {
169     my $this = shift;
170     my $class = ref($this) || $this;
171 elmex 1.2 my $self = { @_, disconnect_cb => sub {} };
172 elmex 1.1 bless $self, $class;
173     return $self;
174     }
175    
176     sub connect {
177     my ($self, $host, $port) = @_;
178    
179     $self->{socket}
180     and return;
181    
182     my $sock = IO::Socket::INET->new (
183     PeerAddr => $host,
184     PeerPort => $port,
185     Proto => 'tcp',
186     Blocking => 0
187 elmex 1.2 );
188     die "couldn't connect to server '$host:$port': $!\n" unless $sock->connected;
189 elmex 1.1
190     $self->{socket} = $sock;
191     $self->{host} = $host;
192     $self->{port} = $port;
193    
194     $self->{r} =
195     AnyEvent->io (poll => 'r', fh => $sock, cb => sub {
196     my $l = sysread $sock, my $data, 1024;
197    
198     $self->{read_buffer} .= $data;
199     $self->handle_data (\$self->{read_buffer});
200    
201     unless ($l) {
202     if (defined $l) {
203 elmex 1.2 $self->{disconnect_cb}->("EOF from json server '$host:$port'");
204 elmex 1.1 return;
205    
206     } else {
207 elmex 1.2 $self->{disconnect_cb}->("Error while reading from json server '$host:$port': $!");
208 elmex 1.1 return;
209     }
210     }
211     });
212     }
213    
214     sub handle_data {
215     my ($self, $buf) = @_;
216    
217 elmex 1.2 while ($$buf =~ m/^(\s*(\d+) )(.*)$/s) {
218 elmex 1.1 my ($prefix, $len, $rembuf) = ($1, $2, $3);
219     if ((length $rembuf) >= $len) {
220     my $data = substr $rembuf, 0, $len;
221     substr $$buf, 0, (length $prefix) + (length $data), '';
222     $self->{packet_cb}->($self, JSON::Syck::Load ($data));
223 elmex 1.2 } else {
224     return
225 elmex 1.1 }
226     }
227     }
228    
229     sub send_data {
230     my ($self, $data) = @_;
231     my $dump = JSON::Syck::Dump ($data);
232     $self->write_data ((length $dump) . " " . $dump . "\015\012");
233     }
234    
235     sub write_data {
236     my ($self, $data) = @_;
237     return unless $self->{r};
238    
239     my $cl = $self->{socket};
240     $self->{write_buffer} .= $data;
241    
242     unless ($self->{w}) {
243     $self->{w} =
244     AnyEvent->io (poll => 'w', fh => $cl, cb => sub {
245     if (my $data = $self->{write_buffer}) {
246     my $len = syswrite $cl, $data;
247     unless ($len) {
248     if (not defined $len) {
249     warn "error when writing data on $self->{host}:$self->{port}: $!";
250     return;
251     } else {
252     delete $self->{w};
253     }
254     }
255    
256     if ($len == length $self->{write_buffer}) {
257     delete $self->{w};
258     }
259    
260     $self->{write_buffer} = substr $self->{write_buffer}, $len;
261     }
262     });
263     }
264     }
265    
266     1;