--- trunk/Estraier.pm 2006/05/08 21:33:37 132 +++ trunk/Estraier.pm 2006/08/06 12:19:19 164 @@ -4,7 +4,7 @@ use strict; use warnings; -our $VERSION = '0.06_1'; +our $VERSION = '0.07_2'; =head1 NAME @@ -20,7 +20,10 @@ my $node = new Search::Estraier::Node( url => 'http://localhost:1978/node/test', user => 'admin', - passwd => 'admin' + passwd => 'admin', + create => 1, + label => 'Label for node', + croak_on_error => 1, ); # create document @@ -117,9 +120,34 @@ =head1 Search::Estraier::Document -This class implements Document which is collection of attributes -(key=value), vectors (also key value) display text and hidden text. +This class implements Document which is single item in Hyper Estraier. + +It's is collection of: + +=over 4 + +=item attributes + +C<< 'key' => 'value' >> pairs which can later be used for filtering of results + +You can add common filters to C in estmaster's C<_conf> +file for better performance. See C in +L. +=item vectors + +also C<< 'key' => 'value' >> pairs + +=item display text + +Text which will be used to create searchable corpus of your index and +included in snippet output. + +=item hidden text + +Text which will be searchable, but will not be included in snippet. + +=back =head2 new @@ -874,6 +902,8 @@ url => 'http://localhost:1978/node/test', user => 'admin', passwd => 'admin' + create => 1, + label => 'optional node label', debug => 1, croak_on_error => 1 ); @@ -894,6 +924,14 @@ password for authentication +=item create + +create node if it doesn't exists + +=item label + +optional label for new node if C is used + =item debug dumps a B of debugging output @@ -937,6 +975,19 @@ size => -1.0, }; + if ($self->{create}) { + if (! eval { $self->name } || $@) { + my $name = $1 if ($self->{url} =~ m#/node/([^/]+)/*#); + croak "can't find node name in '$self->{url}'" unless ($name); + my $label = $self->{label} || $name; + $self->master( + action => 'nodeadd', + name => $name, + label => $label, + ) || croak "can't create node $name ($label)"; + } + } + $self ? return $self : return undef; } @@ -1027,7 +1078,7 @@ $node->put_doc( $document_draft ) or die "can't add document"; -Return true on success or false on failture. +Return true on success or false on failure. =cut @@ -1035,11 +1086,15 @@ my $self = shift; my $doc = shift || return; return unless ($self->{url} && $doc->isa('Search::Estraier::Document')); - $self->shuttle_url( $self->{url} . '/put_doc', + if ($self->shuttle_url( $self->{url} . '/put_doc', 'text/x-estraier-draft', $doc->dump_draft, undef - ) == 200; + ) == 200) { + $self->_clear_info; + return 1; + } + return undef; } @@ -1058,11 +1113,15 @@ my $id = shift || return; return unless ($self->{url}); croak "id must be number, not '$id'" unless ($id =~ m/^\d+$/); - $self->shuttle_url( $self->{url} . '/out_doc', + if ($self->shuttle_url( $self->{url} . '/out_doc', 'application/x-www-form-urlencoded', "id=$id", undef - ) == 200; + ) == 200) { + $self->_clear_info; + return 1; + } + return undef; } @@ -1080,11 +1139,15 @@ my $self = shift; my $uri = shift || return; return unless ($self->{url}); - $self->shuttle_url( $self->{url} . '/out_doc', + if ($self->shuttle_url( $self->{url} . '/out_doc', 'application/x-www-form-urlencoded', "uri=" . uri_escape($uri), undef - ) == 200; + ) == 200) { + $self->_clear_info; + return 1; + } + return undef; } @@ -1102,11 +1165,15 @@ my $self = shift; my $doc = shift || return; return unless ($self->{url} && $doc->isa('Search::Estraier::Document')); - $self->shuttle_url( $self->{url} . '/edit_doc', + if ($self->shuttle_url( $self->{url} . '/edit_doc', 'text/x-estraier-draft', $doc->dump_draft, undef - ) == 200; + ) == 200) { + $self->_clear_info; + return 1; + } + return undef; } @@ -1473,7 +1540,7 @@ push @args, 'wwidth=' . $self->{wwidth}; push @args, 'hwidth=' . $self->{hwidth}; push @args, 'awidth=' . $self->{awidth}; - push @args, 'skip=' . $self->{skip} if ($self->{skip}); + push @args, 'skip=' . $cond->{skip} if ($cond->{skip}); return join('&', @args); } @@ -1620,7 +1687,7 @@ croak "mode must be number, not '$mode'" unless ($mode =~ m/^\d+$/); $self->shuttle_url( $self->{url} . '/_set_user', - 'text/plain', + 'application/x-www-form-urlencoded', 'name=' . uri_escape($name) . '&mode=' . $mode, undef ) == 200; @@ -1653,9 +1720,10 @@ undef ) == 200) { # refresh node info after adding link - $self->_set_info; + $self->_clear_info; return 1; } + return undef; } =head2 admins @@ -1700,6 +1768,164 @@ return $self->{inform}->{links}; } +=head2 cacheusage + +Return cache usage for a node + + my $cache = $node->cacheusage; + +=cut + +sub cacheusage { + my $self = shift; + + return unless ($self->{url}); + + my $resbody; + my $rv = $self->shuttle_url( $self->{url} . '/cacheusage', + 'text/plain', + undef, + \$resbody, + ); + + return if ($rv != 200 || !$resbody); + + return $resbody; +} + +=head2 master + +Set actions on Hyper Estraier node master (C process) + + $node->master( + action => 'sync' + ); + +All available actions are documented in +L + +=cut + +my $estmaster_rest = { + shutdown => { + status => 202, + }, + sync => { + status => 202, + }, + backup => { + status => 202, + }, + userlist => { + status => 200, + returns => [ qw/name passwd flags fname misc/ ], + }, + useradd => { + required => [ qw/name passwd flags/ ], + optional => [ qw/fname misc/ ], + status => 200, + }, + userdel => { + required => [ qw/name/ ], + status => 200, + }, + nodelist => { + status => 200, + returns => [ qw/name label doc_num word_num size/ ], + }, + nodeadd => { + required => [ qw/name/ ], + optional => [ qw/label/ ], + status => 200, + }, + nodedel => { + required => [ qw/name/ ], + status => 200, + }, + nodeclr => { + required => [ qw/name/ ], + status => 200, + }, + nodertt => { + status => 200, + }, +}; + +sub master { + my $self = shift; + + my $args = {@_}; + + # have action? + my $action = $args->{action} || croak "need action, available: ", + join(", ",keys %{ $estmaster_rest }); + + # check if action is valid + my $rest = $estmaster_rest->{$action}; + croak "action '$action' is not supported, available actions: ", + join(", ",keys %{ $estmaster_rest }) unless ($rest); + + croak "BUG: action '$action' needs return status" unless ($rest->{status}); + + my @args; + + if ($rest->{required} || $rest->{optional}) { + + map { + croak "need parametar '$_' for action '$action'" unless ($args->{$_}); + push @args, $_ . '=' . uri_escape( $args->{$_} ); + } ( @{ $rest->{required} } ); + + map { + push @args, $_ . '=' . uri_escape( $args->{$_} ) if ($args->{$_}); + } ( @{ $rest->{optional} } ); + + } + + my $uri = new URI( $self->{url} ); + + my $resbody; + + my $status = $self->shuttle_url( + 'http://' . $uri->host_port . '/master?action=' . $action , + 'application/x-www-form-urlencoded', + join('&', @args), + \$resbody, + 1, + ) or confess "shuttle_url failed"; + + if ($status == $rest->{status}) { + + # refresh node info after sync + $self->_clear_info if ($action eq 'sync' || $action =~ m/^node(?:add|del|clr)$/); + + if ($rest->{returns} && wantarray) { + + my @results; + my $fields = $#{$rest->{returns}}; + + foreach my $line ( split(/[\r\n]/,$resbody) ) { + my @e = split(/\t/, $line, $fields + 1); + my $row; + foreach my $i ( 0 .. $fields) { + $row->{ $rest->{returns}->[$i] } = $e[ $i ]; + } + push @results, $row; + } + + return @results; + + } elsif ($resbody) { + chomp $resbody; + return $resbody; + } else { + return 0E0; + } + } + + carp "expected status $rest->{status}, but got $status"; + return undef; +} =head1 PRIVATE METHODS @@ -1730,7 +1956,7 @@ my @lines = split(/[\r\n]/,$resbody); - $self->{inform} = {}; + $self->_clear_info; ( $self->{inform}->{name}, $self->{inform}->{label}, $self->{inform}->{dnum}, $self->{inform}->{wnum}, $self->{inform}->{size} ) = split(/\t/, shift @lines, 5); @@ -1755,6 +1981,25 @@ } +=head2 _clear_info + +Clear information for node + + $node->_clear_info; + +On next call to C, C