File Coverage

blib/lib/SWISH/API/Remote.pm
Criterion Covered Total %
statement 66 122 54.1
branch 16 46 34.7
condition 4 19 21.0
subroutine 14 20 70.0
pod 2 6 33.3
total 102 213 47.8


line stmt bran cond sub pod time code
1             package SWISH::API::Remote;
2 3     3   84823 use SWISH::API::Remote::Results;
  3         11  
  3         97  
3 3     3   2198 use SWISH::API::Remote::Result;
  3         9  
  3         107  
4 3     3   2176 use SWISH::API::Remote::Header;
  3         8  
  3         91  
5 3     3   2878 use SWISH::API::Remote::MetaName;
  3         9  
  3         83  
6 3     3   19 use SWISH::API::Remote::FunctionGenerator;
  3         6  
  3         57  
7              
8 3     3   15 use strict;
  3         5  
  3         98  
9 3     3   16 use warnings;
  3         6  
  3         81  
10 3     3   5854 use Data::Dumper;
  3         44193  
  3         282  
11              
12 3     3   28 use fields qw( uri index debug timeout );
  3         55  
  3         30  
13 3     3   238 use URI::Escape; # for uri_(un)escape
  3         4  
  3         223  
14 3     3   8075 use LWP::UserAgent;
  3         238318  
  3         164  
15              
16             our $VERSION = '0.10'; # this is the version strings
17              
18 3     3   39 use constant DEFAULT_PROPERTIES => "swishrank,swishdocpath,swishtitle,swishdocsize";
  3         7  
  3         4352  
19              
20             ############################################
21             # new( $proto, $uri, $index, $opts_hash)
22             # returns a newly created SWISH::API::Remote object, which
23             # is modelled on SWISH::API::Remote
24             sub new {
25 2     2 1 31 my ($proto, $uri, $index, $opts_hash) = @_;
26 2 50       13 $opts_hash = {} unless defined($opts_hash);
27 2   33     13 my $class = ref($proto) || $proto;
28 2         5 my $self = {};
29 2         6 bless ($self, $class);
30 2         9 my %opts = %$opts_hash; # make a copy, which we delete keys from
31 2         11 $self->{uri} = $uri;
32 2   50     9 $self->{index} = $index || "DEFAULT";
33 2   50     13 $self->{debug} = $opts{DEBUG} || 0;
34 2         5 delete ($opts{DEBUG});
35 2   50     17 $self->{timeout} = $opts{TIMEOUT} || 3;
36 2         5 delete ($opts{TIMEOUT});
37             # any keys left in %opts are not understood.
38 2 50       11 if (keys %opts) {
39 0         0 die "0: Don't understand options: " . join(", ", keys( %opts )) . "\n";
40             }
41 2         16 return $self;
42             }
43              
44             ############################################
45             # $remote->IndexNames()
46             # to match SWISH::API::IndexNames
47             # returns list of index names
48             # we already know the indexnames, so we just return them. Note they're not
49             # filenames, they're index names like "DEFAULT"
50             # PLEASE NOTE THAT ALTHOUGH THIS RETURNS A LIST, WE CURRENTLY ONLY SUPPORT ONE INDEX <=> ONE INDEXFILE
51             sub IndexNames {
52 0     0 0 0 my $self = shift;
53 0         0 return ($self->{index}); # list of one element, for now we don't allow searching on multiple
54             # indexes (SWISHED might map 'DEFAULT' to two indexes, but the client won't # know that.)
55             }
56              
57             ############################################
58             # $remote->MetaList( $index_name )
59             # to match SWISH::API::MetaList
60             # returns a list of hashes of (Name=>name, ID=>idnum; Type->type)
61             # requires round-trip to SWISHED as implemented
62             sub MetaList {
63 0     0 0 0 my ($self, $index_name) = @_;
64 0         0 my $uri = $self->{uri} . "?f=" . $self->{index} . "&M=1";
65 0         0 my $content = $self->_Fetch_Url( $uri );
66 0         0 my($results, $headers, $props, $metas) = $self->_ParseContent( $content );
67 0         0 return @$metas;
68             }
69             ############################################
70             # to match SWISH::API::PropertyList( $index_name )
71             # returns a list of hashes of (Name=>name; ID=>idnum; Type->type)
72             # requires round-trip to SWISHED as implemented
73             sub PropertyList {
74 0     0 0 0 my ($self, $index_name) = @_;
75 0         0 my $uri = $self->{uri} . "?f=" . $self->{index} . "&P=1";
76 0         0 my $content = $self->_Fetch_Url( $uri );
77 0         0 my($results, $headers, $props, $metas) = $self->_ParseContent( $content );
78 0         0 return @$props;
79             }
80              
81             ############################################
82             # THERE IS NO CORRESPONDING SWISH::API::HeaderList( $index_name )
83             # returns a list of hashes of (Name=>name; Value=>value)
84             # requires round-trip to SWISHED as implemented
85             sub HeaderList {
86 0     0 0 0 my ($self, $index_name) = @_;
87 0         0 my $uri = $self->{uri} . "?f=" . $self->{index} . "&h=1";
88 0         0 my $content = $self->_Fetch_Url( $uri );
89 0         0 my($results, $headers, $props, $metas) = $self->_ParseContent( $content );
90 0         0 return @$headers;
91             }
92              
93             ############################################
94             # $remote->Execute( $query )
95             # to match SWISH::API::Execute
96             # requires round-trip to SWISHED
97             # each qs 'name' is based on the swish-e exe's corresponding command line flag
98             sub Execute {
99 0     0 1 0 my $self = shift;
100 0   0     0 my $query = shift || "";
101 0   0     0 my $searchopts = shift || {};
102 0         0 my $uri = $self->{uri} . "?f=" . $self->{index};
103 0 0       0 if (defined($query)) { # like -w
104 0         0 $uri .= "&w=" . uri_escape($query);
105             }
106 0 0 0     0 if (exists($searchopts->{HEADERS}) && $searchopts->{HEADERS}) { # new HEADERS option
107 0         0 $uri .= "&h=1";
108             }
109 0 0 0     0 if (exists($searchopts->{PROPERTIES}) && $searchopts->{PROPERTIES}) {
110 0         0 $uri .= "&p=" . uri_escape($searchopts->{PROPERTIES});
111             } else {
112 0         0 $uri .= "&p=" . DEFAULT_PROPERTIES;
113             }
114 0 0       0 if (exists($searchopts->{BEGIN})) {
115 0         0 $uri .= "&b=" . uri_escape($searchopts->{BEGIN});
116             }
117 0 0       0 if (exists($searchopts->{MAX})) {
118 0         0 $uri .= "&m=" . uri_escape($searchopts->{MAX});
119             }
120 0         0 my $content = $self->_Fetch_Url( $uri ); # fetch the content from the SWISHED server
121 0         0 my($results, $headers, $props, $metas) = $self->_ParseContent( $content );
122             # if we parsed this line-by-line, we could start showing things faster
123 0         0 return $results; # we don't expect any props or metas back
124             }
125              
126             ############################################
127             # $self->_Fetch_Url( $uri )
128             # returns the $content; prints an e: line if there's an error.
129             # intended to be private.
130             sub _Fetch_Url {
131 0     0   0 my ($self, $uri) = @_;
132 0 0       0 print "Fetching $uri\n" if ($self->{debug});
133              
134 0         0 my $ua = LWP::UserAgent->new;
135 0         0 $ua->timeout( $self->{timeout} );
136 0 0       0 print "Setting timeout to $self->{timeout}\n" if $self->{debug};
137             #$ua->env_proxy;
138 0         0 my $response = $ua->get( $uri );
139 0         0 my $content = "";
140 0 0       0 if ($response->is_success) {
141 0         0 $content = $response->content;
142 0 0       0 print "Got: $content\n" if $self->{debug};
143             } else {
144 0         0 $content = "e: Couldn't connect: " . $response->status_line . "\n";
145 0 0       0 print "Error: Couldn't connect.\n" if $self->{debug};
146             }
147 0         0 return $content;
148             }
149              
150             ############################################################################################
151             # if we parsed this line-by-line, we could start showing things faster
152             # (though it wouldn't necessarily be faster overall)
153             # intended to be private. Parses the returned content into members
154             # returns ($results, $headers, $props, $metas)
155             sub _ParseContent {
156 1     1   3 my ($self, $content) = @_;
157             #warn "Got content $content\n\n";
158 1         2 my @results = ();
159 1         2 my @resultprops = ();
160 1         11 my $results = SWISH::API::Remote::Results->new();
161 1         3 my @indexheaders;
162             my @indexmetas;
163 0         0 my @indexprops;
164             #my @lines = split(/\n/, $content);
165             #for my $line (@lines) {
166 1         9 for my $line (split(/\n/, $content)) {
167             # this is kind of ugly. We should remove the L: part at the same time, but we do.
168 14 100       30 next unless $line;
169 13 100       93 if ($line =~ s/^k:\s*//) { # the 'key'
    100          
    50          
    100          
    50          
    50          
    50          
    50          
170 1         5 @resultprops = map { (split(/=/, $_))[1] } (split (/&/, $line));
  4         30  
171             #print Data::Dumper::Dumper(\@resultprops);
172             }
173             elsif ($line =~ s/^r:\s*//) {
174 10         28 my $result = SWISH::API::Remote::Result::New_From_Query_String( $line, \@resultprops );
175 10         28 $results->AddResult($result);
176             }
177             elsif ($line =~ s/^e:\s*//) {
178 0         0 $results->AddError($line);
179 0 0       0 print "Added error: $line\n" if $self->{debug};
180             }
181             elsif ($line =~ s/^d:\s*//) {
182 1         5 $results->AddDebug($line); # add the 'debug' line returned from the server
183 1 50       5 print "Added debug: $line\n" if $self->{debug};
184             }
185             elsif ($line =~ s/^h:\s*//) {
186             #print "PARSING: h: $line\n" if $self->{debug};
187 0         0 @indexheaders = SWISH::API::Remote::Header::Parse_Headers_From_Query_String( $line );
188             #print "GOT HEADERS: " . Dumper( \@indexheaders ) if ($self->{debug});
189             }
190             elsif ($line =~ s/^M:\s*//) {
191             #print "PARSING: M: $line\n";
192 0         0 @indexmetas = SWISH::API::Remote::MetaName::Parse_MetaNames_From_Query_String( $line );
193             #print "GOT METAS: " . Dumper( \@indexmetas ) if $self->{debug};
194             }
195             elsif ($line =~ s/^P:\s*//) {
196             #print "PARSING: p: $line\n" if $self->{debug};
197 0         0 @indexprops = SWISH::API::Remote::MetaName::Parse_MetaNames_From_Query_String( $line );
198             #print "GOT PROPS: " . Dumper( \@indexprops ) if $self->{debug};
199             }
200             elsif ($line =~ s/^m:\s*.*hits=(\d+)//) {
201             # TODO: in the future we'll probably parse more from this Meta line
202             # for example, As of swished 0.09, there is also a swished_version
203             # like "0.09" (or "0.09n" if dev version) passed back too
204 1         7 $results->Hits($1);
205             } else {
206             # don't know what to do with this line. TODO: error?
207 0         0 $results->AddError( "Don't know what to do with line: $line" );
208             }
209            
210             }
211 1         7 return ($results, \@indexheaders, \@indexprops, \@indexmetas);
212             }
213             ############################################
214             ## make uri and index accessors
215             SWISH::API::Remote::FunctionGenerator::makeaccessors(
216             __PACKAGE__, qw ( uri index )
217             );
218              
219              
220             1;
221             __END__