ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Net-IRC3/samples/jsonclient
Revision: 1.7
Committed: Mon Jan 15 17:41:42 2007 UTC (19 years, 8 months ago) by elmex
Branch: MAIN
Changes since 1.6: +26 -0 lines
Log Message:
just a minor change on the json chat

File Contents

# Content
1 #!/usr/bin/perl
2 use strict;
3 use utf8;
4 use URI;
5 use JSONConnection;
6 use JSON::Syck;
7 use POSIX qw(strftime);
8 use CursesChatMainwindow;
9
10 our @highlight;
11 our $CFG;
12 our %known_ids;
13 our %rev_known_ids;
14 our $js;
15 our %completion = map { $_ => 1 } qw{
16 /buffer
17 /colors
18 /list_buffers
19 /reload /remote_reload /reconnect
20 };
21
22 my $d = 0;
23 my $wt;
24 sub timer {
25 $wt = AnyEvent->timer (after => 3, cb => sub {
26 printline (status => [0, "TEST $d"]); $d++;
27 timer ();
28 });
29 }
30
31 sub search_buffer {
32 my ($id) = @_;
33
34 for (keys %{$::CFG->{buffers}}) {
35 if ($::CFG->{buffers}->{$_} eq $id) {
36 return $_;
37 }
38 }
39
40 return undef
41 }
42
43 sub write_chatline {
44 my ($buffer, $nick, $time, $msg, $mode) = @_;
45 my $nick_color = $mode eq 'local' ? 7 : ($mode eq 'private' ? 4 : 0);
46 my $ts = '[' . POSIX::strftime ("%T", localtime ($time)) . ']';
47 my (@chatline) = (("p".length $ts), 0, $ts, 0, " <", $nick_color, "$nick", 0, "> ", 0, $msg);
48 printline ($buffer, \@chatline);
49 }
50
51 sub write_infoline {
52 my ($buffer, $time, $msg) = @_;
53 my $ts = '[' . POSIX::strftime ("%T", localtime ($time)) . ']';
54 my (@chatline) = (("p".length $ts), 0, $ts, 0, " ", 3, $msg);
55 printline ($buffer, \@chatline);
56 }
57
58
59 sub load_cfg {
60 $CFG ||= {};
61 return unless -e "$ENV{HOME}/.jsonircclrc";
62 open CFGH, "<", "$ENV{HOME}/.jsonircclrc" or die "Couldn't open ~/.jsonircclrc: $!";
63 $::CFG = JSON::Syck::Load (do { local $/; <CFGH> });
64 }
65
66 sub maybe_pop_highlight {
67 my ($buffer) = @_;
68 @highlight = grep { $buffer ne $_->[0] } @highlight;
69 printline (msgline => [map { (103, $_->[1] || $_->[0], 0, ' ') } @highlight]);
70 }
71
72 sub push_highlight {
73 my ($id) = @_;
74
75 unless (grep { $_->[0] eq $id } (@highlight, [current_buffer ()])) {
76 push @highlight, [$id, search_buffer ($id)];
77 printline (msgline => [map { (103, $_->[1] || $_->[0], 0, ' ') } @highlight]);
78 }
79 }
80
81 sub change_buffer {
82 my ($new_buf) = @_;
83 maybe_pop_highlight ($new_buf);
84 select_buffer ($new_buf);
85 }
86
87 sub prettyfy_id {
88 my ($id) = @_;
89 my $uri = URI->new ($id);
90 my $a = $uri->authority;
91 my $p = ($uri->path_segments ())[1];
92 $rev_known_ids{"$a/$p"} = $id;
93 "$a/$p"
94 }
95
96 load_cfg ();
97
98 my $c = AnyEvent->condvar;
99
100 #timer ();
101
102 $js =
103 JSONClientConnection->new (
104 packet_cb => sub {
105 my ($js, $data) = @_;
106 require JSON::Syck;
107
108 if ($data->{type} eq 'message') {
109 my ($src_id) = ($data->{src});
110 my $pretty_id = prettyfy_id ($src_id);
111 $known_ids{$src_id}->{send_id} = $data->{to}->{id};
112
113 if ($data->{msg_type} eq 'private') {
114 push_highlight ($pretty_id);
115 } else {
116 for (@{$::CFG->{highlight}}) {
117 if ($data->{message} =~ m/$_/) {
118 push_highlight ($pretty_id);
119 }
120 }
121 }
122
123 write_chatline ($pretty_id, prettyfy_id ($data->{from}->{id}), $data->{timestamp}, $data->{message}, $data->{msg_type});
124
125 } elsif ($data->{type} eq 'metainfo') {
126 my $src_id = $data->{src};
127 my $pretty_id = prettyfy_id ($src_id);
128 my $it = $data->{info_type};
129
130 if ($it eq 'add_ids') {
131 write_infoline ($pretty_id, $data->{timestamp},
132 "channel add: " . join (', ', map { prettyfy_id ($_) } @{$data->{ids}}));
133
134 } elsif ($it eq 'remove_ids') {
135 write_infoline ($pretty_id, $data->{timestamp},
136 "channel remove: " . join (', ', map { prettyfy_id ($_) } @{$data->{ids}}));
137
138 } elsif ($it eq 'special') {
139 write_infoline ($pretty_id, $data->{timestamp}, "[$data->{message}]");
140 }
141
142 } elsif ($data->{type} eq 'info') {
143 printline (status => [3, 'INFO: ' . $data->{message}]);
144 } elsif ($data->{type} eq 'error') {
145 printline (status => [4, 'INFO: ' . $data->{message}]);
146 }
147
148 printline (debug => [0, JSON::Syck::Dump ($data)]);
149 },
150 disconnect_cb => sub {
151 printline (status => [4, "ERROR: " . $_[0]]);
152 }
153 );
154
155 $js->connect (localhost => 1236);
156
157 CursesChatMainwindow::init;
158
159 printline (status => ['p0', 0, "Connected!"]);
160 printline (statusline => [20, "Welcome to the json enhanced chat framework!"]);
161
162 sub find_common_prefix {
163 my (@words) = @_;
164 @words = sort { length ($a) <=> length ($b) } @words;
165 my $shortest = $words[0];
166
167 while ($shortest ne '') {
168 my $no_match = 0;
169 for (@words) {
170 unless (/^\Q$shortest\E/) {
171 $no_match = 1;
172 last;
173 }
174 }
175
176 return $shortest if not $no_match;
177 substr $shortest, -1, 1, '';
178 }
179
180 return '';
181 }
182
183 CursesChatMainwindow::register_complete_cb (sub {
184 my ($word, $first_compl, $idx, @line) = @_;
185
186 # TODO: make completion cycling with $first_compl
187 printline (undef, [0, "f[$first_compl] [$idx] [$word]"]);
188
189 my @found;
190
191 if ($idx == 0) {
192 for (keys %completion) {
193 if (/^\Q$word\E/) {
194 push @found, $_;
195 }
196 }
197
198 } else {
199 my %buffers = map { $_ => 1 } list_buffers;
200
201 for (keys %rev_known_ids) {
202 delete $buffers{$_};
203 if (/^\Q$word\E/) {
204 push @found, $_;
205 }
206 }
207
208 for (keys %buffers) {
209 if (/^\Q$word\E/) {
210 push @found, $_;
211 }
212 }
213 }
214
215 return "$found[0] " if @found == 1;
216
217 if (@found) {
218 printline (undef, [0, "$word: " . join ", ", @found]);
219 return find_common_prefix (@found);
220 }
221
222 return $word;
223 });
224
225 CursesChatMainwindow::register_input_cb (sub {
226 my ($input, $escape) = @_;
227
228 unless (defined $input) {
229 if (exists $CFG->{buffers}->{$escape}) {
230 change_buffer (my $buf = $CFG->{buffers}->{$escape} || 'status');
231 printline (statusline => [20, "[$buf]"]);
232 } else {
233 change_buffer ('status');
234 printline (statusline => [20, "[status]"]);
235 }
236 return;
237 }
238
239 if ($input =~ m/^\/buffer\s*(\S+)/) {
240 change_buffer ("$1");
241 printline (statusline => [20, "[$1]"]);
242
243 } elsif ($input =~ m/^\/list_buffers/) {
244 printline (undef, [0, "buffers:"]);
245 for (list_buffers) {
246 printline (undef, [0, "- $_"]);
247 }
248
249 } elsif ($input =~ m/^\/colors/) {
250 CursesChatMainwindow::print_colors;
251
252 } elsif ($input =~ m/^\/reconnect\s*(\S*)\s*(\S*)/) {
253 $js->connect ($1 || 'localhost', $2 || 1236);
254 printline (status => [3, "reconnected"]);
255
256 } elsif ($input =~ m/^\/reload/) {
257 load_cfg ();
258
259 } elsif ($input =~ m/^\/remote_reload/) {
260 $js->send_data ({ type => 'command', command => 'reload' });
261
262 } else {
263 my $pret_id = "" . current_buffer ();
264 my $dest_id = $rev_known_ids{$pret_id};
265
266 my $msg = {
267 type => 'message',
268 dest => $dest_id,
269 message => $input
270 };
271 $js->send_data ($msg);
272 printline (debug => [0, JSON::Syck::Dump ($msg)]);
273 my $mynick = $known_ids{$dest_id}->{send_id} ? prettyfy_id ($known_ids{$dest_id}->{send_id}) : "";
274 write_chatline ($pret_id, $mynick, time, $input, 'local');
275 }
276 });
277
278 $c->wait;
279
280 CursesChatMainwindow::end;