/[Search-Estraier]/trunk/lib/Search/Estraier.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

Diff of /trunk/lib/Search/Estraier.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 53 by dpavlin, Fri Jan 6 14:39:45 2006 UTC revision 122 by dpavlin, Tue May 2 10:19:47 2006 UTC
# Line 4  use 5.008; Line 4  use 5.008;
4  use strict;  use strict;
5  use warnings;  use warnings;
6    
7  our $VERSION = '0.00';  our $VERSION = '0.05_1';
8    
9  =head1 NAME  =head1 NAME
10    
# Line 12  Search::Estraier - pure perl module to u Line 12  Search::Estraier - pure perl module to u
12    
13  =head1 SYNOPSIS  =head1 SYNOPSIS
14    
15    use Search::Estraier;  =head2 Simple indexer
16    my $est = new Search::Estraier();  
17            use Search::Estraier;
18    
19            # create and configure node
20            my $node = new Search::Estraier::Node(
21                    url => 'http://localhost:1978/node/test',
22                    user => 'admin',
23                    passwd => 'admin'
24            );
25    
26            # create document
27            my $doc = new Search::Estraier::Document;
28    
29            # add attributes
30            $doc->add_attr('@uri', "http://estraier.gov/example.txt");
31            $doc->add_attr('@title', "Over the Rainbow");
32    
33            # add body text to document
34            $doc->add_text("Somewhere over the rainbow.  Way up high.");
35            $doc->add_text("There's a land that I heard of once in a lullaby.");
36    
37            die "error: ", $node->status,"\n" unless (eval { $node->put_doc($doc) });
38    
39    =head2 Simple searcher
40    
41            use Search::Estraier;
42    
43            # create and configure node
44            my $node = new Search::Estraier::Node(
45                    url => 'http://localhost:1978/node/test',
46                    user => 'admin',
47                    passwd => 'admin',
48                    croak_on_error => 1,
49            );
50    
51            # create condition
52            my $cond = new Search::Estraier::Condition;
53    
54            # set search phrase
55            $cond->set_phrase("rainbow AND lullaby");
56    
57            my $nres = $node->search($cond, 0);
58    
59            if (defined($nres)) {
60                    print "Got ", $nres->hits, " results\n";
61    
62                    # for each document in results
63                    for my $i ( 0 ... $nres->doc_num - 1 ) {
64                            # get result document
65                            my $rdoc = $nres->get_doc($i);
66                            # display attribte
67                            print "URI: ", $rdoc->attr('@uri'),"\n";
68                            print "Title: ", $rdoc->attr('@title'),"\n";
69                            print $rdoc->snippet,"\n";
70                    }
71            } else {
72                    die "error: ", $node->status,"\n";
73            }
74    
75  =head1 DESCRIPTION  =head1 DESCRIPTION
76    
# Line 25  or Hyper Estraier development files on t Line 82  or Hyper Estraier development files on t
82  It is implemented as multiple packages which closly resamble Ruby  It is implemented as multiple packages which closly resamble Ruby
83  implementation. It also includes methods to manage nodes.  implementation. It also includes methods to manage nodes.
84    
85    There are few examples in C<scripts> directory of this distribution.
86    
87  =cut  =cut
88    
89  =head1 Inheritable common methods  =head1 Inheritable common methods
# Line 41  Remove multiple whitespaces from string, Line 100  Remove multiple whitespaces from string,
100  =cut  =cut
101    
102  sub _s {  sub _s {
103          my $text = $_[1] || return;          my $text = $_[1];
104            return unless defined($text);
105          $text =~ s/\s\s+/ /gs;          $text =~ s/\s\s+/ /gs;
106          $text =~ s/^\s+//;          $text =~ s/^\s+//;
107          $text =~ s/\s+$//;          $text =~ s/\s+$//;
# Line 106  sub new { Line 166  sub new {
166                          } elsif ($line =~ m/^$/) {                          } elsif ($line =~ m/^$/) {
167                                  $in_text = 1;                                  $in_text = 1;
168                                  next;                                  next;
169                          } elsif ($line =~ m/^(.+)=(.+)$/) {                          } elsif ($line =~ m/^(.+)=(.*)$/) {
170                                  $self->{attrs}->{ $1 } = $2;                                  $self->{attrs}->{ $1 } = $2;
171                                  next;                                  next;
172                          }                          }
173    
174                          warn "draft ignored: $line\n";                          warn "draft ignored: '$line'\n";
175                  }                  }
176          }          }
177    
# Line 205  Returns array with attribute names from Line 265  Returns array with attribute names from
265    
266  sub attr_names {  sub attr_names {
267          my $self = shift;          my $self = shift;
268          croak "attr_names return array, not scalar" if (! wantarray);          return unless ($self->{attrs});
269            #croak "attr_names return array, not scalar" if (! wantarray);
270          return sort keys %{ $self->{attrs} };          return sort keys %{ $self->{attrs} };
271  }  }
272    
# Line 221  Returns value of an attribute. Line 282  Returns value of an attribute.
282  sub attr {  sub attr {
283          my $self = shift;          my $self = shift;
284          my $name = shift;          my $name = shift;
285            return unless (defined($name) && $self->{attrs});
286          return $self->{'attrs'}->{ $name };          return $self->{attrs}->{ $name };
287  }  }
288    
289    
# Line 236  Returns array with text sentences. Line 297  Returns array with text sentences.
297    
298  sub texts {  sub texts {
299          my $self = shift;          my $self = shift;
300          confess "texts return array, not scalar" if (! wantarray);          #confess "texts return array, not scalar" if (! wantarray);
301          return @{ $self->{dtexts} };          return @{ $self->{dtexts} } if ($self->{dtexts});
302  }  }
303    
304    
# Line 251  Return whole text as single scalar. Line 312  Return whole text as single scalar.
312    
313  sub cat_texts {  sub cat_texts {
314          my $self = shift;          my $self = shift;
315          return join(' ',@{ $self->{dtexts} });          return join(' ',@{ $self->{dtexts} }) if ($self->{dtexts});
316  }  }
317    
318    
# Line 268  sub dump_draft { Line 329  sub dump_draft {
329          my $draft;          my $draft;
330    
331          foreach my $attr_name (sort keys %{ $self->{attrs} }) {          foreach my $attr_name (sort keys %{ $self->{attrs} }) {
332                  $draft .= $attr_name . '=' . $self->{attrs}->{$attr_name} . "\n";                  next unless defined(my $v = $self->{attrs}->{$attr_name});
333                    $draft .= $attr_name . '=' . $v . "\n";
334          }          }
335    
336          if ($self->{kwords}) {          if ($self->{kwords}) {
# Line 316  sub delete { Line 378  sub delete {
378    
379  package Search::Estraier::Condition;  package Search::Estraier::Condition;
380    
381  use Carp qw/confess croak/;  use Carp qw/carp confess croak/;
382    
383  use Search::Estraier;  use Search::Estraier;
384  our @ISA = qw/Search::Estraier/;  our @ISA = qw/Search::Estraier/;
# Line 394  sub set_max { Line 456  sub set_max {
456    
457  =head2 set_options  =head2 set_options
458    
459    $cond->set_options( SURE => 1 );    $cond->set_options( 'SURE' );
460    
461      $cond->set_options( qw/AGITO NOIDF SIMPLE/ );
462    
463    Possible options are:
464    
465    =over 8
466    
467    =item SURE
468    
469    check every N-gram
470    
471    =item USUAL
472    
473    check every second N-gram
474    
475    =item FAST
476    
477    check every third N-gram
478    
479    =item AGITO
480    
481    check every fourth N-gram
482    
483    =item NOIDF
484    
485    don't perform TF-IDF tuning
486    
487    =item SIMPLE
488    
489    use simplified query phrase
490    
491    =back
492    
493    Skipping N-grams will speed up search, but reduce accuracy. Every call to C<set_options> will reset previous
494    options;
495    
496    This option changed in version C<0.04> of this module. It's backwards compatibile.
497    
498  =cut  =cut
499    
500  my $options = {  my $options = {
         # check N-gram keys skipping by three  
501          SURE => 1 << 0,          SURE => 1 << 0,
         # check N-gram keys skipping by two  
502          USUAL => 1 << 1,          USUAL => 1 << 1,
         # without TF-IDF tuning  
503          FAST => 1 << 2,          FAST => 1 << 2,
         # with the simplified phrase  
504          AGITO => 1 << 3,          AGITO => 1 << 3,
         # check every N-gram key  
505          NOIDF => 1 << 4,          NOIDF => 1 << 4,
         # check N-gram keys skipping by one  
506          SIMPLE => 1 << 10,          SIMPLE => 1 << 10,
507  };  };
508    
509  sub set_options {  sub set_options {
510          my $self = shift;          my $self = shift;
511          my $option = shift;          my $opt = 0;
512          confess "unknown option" unless ($options->{$option});          foreach my $option (@_) {
513          $self->{options} ||= $options->{$option};                  my $mask;
514                    unless ($mask = $options->{$option}) {
515                            if ($option eq '1') {
516                                    next;
517                            } else {
518                                    croak "unknown option $option";
519                            }
520                    }
521                    $opt += $mask;
522            }
523            $self->{options} = $opt;
524  }  }
525    
526    
# Line 460  Return search result attrs. Line 563  Return search result attrs.
563  sub attrs {  sub attrs {
564          my $self = shift;          my $self = shift;
565          #croak "attrs return array, not scalar" if (! wantarray);          #croak "attrs return array, not scalar" if (! wantarray);
566          return @{ $self->{attrs} };          return @{ $self->{attrs} } if ($self->{attrs});
567  }  }
568    
569    
# Line 496  sub options { Line 599  sub options {
599  }  }
600    
601    
602    =head2 set_skip
603    
604    Set number of skipped documents from beginning of results
605    
606      $cond->set_skip(42);
607    
608    Similar to C<offset> in RDBMS.
609    
610    =cut
611    
612    sub set_skip {
613            my $self = shift;
614            $self->{skip} = shift;
615    }
616    
617    =head2 skip
618    
619    Return skip for this condition.
620    
621      print $cond->skip;
622    
623    =cut
624    
625    sub skip {
626            my $self = shift;
627            return $self->{skip};
628    }
629    
630    
631  package Search::Estraier::ResultDocument;  package Search::Estraier::ResultDocument;
632    
633  use Carp qw/croak/;  use Carp qw/croak/;
# Line 524  sub new { Line 656  sub new {
656          my $self = {@_};          my $self = {@_};
657          bless($self, $class);          bless($self, $class);
658    
659          foreach my $f (qw/uri attrs snippet keywords/) {          croak "missing uri for ResultDocument" unless defined($self->{uri});
                 croak "missing $f for ResultDocument" unless defined($self->{$f});  
         }  
660    
661          $self ? return $self : return undef;          $self ? return $self : return undef;
662  }  }
# Line 641  Return number of documents Line 771  Return number of documents
771    
772    print $res->doc_num;    print $res->doc_num;
773    
774    This will return real number of documents (limited by C<max>).
775    If you want to get total number of hits, see C<hits>.
776    
777  =cut  =cut
778    
779  sub doc_num {  sub doc_num {
# Line 672  sub get_doc { Line 805  sub get_doc {
805    
806  Return specific hint from results.  Return specific hint from results.
807    
808    print $rec->hint( 'VERSION' );    print $res->hint( 'VERSION' );
809    
810  Possible hints are: C<VERSION>, C<NODE>, C<HIT>, C<HINT#n>, C<DOCNUM>, C<WORDNUM>,  Possible hints are: C<VERSION>, C<NODE>, C<HIT>, C<HINT#n>, C<DOCNUM>, C<WORDNUM>,
811  C<TIME>, C<LINK#n>, C<VIEW>.  C<TIME>, C<LINK#n>, C<VIEW>.
# Line 685  sub hint { Line 818  sub hint {
818          return $self->{hints}->{$key};          return $self->{hints}->{$key};
819  }  }
820    
821    =head2 hints
822    
823    More perlish version of C<hint>. This one returns hash.
824    
825      my %hints = $res->hints;
826    
827    =cut
828    
829    sub hints {
830            my $self = shift;
831            return $self->{hints};
832    }
833    
834    =head2 hits
835    
836    Syntaxtic sugar for total number of hits for this query
837    
838      print $res->hits;
839    
840    It's same as
841    
842      print $res->hint('HIT');
843    
844    but shorter.
845    
846    =cut
847    
848    sub hits {
849            my $self = shift;
850            return $self->{hints}->{'HIT'} || 0;
851    }
852    
853  package Search::Estraier::Node;  package Search::Estraier::Node;
854    
# Line 700  use URI::Escape qw/uri_escape/; Line 864  use URI::Escape qw/uri_escape/;
864    
865    my $node = new Search::HyperEstraier::Node;    my $node = new Search::HyperEstraier::Node;
866    
867    or optionally with C<url> as parametar
868    
869      my $node = new Search::HyperEstraier::Node( 'http://localhost:1978/node/test' );
870    
871    or in more verbose form
872    
873      my $node = new Search::HyperEstraier::Node(
874            url => 'http://localhost:1978/node/test',
875            debug => 1,
876            croak_on_error => 1
877      );
878    
879    with following arguments:
880    
881    =over 4
882    
883    =item url
884    
885    URL to node
886    
887    =item debug
888    
889    dumps a B<lot> of debugging output
890    
891    =item croak_on_error
892    
893    very helpful during development. It will croak on all errors instead of
894    silently returning C<-1> (which is convention of Hyper Estraier API in other
895    languages).
896    
897    =back
898    
899  =cut  =cut
900    
901  sub new {  sub new {
# Line 707  sub new { Line 903  sub new {
903          my $self = {          my $self = {
904                  pxport => -1,                  pxport => -1,
905                  timeout => 0,   # this used to be -1                  timeout => 0,   # this used to be -1
                 dnum => -1,  
                 wnum => -1,  
                 size => -1.0,  
906                  wwidth => 480,                  wwidth => 480,
907                  hwidth => 96,                  hwidth => 96,
908                  awidth => 96,                  awidth => 96,
909                  status => -1,                  status => -1,
910          };          };
911    
912          bless($self, $class);          bless($self, $class);
913    
914          if (@_) {          if ($#_ == 0) {
915                  $self->{debug} = shift;                  $self->{url} = shift;
916                  warn "## Node debug on\n";          } else {
917                    my $args = {@_};
918    
919                    %$self = ( %$self, @_ );
920    
921                    warn "## Node debug on\n" if ($self->{debug});
922          }          }
923    
924            $self->{inform} = {
925                    dnum => -1,
926                    wnum => -1,
927                    size => -1.0,
928            };
929    
930          $self ? return $self : return undef;          $self ? return $self : return undef;
931  }  }
932    
# Line 1000  Get ID of document specified by URI Line 1205  Get ID of document specified by URI
1205    
1206    my $id = $node->uri_to_id( 'file:///document/uri/42' );    my $id = $node->uri_to_id( 'file:///document/uri/42' );
1207    
1208    This method won't croak, even if using C<croak_on_error>.
1209    
1210  =cut  =cut
1211    
1212  sub uri_to_id {  sub uri_to_id {
1213          my $self = shift;          my $self = shift;
1214          my $uri = shift || return;          my $uri = shift || return;
1215          return $self->_fetch_doc( uri => $uri, path => '/uri_to_id', chomp_resbody => 1 );          return $self->_fetch_doc( uri => $uri, path => '/uri_to_id', chomp_resbody => 1, croak_on_error => 0 );
1216  }  }
1217    
1218    
# Line 1065  sub _fetch_doc { Line 1272  sub _fetch_doc {
1272                  'application/x-www-form-urlencoded',                  'application/x-www-form-urlencoded',
1273                  $arg,                  $arg,
1274                  \$resbody,                  \$resbody,
1275                    $a->{croak_on_error},
1276          );          );
1277    
1278          return if ($rv != 200);          return if ($rv != 200);
# Line 1095  sub _fetch_doc { Line 1303  sub _fetch_doc {
1303    
1304  sub name {  sub name {
1305          my $self = shift;          my $self = shift;
1306          $self->set_info unless ($self->{name});          $self->_set_info unless ($self->{inform}->{name});
1307          return $self->{name};          return $self->{inform}->{name};
1308  }  }
1309    
1310    
# Line 1108  sub name { Line 1316  sub name {
1316    
1317  sub label {  sub label {
1318          my $self = shift;          my $self = shift;
1319          $self->set_info unless ($self->{label});          $self->_set_info unless ($self->{inform}->{label});
1320          return $self->{label};          return $self->{inform}->{label};
1321  }  }
1322    
1323    
# Line 1121  sub label { Line 1329  sub label {
1329    
1330  sub doc_num {  sub doc_num {
1331          my $self = shift;          my $self = shift;
1332          $self->set_info if ($self->{dnum} < 0);          $self->_set_info if ($self->{inform}->{dnum} < 0);
1333          return $self->{dnum};          return $self->{inform}->{dnum};
1334  }  }
1335    
1336    
# Line 1134  sub doc_num { Line 1342  sub doc_num {
1342    
1343  sub word_num {  sub word_num {
1344          my $self = shift;          my $self = shift;
1345          $self->set_info if ($self->{wnum} < 0);          $self->_set_info if ($self->{inform}->{wnum} < 0);
1346          return $self->{wnum};          return $self->{inform}->{wnum};
1347  }  }
1348    
1349    
# Line 1147  sub word_num { Line 1355  sub word_num {
1355    
1356  sub size {  sub size {
1357          my $self = shift;          my $self = shift;
1358          $self->set_info if ($self->{size} < 0);          $self->_set_info if ($self->{inform}->{size} < 0);
1359          return $self->{size};          return $self->{inform}->{size};
1360  }  }
1361    
1362    
# Line 1176  sub search { Line 1384  sub search {
1384    
1385          my $rv = $self->shuttle_url( $self->{url} . '/search',          my $rv = $self->shuttle_url( $self->{url} . '/search',
1386                  'application/x-www-form-urlencoded',                  'application/x-www-form-urlencoded',
1387                  $self->cond_to_query( $cond ),                  $self->cond_to_query( $cond, $depth ),
1388                  \$resbody,                  \$resbody,
1389          );          );
1390          return if ($rv != 200);          return if ($rv != 200);
# Line 1268  sub search { Line 1476  sub search {
1476    
1477  =head2 cond_to_query  =head2 cond_to_query
1478    
1479    my $args = $node->cond_to_query( $cond );  Return URI encoded string generated from Search::Estraier::Condition
1480    
1481      my $args = $node->cond_to_query( $cond, $depth );
1482    
1483  =cut  =cut
1484    
# Line 1277  sub cond_to_query { Line 1487  sub cond_to_query {
1487    
1488          my $cond = shift || return;          my $cond = shift || return;
1489          croak "condition must be Search::Estraier::Condition, not '$cond->isa'" unless ($cond->isa('Search::Estraier::Condition'));          croak "condition must be Search::Estraier::Condition, not '$cond->isa'" unless ($cond->isa('Search::Estraier::Condition'));
1490            my $depth = shift;
1491    
1492          my @args;          my @args;
1493    
# Line 1286  sub cond_to_query { Line 1497  sub cond_to_query {
1497    
1498          if (my @attrs = $cond->attrs) {          if (my @attrs = $cond->attrs) {
1499                  for my $i ( 0 .. $#attrs ) {                  for my $i ( 0 .. $#attrs ) {
1500                          push @args,'attr' . ($i+1) . '=' . uri_escape( $attrs[$i] );                          push @args,'attr' . ($i+1) . '=' . uri_escape( $attrs[$i] ) if ($attrs[$i]);
1501                  }                  }
1502          }          }
1503    
# Line 1304  sub cond_to_query { Line 1515  sub cond_to_query {
1515                  push @args, 'options=' . $options;                  push @args, 'options=' . $options;
1516          }          }
1517    
1518          push @args, 'depth=' . $self->{depth} if ($self->{depth});          push @args, 'depth=' . $depth if ($depth);
1519          push @args, 'wwidth=' . $self->{wwidth};          push @args, 'wwidth=' . $self->{wwidth};
1520          push @args, 'hwidth=' . $self->{hwidth};          push @args, 'hwidth=' . $self->{hwidth};
1521          push @args, 'awidth=' . $self->{awidth};          push @args, 'awidth=' . $self->{awidth};
1522            push @args, 'skip=' . $self->{skip} if ($self->{skip});
1523    
1524          return join('&', @args);          return join('&', @args);
1525  }  }
# Line 1315  sub cond_to_query { Line 1527  sub cond_to_query {
1527    
1528  =head2 shuttle_url  =head2 shuttle_url
1529    
1530  This is method which uses C<IO::Socket::INET> to communicate with Hyper Estraier node  This is method which uses C<LWP::UserAgent> to communicate with Hyper Estraier node
1531  master.  master.
1532    
1533    my $rv = shuttle_url( $url, $content_type, $req_body, \$resbody );    my $rv = shuttle_url( $url, $content_type, $req_body, \$resbody );
# Line 1325  body will be saved within object. Line 1537  body will be saved within object.
1537    
1538  =cut  =cut
1539    
1540    use LWP::UserAgent;
1541    
1542  sub shuttle_url {  sub shuttle_url {
1543          my $self = shift;          my $self = shift;
1544    
1545          my ($url, $content_type, $reqbody, $resbody) = @_;          my ($url, $content_type, $reqbody, $resbody, $croak_on_error) = @_;
1546    
1547            $croak_on_error = $self->{croak_on_error} unless defined($croak_on_error);
1548    
1549          $self->{status} = -1;          $self->{status} = -1;
1550    
# Line 1343  sub shuttle_url { Line 1559  sub shuttle_url {
1559                  return -1;                  return -1;
1560          }          }
1561    
1562          my ($host,$port,$query) = ($url->host, $url->port, $url->path);          my $ua = LWP::UserAgent->new;
1563            $ua->agent( "Search-Estraier/$Search::Estraier::VERSION" );
1564    
1565          if ($self->{pxhost}) {          my $req;
1566                  ($host,$port) = ($self->{pxhost}, $self->{pxport});          if ($reqbody) {
1567                  $query = "http://$host:$port/$query";                  $req = HTTP::Request->new(POST => $url);
1568            } else {
1569                    $req = HTTP::Request->new(GET => $url);
1570          }          }
1571    
1572          $query .= '?' . $url->query if ($url->query && ! $reqbody);          $req->headers->header( 'Host' => $url->host . ":" . $url->port );
1573            $req->headers->header( 'Connection', 'close' );
1574            $req->headers->header( 'Authorization', 'Basic ' . $self->{auth} ) if ($self->{auth});
1575            $req->content_type( $content_type );
1576    
1577          my $headers;          warn $req->headers->as_string,"\n" if ($self->{debug});
1578    
1579          if ($reqbody) {          if ($reqbody) {
1580                  $headers .= "POST $query HTTP/1.0\r\n";                  warn "$reqbody\n" if ($self->{debug});
1581          } else {                  $req->content( $reqbody );
                 $headers .= "GET $query HTTP/1.0\r\n";  
1582          }          }
1583    
1584          $headers .= "Host: " . $url->host . ":" . $url->port . "\r\n";          my $res = $ua->request($req) || croak "can't make request to $url: $!";
         $headers .= "Connection: close\r\n";  
         $headers .= "User-Agent: Search-Estraier/$Search::Estraier::VERSION\r\n";  
         $headers .= "Content-Type: $content_type\r\n";  
         $headers .= "Authorization: Basic $self->{auth}\r\n";  
         my $len = 0;  
         {  
                 use bytes;  
                 $len = length($reqbody) if ($reqbody);  
         }  
         $headers .= "Content-Length: $len\r\n";  
         $headers .= "\r\n";  
   
         my $sock = IO::Socket::INET->new(  
                 PeerAddr        => $host,  
                 PeerPort        => $port,  
                 Proto           => 'tcp',  
                 Timeout         => $self->{timeout} || 90,  
         );  
1585    
1586          if (! $sock) {          warn "## response status: ",$res->status_line,"\n" if ($self->{debug});
1587                  carp "can't open socket to $host:$port";  
1588                  return -1;          ($self->{status}, $self->{status_message}) = split(/\s+/, $res->status_line, 2);
1589    
1590            if (! $res->is_success) {
1591                    if ($croak_on_error) {
1592                            croak("can't get $url: ",$res->status_line);
1593                    } else {
1594                            return -1;
1595                    }
1596          }          }
1597    
1598          warn $headers if ($self->{debug});          $$resbody .= $res->content;
1599    
1600          print $sock $headers or          warn "## response body:\n$$resbody\n" if ($resbody && $self->{debug});
                 carp "can't send headers to network:\n$headers\n" and return -1;  
1601    
1602          if ($reqbody) {          return $self->{status};
1603                  warn "$reqbody\n" if ($self->{debug});  }
1604                  print $sock $reqbody or  
1605                          carp "can't send request body to network:\n$$reqbody\n" and return -1;  
1606    =head2 set_snippet_width
1607    
1608    Set width of snippets in results
1609    
1610      $node->set_snippet_width( $wwidth, $hwidth, $awidth );
1611    
1612    C<$wwidth> specifies whole width of snippet. It's C<480> by default. If it's C<0> snippet
1613    is not sent with results. If it is negative, whole document text is sent instead of snippet.
1614    
1615    C<$hwidth> specified width of strings from beginning of string. Default
1616    value is C<96>. Negative or zero value keep previous value.
1617    
1618    C<$awidth> specifies width of strings around each highlighted word. It's C<96> by default.
1619    If negative of zero value is provided previous value is kept unchanged.
1620    
1621    =cut
1622    
1623    sub set_snippet_width {
1624            my $self = shift;
1625    
1626            my ($wwidth, $hwidth, $awidth) = @_;
1627            $self->{wwidth} = $wwidth;
1628            $self->{hwidth} = $hwidth if ($hwidth >= 0);
1629            $self->{awidth} = $awidth if ($awidth >= 0);
1630    }
1631    
1632    
1633    =head2 set_user
1634    
1635    Manage users of node
1636    
1637      $node->set_user( 'name', $mode );
1638    
1639    C<$mode> can be one of:
1640    
1641    =over 4
1642    
1643    =item 0
1644    
1645    delete account
1646    
1647    =item 1
1648    
1649    set administrative right for user
1650    
1651    =item 2
1652    
1653    set user account as guest
1654    
1655    =back
1656    
1657    Return true on success, otherwise false.
1658    
1659    =cut
1660    
1661    sub set_user {
1662            my $self = shift;
1663            my ($name, $mode) = @_;
1664    
1665            return unless ($self->{url});
1666            croak "mode must be number, not '$mode'" unless ($mode =~ m/^\d+$/);
1667    
1668            $self->shuttle_url( $self->{url} . '/_set_user',
1669                    'text/plain',
1670                    'name=' . uri_escape($name) . '&mode=' . $mode,
1671                    undef
1672            ) == 200;
1673    }
1674    
1675    
1676    =head2 set_link
1677    
1678    Manage node links
1679    
1680      $node->set_link('http://localhost:1978/node/another', 'another node label', $credit);
1681    
1682    If C<$credit> is negative, link is removed.
1683    
1684    =cut
1685    
1686    sub set_link {
1687            my $self = shift;
1688            my ($url, $label, $credit) = @_;
1689    
1690            return unless ($self->{url});
1691            croak "mode credit be number, not '$credit'" unless ($credit =~ m/^\d+$/);
1692    
1693            my $reqbody = 'url=' . uri_escape($url) . '&label=' . uri_escape($label);
1694            $reqbody .= '&credit=' . $credit if ($credit > 0);
1695    
1696            if ($self->shuttle_url( $self->{url} . '/_set_link',
1697                    'application/x-www-form-urlencoded',
1698                    $reqbody,
1699                    undef
1700            ) == 200) {
1701                    # refresh node info after adding link
1702                    $self->_set_info;
1703                    return 1;
1704          }          }
1705    }
1706    
1707          my $line = <$sock>;  =head2 admins
         chomp($line);  
         my ($schema, $res_status, undef) = split(/  */, $line, 3);  
         return if ($schema !~ /^HTTP/ || ! $res_status);  
   
         $self->{status} = $res_status;  
         warn "## response status: $res_status\n" if ($self->{debug});  
   
         # skip rest of headers  
         $line = <$sock>;  
         while ($line) {  
                 $line = <$sock>;  
                 $line =~ s/[\r\n]+$//;  
                 warn "## ", $line || 'NULL', " ##\n" if ($self->{debug});  
         };  
1708    
1709          # read body   my @admins = @{ $node->admins };
         $len = 0;  
         do {  
                 $len = read($sock, my $buf, 8192);  
                 $$resbody .= $buf if ($resbody);  
         } while ($len);  
1710    
1711          warn "## response body:\n$$resbody\n" if ($resbody && $self->{debug});  Return array of users with admin rights on node
1712    
1713          return $self->{status};  =cut
1714    
1715    sub admins {
1716            my $self = shift;
1717            $self->_set_info unless ($self->{inform}->{name});
1718            return $self->{inform}->{admins};
1719    }
1720    
1721    =head2 guests
1722    
1723     my @guests = @{ $node->guests };
1724    
1725    Return array of users with guest rights on node
1726    
1727    =cut
1728    
1729    sub guests {
1730            my $self = shift;
1731            $self->_set_info unless ($self->{inform}->{name});
1732            return $self->{inform}->{guests};
1733  }  }
1734    
1735    =head2 links
1736    
1737     my $links = @{ $node->links };
1738    
1739    Return array of links for this node
1740    
1741    =cut
1742    
1743    sub links {
1744            my $self = shift;
1745            $self->_set_info unless ($self->{inform}->{name});
1746            return $self->{inform}->{links};
1747    }
1748    
1749  =head2 set_info  
1750    =head1 PRIVATE METHODS
1751    
1752    You could call those directly, but you don't have to. I hope.
1753    
1754    =head2 _set_info
1755    
1756  Set information for node  Set information for node
1757    
1758    $node->set_info;    $node->_set_info;
1759    
1760  =cut  =cut
1761    
1762  sub set_info {  sub _set_info {
1763          my $self = shift;          my $self = shift;
1764    
1765          $self->{status} = -1;          $self->{status} = -1;
# Line 1448  sub set_info { Line 1774  sub set_info {
1774    
1775          return if ($rv != 200 || !$resbody);          return if ($rv != 200 || !$resbody);
1776    
1777          chomp($resbody);          my @lines = split(/[\r\n]/,$resbody);
1778    
1779            $self->{inform} = {};
1780    
1781            ( $self->{inform}->{name}, $self->{inform}->{label}, $self->{inform}->{dnum},
1782                    $self->{inform}->{wnum}, $self->{inform}->{size} ) = split(/\t/, shift @lines, 5);
1783    
1784            return $resbody unless (@lines);
1785    
1786            shift @lines;
1787    
1788            while(my $admin = shift @lines) {
1789                    push @{$self->{inform}->{admins}}, $admin;
1790            }
1791    
1792            while(my $guest = shift @lines) {
1793                    push @{$self->{inform}->{guests}}, $guest;
1794            }
1795    
1796            while(my $link = shift @lines) {
1797                    push @{$self->{inform}->{links}}, $link;
1798            }
1799    
1800          ( $self->{name}, $self->{label}, $self->{dnum}, $self->{wnum}, $self->{size} ) =          return $resbody;
                 split(/\t/, $resbody, 5);  
1801    
1802  }  }
1803    

Legend:
Removed from v.53  
changed lines
  Added in v.122

  ViewVC Help
Powered by ViewVC 1.1.26