source: subversion/applications/rendering/tilesAtHome/lib/Server.pm @ 11132

Last change on this file since 11132 was 11110, checked in by matthiasj, 11 years ago

move all *.pm files into lib and add lib to the library search paths

File size: 9.2 KB
Line 
1# A 'Server' encapsulates all server communications.
2=pod
3
4=head1 Server class for all communications of the t@h render
5
6=head2 License and authors
7
8 # Copyright 2008, by Matthias Julius and others
9 # licensed under the GPL v2 or (at your option) any later version.
10
11=head2 Overview
12
13The I<Server> class encapsulates all server communications of the t@h client. It
14is used to fetch a request from and return to the server as well as downloading
15of data from the OSM API and uploading of rendered tilesets.
16
17=cut
18
19# See rest of the pd documentation is at the end of this file. Please keep
20# the description of public methods/attributes up to date.
21package Server;
22
23use warnings;
24use strict;
25use LWP::UserAgent;
26use Error qw(:try);
27use tahlib;
28use TahConf;
29use Request;
30
31#-------------------------------------------------------------------------------
32=pod
33
34=head2 Public methods
35
36=head3 Class methods
37
38=over
39
40=item C<< ->new() >>
41
42A I<Server> can be instantiated with ->new().
43
44e.g. my $server = new Server or my $server = Server->new()
45
46=cut
47#-------------------------------------------------------------------------------
48sub new 
49{
50    my $class = shift;
51    my $self = {
52        Config => TahConf->getConfig(),
53        ua => undef,
54    };
55    bless $self, $class;
56
57    my $ua = LWP::UserAgent->new(timeout => $self->{Config}->get("DownloadTimeout"), protocols_allowed => ['http']);
58    $ua->agent("tilesAtHome ($^O)");
59    $ua->env_proxy();
60    push @{ $ua->requests_redirectable }, 'POST';
61    $self->{ua} = $ua;
62
63    return $self;
64}
65
66
67#-------------------------------------------------------------------------------
68=pod
69
70=back
71
72=head3 Instance methods
73
74=over
75
76=item C<< ->getString($URL) >>
77
78Get a string from the server via HTTP.  Returns the string returned by the
79server using $URL as the URL.
80
81=cut
82#-------------------------------------------------------------------------------
83sub getString
84{
85    my $self = shift();
86    my $URL = shift();
87
88    my $res = $self->{ua}->post($URL, Content_Type => 'form-data',
89                                Content => [ user => $self->{Config}->get("UploadUsername"),
90                                             passwd => $self->{Config}->get("UploadPassword"),
91                                             version => $self->{Config}->get("ClientVersion"),
92                                             layerspossible => $self->{Config}->get("LayersCapability"),
93                                             max_complexity => $self->{Config}->get("MaxTilesetComplexity"),
94                                             client_uuid => ::GetClientId() ]);
95
96    (print "Request string from server: ", $res->content,"\n") if ($self->{Config}->get("Debug"));     
97
98    if(!$res->is_success())
99    {   # getting request string from server failed here
100        throw ServerError "Unable to get string from server", "TempError";
101    }
102
103    # got a server reply here
104    my $res_string = $res->content();
105    chomp($res_string);
106    return $res_string;  ## FIXME: check single line returned. grep?
107}
108
109
110#-------------------------------------------------------------------------------
111=pod
112
113=item C<< ->fetchRequest() >>
114
115Get a new render request from the server to be rendered.  Returns a Request
116object.
117
118=cut
119#-------------------------------------------------------------------------------
120sub fetchRequest
121{
122    my $self = shift;
123    my $Request;
124
125    my $Requeststring = $self->getString($self->{Config}->get("RequestURL"));
126
127    throw ServerError "Server returned no content", "TempError" unless $Requeststring;
128
129    # $ValidFlag is 'OK' (got request) or 'XX' (error occurred, or no work for us)
130    # $Version denotes the version of the request taking protocol the server speaks. It's currently at '5'
131    my ($ValidFlag, $Version) = split(/\|/, $Requeststring);
132
133    # First check that we understand the server protocol
134    if ($Version < 5 or $Version > 5) {
135        throw ServerError "Server is speaking a different version of the protocol to us ($Version).\n"
136            . "Check to see whether a new version of this program was released!", "ProtocolVersionError";
137    }
138
139    if ($ValidFlag eq "OK") {
140        # We got a valid request here!
141        if ($Version == 5) {# this may seem nonsensical, but we'll need this once we introduce a new version
142            my ($Z, $X, $Y, $Layers, $lastModified, $complexity);
143            ($ValidFlag, $Version, $X, $Y, $Z, $Layers, $lastModified, $complexity) = split(/\|/, $Requeststring);
144            $Request = Request->new($Z,$X,$Y);
145            $Request->layers_str($Layers);
146            $Request->lastModified($lastModified);
147            $Request->complexity($complexity);
148        }
149    }
150    elsif ($ValidFlag eq "XX") {
151        ($ValidFlag, $Version, my $reason) = split(/\|/, $Requeststring);
152        if ($reason =~ /Invalid username/) {
153            throw ServerError "ERROR: Authentication failed - please check your username and password in 'authentication.conf'.\n\n"
154                . "! If this worked just yesterday, you now need to put your osm account e-mail and password there.", "PermError";
155        }
156        elsif ($reason =~ /Invalid client version/) {
157            throw ServerError "ERROR: This client version (" . $self->{Config}->get("ClientVersion")
158                . ") was not accepted by the server.", "PermError";  ## this should never happen as long as auto-update works
159        }
160        elsif ($reason =~ /No requests in queue/) {
161            throw ServerError "No Requests on server", "NoJobs";
162        }
163        elsif ($reason =~ /Throttling/) {
164            throw ServerError $reason, "NoJobs";
165        }
166        elsif ($reason =~ /You have more than (\d+) active requests/) {
167            throw ServerError "Is your client broken or have you just uploaded like crazy? \"$reason\"", "NoJobs";
168        }
169        else {
170            throw ServerError "Unknown server response: $Requeststring", "TempError";
171        }
172    }
173    else {
174        # ValidFlag was neither 'OK' nor 'XX'. This should NEVER happen.
175        throw ServerError "Unknown server response ($Requeststring), ValidFlag neither 'OK' nor 'XX'", "TempError";
176    }
177    return $Request;
178}
179
180
181#-----------------------------------------------------------------------------
182=pod
183
184=item C<< ->putRequestBack($Request, $Cause) >>
185
186Puts a request back to the server, indicating the cause.
187This is called when the client encounters errors in processing a tileset,
188it tells the server the tileset will not be returned by the client.
189
190=over
191
192=item C<$Request> is a Request object
193
194=item C<$Cause> is a string describing the cause
195
196=back
197
198=cut
199#-----------------------------------------------------------------------------
200sub putRequestBack 
201{
202    my ($self, $Request, $Cause) = @_;
203
204    my $ua = $self->{ua};
205
206    ::statusMessage(sprintf("Putting job (%d,%d,%d) back due to '%s'", $Request->Z, $Request->X, $Request->Y, $Cause), 1, 0);
207    my $res = $ua->post($self->{Config}->get("ReRequestURL"),
208                        Content_Type => 'form-data',
209                        Content => [ x => $Request->X,
210                                     y => $Request->Y,
211                                     min_z => $Request->Z,
212                                     user => $self->{Config}->get("UploadUsername"),
213                                     passwd => $self->{Config}->get("UploadPassword"),
214                                     version => $self->{Config}->get("ClientVersion"),
215                                     cause => $Cause,
216                                     client_uuid => ::GetClientId() ]);
217
218    if(!$res->is_success()) {
219        throw ServerError "Error reading response from server", "TempError";
220    }
221}
222
223
224#------------------------------------------------------------------
225=pod
226
227=item C<< ->downloadFile($URL, $Filename, $UseExisting) >>
228
229Download an URL into a specified file.
230
231B<Parameter>:
232
233=over
234
235=item C<$URL> the URL to download
236
237=item C<$Filename> a string naming the file into which the data should be stored
238
239=item C<$UseExisting> if false or omitted the file will be deleted before download,
240if true the file will only be downloaded if the server has a newer version.
241
242=back
243
244=cut
245#-------------------------------------------------------------------
246sub downloadFile 
247{
248    my $self = shift();
249    my $Config = $self->{Config};
250    my ($URL, $File, $UseExisting) = @_;
251
252    my $ua = $self->{ua};
253
254    if(!$UseExisting) {
255        unlink($File);
256    }
257
258    # Note: mirror sets the time on the file to match the server time. This
259    # is important for the handling of JobTime later.
260    my $res = $ua->mirror($URL, $File);
261
262    if (!$res->is_success()) {
263        unlink($File) if (! $UseExisting);
264        throw ServerError $res->status_line, "TempError";
265    }
266    return -s $File;
267}
268
269
270#-------------------------------------------------------------------------------
271=pod
272
273=back
274
275=cut
276#-------------------------------------------------------------------------------
277
278package ServerError;
279use base 'Error::Simple';
280
2811;
282
283=pod
284
285=head2 Exceptions thrown
286
287Server objects will throw exceptions of class ServerError.
288
289C<< $err->text() >> returns a description of the error and C<< $err->value() >>
290returns an error class.  Possible values are:
291
292=over
293
294=item B<PermError> indicating a permanent error
295
296=item B<TempError> indicating a temporary error
297
298=item B<NoJobs> indicating that the server doesn't have any jobs for us
299
300=back
301
302=cut
Note: See TracBrowser for help on using the repository browser.