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 (17 years, 6 months ago) by elmex
Branch: MAIN
Changes since 1.1: +11 -6 lines
Log Message:
further improvements on the json irc client

File Contents

# Content
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 while ($$buf =~ m/^(\s*(\d+) )(.*)$/s) {
153 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 } else {
159 return
160 }
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 my $self = { @_, disconnect_cb => sub {} };
172 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 );
188 die "couldn't connect to server '$host:$port': $!\n" unless $sock->connected;
189
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 $self->{disconnect_cb}->("EOF from json server '$host:$port'");
204 return;
205
206 } else {
207 $self->{disconnect_cb}->("Error while reading from json server '$host:$port': $!");
208 return;
209 }
210 }
211 });
212 }
213
214 sub handle_data {
215 my ($self, $buf) = @_;
216
217 while ($$buf =~ m/^(\s*(\d+) )(.*)$/s) {
218 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 } else {
224 return
225 }
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;