Missing files.
[dcpomatic.git] / src / lib / json_server.cc
1 /*
2     Copyright (C) 2014 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 "transcode_job.h"
28
29 using std::string;
30 using std::stringstream;
31 using std::cout;
32 using std::map;
33 using std::list;
34 using boost::thread;
35 using boost::shared_ptr;
36 using boost::dynamic_pointer_cast;
37 using boost::asio::ip::tcp;
38
39 #define MAX_LENGTH 512
40
41 enum State {
42         AWAITING_G,
43         AWAITING_E,
44         AWAITING_T,
45         AWAITING_SPACE,
46         READING_URL,
47 };
48
49 JSONServer::JSONServer (int port)
50 {
51         new thread (boost::bind (&JSONServer::run, this, port));
52 }
53
54 void
55 JSONServer::run (int port)
56 try
57 {
58         boost::asio::io_service io_service;
59         tcp::acceptor a (io_service, tcp::endpoint (tcp::v4 (), port));
60         while (1) {
61                 try {
62                         shared_ptr<tcp::socket> s (new tcp::socket (io_service));
63                         a.accept (*s);
64                         handle (s);
65                 }
66                 catch (...) {
67
68                 }
69         }
70 }
71 catch (...)
72 {
73
74 }
75
76 void
77 JSONServer::handle (shared_ptr<tcp::socket> socket)
78 {
79         string url;
80         State state = AWAITING_G;
81
82         while (1) {
83                 char data[MAX_LENGTH];
84                 boost::system::error_code error;
85                 size_t len = socket->read_some (boost::asio::buffer (data), error);
86                 if (error) {
87                         cout << "error.\n";
88                         break;
89                 }
90
91                 char* p = data;
92                 char* e = data + len;
93                 while (p != e) {
94
95                         State old_state = state;
96                         switch (state) {
97                         case AWAITING_G:
98                                 if (*p == 'G') {
99                                         state = AWAITING_E;
100                                 }
101                                 break;
102                         case AWAITING_E:
103                                 if (*p == 'E') {
104                                         state = AWAITING_T;
105                                 }
106                                 break;
107                         case AWAITING_T:
108                                 if (*p == 'T') {
109                                         state = AWAITING_SPACE;
110                                 }
111                                 break;
112                         case AWAITING_SPACE:
113                                 if (*p == ' ') {
114                                         state = READING_URL;
115                                 }
116                                 break;
117                         case READING_URL:
118                                 if (*p == ' ') {
119                                         request (url, socket);
120                                         state = AWAITING_G;
121                                         url = "";
122                                 } else {
123                                         url += *p;
124                                 }
125                                 break;
126                         }
127
128                         if (state == old_state && state != READING_URL) {
129                                 state = AWAITING_G;
130                         }
131
132                         ++p;
133                 }
134         }
135 }
136
137 void
138 JSONServer::request (string url, shared_ptr<tcp::socket> socket)
139 {
140         cout << "request: " << url << "\n";
141         
142         map<string, string> r = split_get_request (url);
143         for (map<string, string>::iterator i = r.begin(); i != r.end(); ++i) {
144                 cout << i->first << " => " << i->second << "\n";
145         }
146         
147         string action;
148         if (r.find ("action") != r.end ()) {
149                 action = r["action"];
150         }
151         
152         stringstream json;
153         if (action == "status") {
154                 
155                 list<shared_ptr<Job> > jobs = JobManager::instance()->get ();
156                 
157                 json << "{ \"jobs\": [";
158                 for (list<shared_ptr<Job> >::iterator i = jobs.begin(); i != jobs.end(); ++i) {
159
160                         json << "{ "
161                              << "\"name\": \""   << (*i)->json_name() << "\", "
162                              << "\"progress\": " << (*i)->progress () << ", "
163                              << "\"status\": \"" << (*i)->json_status() << "\"";
164                         
165                         json << " }";
166                         
167                         list<shared_ptr<Job> >::iterator j = i;
168                         ++j;
169                         if (j != jobs.end ()) {
170                                 json << ", ";
171                         }
172                 }
173                 json << "] }";
174                 
175                 if (json.str().empty ()) {
176                         json << "{ }";
177                 }
178         }
179         
180         stringstream reply;
181         reply << "HTTP/1.1 200 OK\r\n"
182               << "Content-Length: " << json.str().length() << "\r\n"
183               << "Content-Type: application/json\r\n"
184                               << "\r\n"
185               << json.str () << "\r\n";
186         cout << "reply: " << json.str() << "\n";
187         boost::asio::write (*socket, boost::asio::buffer (reply.str().c_str(), reply.str().length()));
188 }