ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Net-IRC3/samples/JSONConnection.pm
Revision: 1.1
Committed: Wed Dec 6 13:12:11 2006 UTC (17 years, 7 months ago) by elmex
Branch: MAIN
Log Message:
added the json irc sample application

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 if ($$buf =~ m/^(\s*(\d+) )(.*)$/) {
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 }
159 }
160 }
161
162 package JSONClientConnection;
163 use strict;
164 use JSON::Syck;
165
166 sub new {
167 my $this = shift;
168 my $class = ref($this) || $this;
169 my $self = {@_};
170 bless $self, $class;
171 return $self;
172 }
173
174 sub connect {
175 my ($self, $host, $port) = @_;
176
177 $self->{socket}
178 and return;
179
180 my $sock = IO::Socket::INET->new (
181 PeerAddr => $host,
182 PeerPort => $port,
183 Proto => 'tcp',
184 Blocking => 0
185 ) or die "couldn't connect to irc server '$host:$port': $!\n";;
186
187 $self->{socket} = $sock;
188 $self->{host} = $host;
189 $self->{port} = $port;
190
191 $self->{r} =
192 AnyEvent->io (poll => 'r', fh => $sock, cb => sub {
193 my $l = sysread $sock, my $data, 1024;
194
195 $self->{read_buffer} .= $data;
196 $self->handle_data (\$self->{read_buffer});
197
198 unless ($l) {
199 if (defined $l) {
200 $self->disconnect ("EOF from json server '$host:$port'");
201 return;
202
203 } else {
204 $self->disconnect ("Error while reading from json server '$host:$port': $!");
205 return;
206 }
207 }
208 });
209 }
210
211 sub handle_data {
212 my ($self, $buf) = @_;
213
214 if ($$buf =~ m/^(\s*(\d+) )(.*)$/) {
215 my ($prefix, $len, $rembuf) = ($1, $2, $3);
216 if ((length $rembuf) >= $len) {
217 my $data = substr $rembuf, 0, $len;
218 substr $$buf, 0, (length $prefix) + (length $data), '';
219 $self->{packet_cb}->($self, JSON::Syck::Load ($data));
220 }
221 }
222 }
223
224 sub send_data {
225 my ($self, $data) = @_;
226 my $dump = JSON::Syck::Dump ($data);
227 $self->write_data ((length $dump) . " " . $dump . "\015\012");
228 }
229
230 sub write_data {
231 my ($self, $data) = @_;
232 return unless $self->{r};
233
234 my $cl = $self->{socket};
235 $self->{write_buffer} .= $data;
236
237 unless ($self->{w}) {
238 $self->{w} =
239 AnyEvent->io (poll => 'w', fh => $cl, cb => sub {
240 if (my $data = $self->{write_buffer}) {
241 my $len = syswrite $cl, $data;
242 unless ($len) {
243 if (not defined $len) {
244 warn "error when writing data on $self->{host}:$self->{port}: $!";
245 return;
246 } else {
247 delete $self->{w};
248 }
249 }
250
251 if ($len == length $self->{write_buffer}) {
252 delete $self->{w};
253 }
254
255 $self->{write_buffer} = substr $self->{write_buffer}, $len;
256 }
257 });
258 }
259 }
260
261 1;