/[wait]/branches/unido/lib/WAIT/Server.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /branches/unido/lib/WAIT/Server.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 106 - (show annotations)
Tue Jul 13 12:22:09 2004 UTC (19 years, 9 months ago) by dpavlin
File size: 9735 byte(s)
Changes made by Andreas J. Koenig <andreas.koenig(at)anima.de> for Unido project

1 # -*- Mode: Perl -*-
2 # $Basename: Server.pm $
3 # $Revision: 1.5 $
4 # ITIID : $ITI$ $Header $__Header$
5 # Author : Ulrich Pfeifer
6 # Created On : Sat Sep 28 13:53:36 1996
7 # Last Modified By: Ulrich Pfeifer
8 # Last Modified On: Sun Nov 22 18:44:38 1998
9 # Language : CPerl
10 # Update Count : 280
11 # Status : Unknown, Use with caution!
12 #
13 # Copyright (c) 1996-1997, Ulrich Pfeifer
14 #
15
16 package WAIT::Server;
17 use vars qw($VERSION @ISA @EXPORT);
18 use WAIT::Config;
19 use IO::Socket;
20 use IO::Select;
21 use strict;
22 use sigtrap qw(handler IGNORE error-signals);
23 require Exporter;
24 @ISA = qw(Exporter);
25 @EXPORT = qw(server);
26
27 my($ver) = '$ProjectVersion: 18.1 $ ' =~ /([\d.]+)/; $VERSION = sprintf '%5.3f', $ver/10;
28
29 sub server {
30 my %opt = @_;
31 my $port = $opt{port} || $WAIT::Config->{port} || 1404;
32
33 my $lsn = new WAIT::Handle(Reuse => 1,
34 Listen => 5,
35 LocalPort => $port,
36 Proto => 'tcp');
37 die "Could not connect to port $port: $!\n" unless defined $lsn;
38
39 my $SEL = new IO::Select( $lsn );
40 my %CON;
41 my $fh;
42 my @ready;
43
44 print "listening on port $port\n";
45
46 while(1) {
47 alarm(0);
48 @ready = $SEL->can_read;
49 #printf STDERR "=== %s %s\n", unpack ('b*', $SEL->[0]), join ':', @ready;
50 #sleep 1;
51 REQUEST:
52 alarm(25);
53 foreach $fh (@ready) {
54 if($fh == $lsn) {
55 my $new = $lsn->accept; # Create a new socket
56 $CON{$new} = new WAIT::Server::Connection $new, $VERSION;
57 $SEL->add($new);
58 } else {
59 my ($cmd, $func, @args, @cmd);
60 my $fno = fileno($fh);
61
62 $cmd = $fh->getline();
63 if ($cmd =~ /^post/i) {
64 /`/;
65 my $buf =
66 $cmd .
67 join('', @{${*$fh}{'net_cmd_lines'}}) .
68 ${*$fh}{'net_cmd_partial'};
69 ($cmd) = ($buf =~ /^Command: (.*)$/m);
70 ($cmd, @cmd) = (split (/:/, $cmd), 'quit');
71 ${*$fh}{'net_cmd_partial'} = '';
72 /`/;
73 $CON{$fh}->{http} = 1;
74 }
75 COMMAND:
76 for $cmd ($cmd, @cmd) {
77 ($func, @args) = split ' ', $cmd;
78 unless (fileno($fh)) {
79 printf STDERR "Shuttig down $fh(%d)\n", $fno;
80 delete $CON{$fh};
81 $SEL->remove($fno);
82 next REQUEST;
83 }
84 $func = lc($func);
85 $func = $CON{$fh}->dispatch($func, @args);
86 if ($func eq 'quit') {
87 printf STDERR "closed\n";
88 $SEL->remove($fh);
89 $CON{$fh}->close;
90 delete $CON{$fh};
91 last COMMAND;
92 }
93 }
94 }
95 }
96 }
97 }
98
99 package WAIT::Handle;
100 use Net::Cmd;
101 use IO::Socket;
102 use vars qw(@ISA);
103 use strict;
104
105 @ISA = qw(Net::Cmd IO::Socket::INET);
106
107 # Snarfed from Net::Cmd; we don't expect an answer.
108 sub dataend
109 {
110 my $cmd = shift;
111
112 return 1
113 unless(exists ${*$cmd}{'net_cmd_lastch'});
114
115 if(${*$cmd}{'net_cmd_lastch'} eq "\015")
116 {
117 syswrite($cmd,"\012",1);
118 print STDERR "\n"
119 if($cmd->debug);
120 }
121 elsif(${*$cmd}{'net_cmd_lastch'} ne "\012")
122 {
123 syswrite($cmd,"\015\012",2);
124 print STDERR "\n"
125 if($cmd->debug);
126 }
127
128 print STDERR "$cmd>>> .\n"
129 if($cmd->debug);
130
131 syswrite($cmd,".\015\012",3);
132
133 delete ${*$cmd}{'net_cmd_lastch'};
134
135 }
136
137 package WAIT::Server::Connection;
138 use strict;
139 use Sys::Hostname;
140 use Socket qw(AF_INET unpack_sockaddr_in);
141 use vars qw(%CMD %MSG %HELP);
142
143 my $HOST = hostname;
144 {
145 no strict;
146 local *stab = *WAIT::Server::Connection::;
147 my ($key,$val);
148 while (($key,$val) = each(%stab)) {
149 next unless $key =~ /^cmd_(.*)/;
150 local(*ENTRY) = $val;
151 if (defined &ENTRY) {
152 $CMD{$1} = \&ENTRY;
153 }
154 }
155 }
156
157
158 sub new {
159 my $type = shift;
160 my $fh = shift;
161 my $msg = shift;
162 my $self = {_fh => $fh};
163
164 my $hersockaddr = $fh->peername();
165 my ($port, $iaddr) = unpack_sockaddr_in($hersockaddr);
166 my $peer = gethostbyaddr($iaddr, AF_INET);
167 $self->{peer} = $peer;
168 $self->{database} = 'DB';
169 $self->{table} = 'cpan';
170 $self->{hits} = 10;
171 print "Connection from $peer\n";
172 bless $self, $type;
173 $self->msg(200, $msg);
174 $self;
175 }
176
177 sub close {
178 my $self = shift;
179
180 $self->{_fh}->close;
181 }
182
183
184 sub dispatch {
185 my $self = shift;
186 my $cmd = shift;
187
188 print "$cmd @_\n";
189 unless (exists $CMD{$cmd}) {
190 $self->msg(500);
191 } else {
192 &{$CMD{$cmd}}($self, @_);
193 }
194 $cmd;
195 }
196
197 sub msg {
198 my $self = shift;
199 my $code = shift;
200 my $msg = $MSG{$code} || '';
201 printf("%s %s %03d $msg\r\n", scalar(localtime(time)), $self->{peer}, $code, @_);
202 $self->{_fh}->datasend(sprintf("%03d $msg\r\n", $code, @_));
203 }
204
205 sub end {
206 my $self = shift;
207 $self->{_fh}->dataend;
208 }
209
210
211 require WAIT::Query::Wais;
212 require WAIT::Database;
213 use Fcntl;
214
215 my %DB; # cache Databas handles
216 sub DATABASE {
217 my $dn = shift;
218
219 return $DB{$dn} if exists $DB{$dn};
220 $DB{$dn} = WAIT::Database->open(name => $dn,
221 directory => $WAIT::Config->{'WAIT_home'},
222 mode => O_RDONLY);
223 return $DB{$dn};
224 }
225
226 my %TB; # cache Table handles
227 sub TABLE {
228 my ($dbname, $tname) = @_;
229
230 return $TB{$dbname.$tname} if exists $TB{$dbname.$tname};
231 my $db = DATABASE($dbname);
232
233 $TB{$dbname.$tname} = $db->table(name => $tname);
234 $TB{$dbname.$tname};
235 }
236
237
238 # helpers
239 sub result {
240 my $self = shift;
241 my $hit = shift;
242 my $did;
243
244 # http uses raw document id's
245 if ($self->{http}) {
246 return $hit;
247 }
248 unless ($self->{result}) {
249 $self->msg(404);
250 return;
251 }
252 unless ($did = $self->{result}->[$hit-1]) {
253 $self->msg(405);
254 return;
255 }
256 return $did;
257 }
258
259 sub table {
260 my $self = shift;
261
262 TABLE($self->{database}, $self->{table});
263 }
264
265 sub output {
266 my $self = shift;
267
268 $self->{_fh}->datasend(@_);
269 }
270
271
272 # The commands
273
274 sub cmd_help {
275 my $self = shift;
276
277 $self->msg(100);
278 for (sort keys %CMD) {
279 $self->output(sprintf("%-15s %s\r\n", $_, $HELP{$_}||''));
280 }
281 $self->end;
282 }
283
284 sub cmd_quit {
285 my $self = shift;
286 $self->msg(205);
287 }
288
289 sub cmd_database {
290 my $self = shift;
291 my $dbname = shift || $self->{database};
292
293
294 if (DATABASE($dbname)) {
295 delete $self->{'result'};
296 $self->{database} = $dbname;
297 $self->msg(201, $dbname);
298 } else {
299 $self->msg(401, $dbname);
300 }
301 }
302
303 sub cmd_table {
304 my $self = shift;
305 my $table = shift || $self->{'table'};
306 my $dbname = $self->{'database'};
307
308 if (TABLE($dbname, $table)) {
309 delete $self->{'result'};
310 $self->{'table'} = $table;
311 $self->msg(202, $table);
312 } else {
313 $self->msg(402, $table);
314 }
315 }
316
317 sub cmd_hits {
318 my $self = shift;
319 my $hits = shift;
320
321 if ($hits) {
322 $self->{hits} = $hits;
323 $self->msg(204, $hits);
324 } else {
325 $self->msg(501);
326 }
327 }
328
329 sub cmd_info {
330 my $self = shift;
331 my $hit = shift;
332
333 my $did = $self->result($hit);
334 return unless $did;
335
336 my $tb = $self->table;
337
338 my %rec = $tb->fetch($did);
339 $self->msg(207, $did);
340 for (keys %rec) {
341 $self->{_fh}->datasend(sprintf("%-15s %s\n", $_, $rec{$_}));
342 }
343 $self->end;
344 }
345
346 sub cmd_get {
347 my $self = shift;
348 my $hit = shift;
349 my $did = $self->result($hit);
350
351 return unless $did;
352 my $tb = $self->table;
353 my %rec = $tb->fetch($did);
354 my $key = $rec{docid};
355
356 $key = $tb->dir . '/' . $key if $key =~ m(^data/);
357
358 my $text = $tb->fetch_extern($key);
359
360 $self->msg(206, $did);
361 $self->output($text);
362 $self->output("\n") unless $text =~ /\n$/;
363 $self->end;
364 }
365
366 sub cmd_search {
367 my $self = shift;
368 my $query = join ' ', @_;
369 my $tb = $self->table;
370
371 my $wq = eval {WAIT::Query::Wais::query($tb, $query)};
372 unless ($wq) {
373 $self->msg(403);
374 return;
375 }
376 my %hits = $wq->execute();
377 my @did = sort {$hits{$b} <=> $hits{$a}}keys %hits;
378
379 # sanity check. this is expensive and should be obsolete!
380 # @did = grep $tb->fetch($_), @did;
381
382 $self->{'result'} = \@did;
383 my $all_hits = scalar @did;
384 my $send_hits = $all_hits;
385
386 if ($send_hits > $self->{hits}) {
387 $send_hits = $self->{hits};
388 }
389 $self->msg(203, $all_hits, $send_hits);
390 my $i;
391
392 for ($i=1;$i<=$send_hits;$i++) {
393 my $did = $did[$i-1];
394 my %rec = $tb->fetch($did);
395 $self->{_fh}->datasend(sprintf("%2d %5.3f %s\n",
396 $self->{http}?$did:$i,
397 $hits{$did},
398 $rec{headline}));
399 }
400 $self->end();
401 }
402
403 # read status messages
404 my $line;
405 while (defined ($line = <DATA>)) {
406 chomp($line);
407 my ($cmd, $msg) = split ' ', $line, 2;
408 last unless $cmd;
409 $HELP{$cmd} = $msg;
410 }
411 while (defined ($line = <DATA>)) {
412 chomp($line);
413 next unless $line =~ /^\d/;
414 my ($code, $msg) = split ' ', $line, 2;
415 $MSG{$code} = $msg;
416 }
417
418
419 1;
420
421 __DATA__
422 help - display this help message
423 database name set database name
424 table name set table name
425 search query submitt query
426 get number fetch full text of hit with number
427 info number display info record of hit with number
428 format text|html|term
429 hits number set maximum hits displayed to number
430 quit
431
432 100 help message follows
433 200 WAIT server %s ready
434 205 closing connection - goodbye!
435 201 database %s selected
436 401 could not open database %s
437 202 table %s selected
438 203 query returnes %d hits, %d hits follow
439 204 will return %d hits
440 207 record %d follows
441 206 text of record %d follows
442 402 could not open table %s
443 403 syntax error in query
444 404 use search first
445 405 no such hit
446 500 command not recognized
447 501 command syntax error
448 502 access restriction or permission denied
449 503 program fault - command not performed
450 1;

  ViewVC Help
Powered by ViewVC 1.1.26