/[wait]/branches/CPAN/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

Annotation of /branches/CPAN/lib/WAIT/Server.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (hide annotations)
Tue May 9 11:29:45 2000 UTC (24 years ago) by ulpfr
File size: 9735 byte(s)
Import of WAIT-1.800

1 ulpfr 10 # -*- 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 ulpfr 19 my($ver) = '$ProjectVersion: 18.1 $ ' =~ /([\d.]+)/; $VERSION = sprintf '%5.3f', $ver/10;
28 ulpfr 10
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;

Properties

Name Value
cvs2svn:cvs-rev 1.1.1.3

  ViewVC Help
Powered by ViewVC 1.1.26