Commit | Line | Data |
532cc23b |
1 | package stemmaweb::Controller::Stemweb; |
2 | use Moose; |
3 | use namespace::autoclean; |
4 | use JSON qw/ from_json /; |
5 | use Safe::Isa; |
6 | use TryCatch; |
7 | |
8 | BEGIN { extends 'Catalyst::Controller' } |
9 | |
10 | =head1 NAME |
11 | |
12 | stemmaweb::Controller::Stemweb - Client listener for Stemweb results |
13 | |
14 | =head1 DESCRIPTION |
15 | |
16 | This is a client listener for the Stemweb API as implemented by the protocol defined at |
17 | L<https://docs.google.com/document/d/1aNYGAo1v1WPDZi6LXZ30FJSMJwF8RQPYbOkKqHdCZEc/pub>. |
18 | |
19 | =head1 METHODS |
20 | |
21 | =head2 result |
22 | |
23 | POST stemweb/result |
24 | Content-Type: application/json |
25 | (On success): |
26 | { job_id: <ID number> |
27 | status: 0 |
28 | format: <format> |
29 | result: <data> } |
30 | (On failure): |
31 | { jobid: <ID number> |
32 | status: >1 |
33 | result: <error message> } |
34 | |
35 | Used by the Stemweb server to notify us that one or more stemma graphs |
36 | has been calculated in response to an earlier request. |
37 | |
38 | =cut |
39 | |
40 | sub result :Local :Args(0) { |
41 | my( $self, $c ) = @_; |
42 | if( $c->request->method eq 'POST' ) { |
43 | # TODO: Verify the sender! |
44 | my $answer; |
45 | if( ref( $c->request->body ) eq 'File::Temp' ) { |
46 | # Read in the file and parse that. |
47 | open( POSTDATA, $c->request->body ) or die "Failed to open post data file"; |
48 | binmode( POSTDATA, ':utf8' ); |
49 | # JSON should be all one line |
50 | my $pdata = <POSTDATA>; |
51 | chomp $pdata; |
52 | close POSTDATA; |
53 | $answer = from_json( $pdata ); |
54 | } else { |
55 | $answer = from_json( $c->request->body ); |
56 | } |
57 | # Find a tradition with the defined Stemweb job ID. |
58 | # TODO: Maybe get Stemweb to pass back the tradition ID... |
59 | my $m = $c->model('Directory'); |
60 | my @traditions; |
61 | $m->scan( sub{ push( @traditions, $_[0] ) |
62 | if $_[0]->$_isa('Text::Tradition') |
63 | && $_[0]->has_stemweb_jobid |
64 | && $_[0]->stemweb_jobid eq $answer->{job_id}; |
65 | } ); |
66 | if( @traditions == 1 ) { |
67 | my $tradition = shift @traditions; |
68 | if( $answer->{status} == 0 ) { |
69 | try { |
70 | $tradition->record_stemweb_result( $answer ); |
71 | $m->save( $tradition ); |
72 | } catch( Text::Tradition::Error $e ) { |
73 | return _json_error( $c, 500, $e->message ); |
74 | } catch { |
75 | return _json_error( $c, 500, $@ ); |
76 | } |
77 | # If we got here, success! |
78 | $c->stash->{'result'} = { 'status' => 'success' }; |
79 | $c->forward('View::JSON'); |
80 | } else { |
81 | return _json_error( $c, 500, |
82 | "Stemweb failure not handled: " . $answer->{result} ); |
83 | } |
84 | } elsif( @traditions ) { |
85 | return _json_error( $c, 500, |
86 | "Multiple traditions with Stemweb job ID " . $answer->{job_id} . "!" ); |
87 | } else { |
88 | return _json_error( $c, 400, |
89 | "No tradition found with Stemweb job ID " . $answer->{job_id} ); |
90 | } |
91 | } else { |
92 | return _json_error( $c, 403, 'Please use POST!' ); |
93 | } |
94 | } |
95 | |
96 | # Helper to throw a JSON exception |
97 | sub _json_error { |
98 | my( $c, $code, $errmsg ) = @_; |
99 | $c->response->status( $code ); |
100 | $c->stash->{'result'} = { 'error' => $errmsg }; |
101 | $c->forward('View::JSON'); |
102 | return 0; |
103 | } |
104 | |
105 | 1; |