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

Last change on this file since 11415 was 11328, checked in by deelkar, 11 years ago

merge minor changes from stable to unstable, and merge added exception (r11327) from unstable to stable

File size: 9.4 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 request 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, $priority);
143            ($ValidFlag, $Version, $X, $Y, $Z, $Layers, $lastModified, $complexity, $priority) = 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    if ( -s $File == 0 )
267    {
268        unlink($File) if (! $UseExisting);
269        throw ServerError "Zero sized osm file", "TempError";
270    }
271    return -s $File;
272}
273
274
275#-------------------------------------------------------------------------------
276=pod
277
278=back
279
280=cut
281#-------------------------------------------------------------------------------
282
283package ServerError;
284use base 'Error::Simple';
285
2861;
287
288=pod
289
290=head2 Exceptions thrown
291
292Server objects will throw exceptions of class ServerError.
293
294C<< $err->text() >> returns a description of the error and C<< $err->value() >>
295returns an error class.  Possible values are:
296
297=over
298
299=item B<PermError> indicating a permanent error
300
301=item B<TempError> indicating a temporary error
302
303=item B<NoJobs> indicating that the server doesn't have any jobs for us
304
305=back
306
307=cut
Note: See TracBrowser for help on using the repository browser.