Missing files.
[dcpomatic.git] / src / lib / json_server.cc
1 /*
2     Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <boost/asio.hpp>
21 #include <boost/bind.hpp>
22 #include <boost/thread.hpp>
23 #include "json_server.h"
24 #include "job_manager.h"
25 #include "job.h"
26 #include "util.h"
27 #include "film.h"
28 #include "transcode_job.h"
29
30 using std::string;
31 using std::stringstream;
32 using std::cout;
33 using std::map;
34 using std::list;
35 using boost::thread;
36 using boost::shared_ptr;
37 using boost::dynamic_pointer_cast;
38 using boost::asio::ip::tcp;
39
40 #define MAX_LENGTH 512
41
42 enum State {
43         AWAITING_G,
44         AWAITING_E,
45         AWAITING_T,
46         AWAITING_SPACE,
47         READING_URL,
48 };
49
50 JSONServer::JSONServer (int port)
51 {
52         new thread (boost::bind (&JSONServer::run, this, port));
53 }
54
55 void
56 JSONServer::run (int port)
57 try
58 {
59         boost::asio::io_service io_service;
60         tcp::acceptor a (io_service, tcp::endpoint (tcp::v4 (), port));
61         while (true) {
62                 try {
63                         shared_ptr<tcp::socket> s (new tcp::socket (io_service));
64                         a.accept (*s);
65                         handle (s);
66                 }
67                 catch (...) {
68
69                 }
70         }
71 }
72 catch (...)
73 {
74
75 }
76
77 void
78 JSONServer::handle (shared_ptr<tcp::socket> socket)
79 {
80         string url;
81         State state = AWAITING_G;
82
83         while (true) {
84                 char data[MAX_LENGTH];
85                 boost::system::error_code error;
86                 size_t len = socket->read_some (boost::asio::buffer (data), error);
87                 if (error) {
88                         cout << "error.\n";
89                         break;
90                 }
91
92                 char* p = data;
93                 char* e = data + len;
94                 while (p != e) {
95
96                         State old_state = state;
97                         switch (state) {
98                         case AWAITING_G:
99                                 if (*p == 'G') {
100                                         state = AWAITING_E;
101                                 }
102                                 break;
103                         case AWAITING_E:
104                                 if (*p == 'E') {
105                                         state = AWAITING_T;
106                                 }
107                                 break;
108                         case AWAITING_T:
109                                 if (*p == 'T') {
110                                         state = AWAITING_SPACE;
111                                 }
112                                 break;
113                         case AWAITING_SPACE:
114                                 if (*p == ' ') {
115                                         state = READING_URL;
116                                 }
117                                 break;
118                         case READING_URL:
119                                 if (*p == ' ') {
120                                         request (url, socket);
121                                         state = AWAITING_G;
122                                         url = "";
123                                 } else {
124                                         url += *p;
125                                 }
126                                 break;
127                         }
128
129                         if (state == old_state && state != READING_URL) {
130                                 state = AWAITING_G;
131                         }
132
133                         ++p;
134                 }
135         }
136 }
137
138 void
139 JSONServer::request (string url, shared_ptr<tcp::socket> socket)
140 {
141         cout << "request: " << url << "\n";
142         
143         map<string, string> r = split_get_request (url);
144         for (map<string, string>::iterator i = r.begin(); i != r.end(); ++i) {
145                 cout << i->first << " => " << i->second << "\n";
146         }
147         
148         string action;
149         if (r.find ("action") != r.end ()) {
150                 action = r["action"];
151         }
152         
153         stringstream json;
154         if (action == "status") {
155                 
156                 list<shared_ptr<Job> > jobs = JobManager::instance()->get ();
157                 
158                 json << "{ \"jobs\": [";
159                 for (list<shared_ptr<Job> >::iterator i = jobs.begin(); i != jobs.end(); ++i) {
160
161                         json << "{ ";
162
163                         if ((*i)->film()) {
164                                 json << "\"dcp\": \"" << (*i)->film()->dcp_name() << "\", ";
165                         }
166                         
167                         json << "\"name\": \""   << (*i)->json_name() << "\", ";
168                         if ((*i)->progress ()) {
169                                 json << "\"progress\": " << (*i)->progress().get() << ", ";
170                         } else {
171                                 json << "\"progress\": unknown, ";
172                         }
173                         json << "\"status\": \"" << (*i)->json_status() << "\"";
174                         json << " }";
175                         
176                         list<shared_ptr<Job> >::iterator j = i;
177                         ++j;
178                         if (j != jobs.end ()) {
179                                 json << ", ";
180                         }
181                 }
182                 json << "] }";
183                 
184                 if (json.str().empty ()) {
185                         json << "{ }";
186                 }
187         }
188         
189         stringstream reply;
190         reply << "HTTP/1.1 200 OK\r\n"
191               << "Content-Length: " << json.str().length() << "\r\n"
192               << "Content-Type: application/json\r\n"
193                               << "\r\n"
194               << json.str () << "\r\n";
195         cout << "reply: " << json.str() << "\n";
196         boost::asio::write (*socket, boost::asio::buffer (reply.str().c_str(), reply.str().length()));
197 }