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