svvitch
digital signage player
|
00001 #include "WebAPI.h" 00002 00003 #include <Poco/DateTime.h> 00004 #include <Poco/format.h> 00005 #include <Poco/Timezone.h> 00006 #include <Poco/DateTimeFormat.h> 00007 #include <Poco/DateTimeFormatter.h> 00008 #include <Poco/DateTimeParser.h> 00009 #include <Poco/NumberFormatter.h> 00010 #include <Poco/RegularExpression.h> 00011 #include <Poco/URI.h> 00012 00013 #include "MainScene.h" 00014 #include "CaptureScene.h" 00015 #include "Utils.h" 00016 00017 00018 SwitchRequestHandlerFactory::SwitchRequestHandlerFactory(Renderer& renderer): 00019 _log(Poco::Logger::get("")), _renderer(renderer) 00020 { 00021 _log.information("create SwitchRequestHandlerFactory"); 00022 } 00023 00024 SwitchRequestHandlerFactory::‾SwitchRequestHandlerFactory() { 00025 _log.information("release SwitchRequestHandlerFactory"); 00026 } 00027 00028 HTTPRequestHandler* SwitchRequestHandlerFactory::createRequestHandler(const HTTPServerRequest& request) { 00029 return new SwitchRequestHandler(_renderer); 00030 } 00031 00032 00033 00034 SwitchRequestHandler::SwitchRequestHandler(Renderer& renderer): BaseRequestHandler(), 00035 _renderer(renderer) 00036 { 00037 _log.debug("create SwitchRequestHandler"); 00038 } 00039 00040 SwitchRequestHandler::‾SwitchRequestHandler() { 00041 _log.debug("release SwitchRequestHandler"); 00042 } 00043 00044 00045 void SwitchRequestHandler::doRequest() { 00046 //_log.information(Poco::format("request from %s", request().clientAddress().toString())); 00047 string encoded; 00048 Poco::URI::encode(request().getURI(), "/", encoded); 00049 Poco::URI uri(encoded); 00050 //_log.information(Poco::format("webAPI access uri [%s]", uri.getPath())); 00051 //vector<string> params; 00052 //svvitch::split(uri.getPath().substr(1), '?', params, 2); 00053 vector<string> urls; 00054 svvitch::split(uri.getPath().substr(1), '/', urls, 3); 00055 // for (vector<string>::iterator it = urls.begin(); it != urls.end(); it++) { 00056 // _log.information(Poco::format("url %s", string(*it))); 00057 // } 00058 if (urls.size() > 1) { 00059 string displayID = urls[0]; 00060 if (urls[1] == "switch") { 00061 switchContent(); 00062 } else if (urls[1] == "update") { 00063 updateWorkspace(); 00064 } else if (urls[1] == "set") { 00065 if (urls.size() == 3) set(urls[2]); 00066 } else if (urls[1] == "get") { 00067 if (urls.size() == 3) get(urls[2]); 00068 } else if (urls[1] == "files") { 00069 files(); 00070 } else if (urls[1] == "download") { 00071 download(); 00072 } else if (urls[1] == "upload") { 00073 upload(); 00074 } else if (urls[1] == "clear-stock") { 00075 clearStock(); 00076 } else if (urls[1] == "copy") { 00077 copy(); 00078 00079 //} else if (urls[1] == "reboot") { 00080 // svvitch::rebootWindows(); 00081 // sendResponse(HTTPResponse::HTTP_OK, "reboot now"); 00082 00083 } else if (urls[1] == "version") { 00084 version(); 00085 } 00086 00087 } else { 00088 _log.information(Poco::format("webAPI access uri [%s]", uri.getPath())); 00089 Path src("docs", uri.getPath().substr(1)); 00090 File f(src); 00091 if (f.exists()) { 00092 if (f.isDirectory()) src = src.makeDirectory().append("index.html"); 00093 sendFile(src); 00094 } 00095 } 00096 00097 if (!response().sent()) { 00098 string s = Poco::format("<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL %s was not found on this server.</p><hr><address>switch %s</address></body></html>", request().getURI(), svvitch::version()); 00099 sendResponse(HTTPResponse::HTTP_NOT_FOUND, s); 00100 } 00101 } 00102 00103 void SwitchRequestHandler::switchContent() { 00104 try { 00105 MainScenePtr scene = dynamic_cast<MainScenePtr>(_renderer.getScene("main")); 00106 if (scene) { 00107 map<string, string> params; 00108 params["switched"] = scene->switchContent()?"true":"false"; 00109 sendJSONP(form().get("callback", ""), params); 00110 } else { 00111 sendResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, "scene not found"); 00112 } 00113 } catch (...) { 00114 } 00115 } 00116 00117 void SwitchRequestHandler::updateWorkspace() { 00118 00119 try { 00120 MainScenePtr main = dynamic_cast<MainScenePtr>(_renderer.getScene("main")); 00121 if (main) { 00122 bool result = main->flushStock() && main->updateWorkspace(); 00123 map<string, string> params; 00124 params["update"] = result?"true":"false"; 00125 sendJSONP(form().get("callback", ""), params); 00126 } else { 00127 sendResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, "scene not found"); 00128 } 00129 } catch (...) { 00130 } 00131 } 00132 00133 void SwitchRequestHandler::set(const string& command) { 00134 try { 00135 string message; 00136 MainScenePtr scene = dynamic_cast<MainScenePtr>(_renderer.getScene("main")); 00137 if (scene) { 00138 if (command == "playlist") { 00139 string playlistID = form().get("pl", ""); 00140 int playlistIndex = 0; 00141 if (form().has("i")) Poco::NumberParser::tryParse(form().get("i"), playlistIndex); 00142 _log.information(Poco::format("set playlist: [%s]-%d", playlistID, playlistIndex)); 00143 _log.information(Poco::format("playlist: %s", playlistID)); 00144 bool result = scene->stackPrepareContent(playlistID, playlistIndex); 00145 map<string, string> params; 00146 params["playlist"] = result?"true":"false"; 00147 if (result) { 00148 //Workspace& workspace = scene->getWorkspace(); 00149 //PlayListPtr playlist = workspace.getPlaylist(playlistID); 00150 //if (playlist) params["name"] = Poco::format("¥"%s¥"", playlist->name()); 00151 //params["playlist"] = Poco::format("¥"%s¥"", playlistID); 00152 //params["index"] = Poco::format("%d", playlistIndex); 00153 } 00154 sendJSONP(form().get("callback", ""), params); 00155 return; 00156 } else if (command == "text") { 00157 string playlistID = form().get("pl", ""); 00158 string text = form().get("t", ""); 00159 map<string, string> params; 00160 params["text"] = scene->setPlaylistText(playlistID, text)?"true":"false"; 00161 sendJSONP(form().get("callback", ""), params); 00162 return; 00163 00164 } else if (command == "brightness") { 00165 int i = 0; 00166 Poco::NumberParser::tryParse(form().get("v"), i); 00167 scene->setBrightness(i); 00168 map<string, string> params; 00169 params["brightness"] = Poco::format("%d", i); 00170 sendJSONP(form().get("callback", ""), params); 00171 return; 00172 00173 } else if (command == "action") { 00174 string action = form().get("v"); 00175 scene->setAction(action); 00176 map<string, string> params; 00177 params["action"] = action; 00178 sendJSONP(form().get("callback", ""), params); 00179 return; 00180 00181 } else if (command == "transition") { 00182 string transition = form().get("v"); 00183 scene->setTransition(transition); 00184 map<string, string> params; 00185 params["transition"] = transition; 00186 sendJSONP(form().get("callback", ""), params); 00187 return; 00188 00189 } else if (command == "status") { 00190 bool result = false; 00191 string name = form().get("n"); 00192 string value = form().get("v"); 00193 ScenePtr targetScene = scene; 00194 string s = form().get("s", ""); 00195 if (!s.empty()) { 00196 targetScene = _renderer.getScene(s); 00197 } 00198 if (!name.empty()) { 00199 if (value.empty()) { 00200 targetScene->removeStatus(name); 00201 } else { 00202 targetScene->setStatus(name, value); 00203 } 00204 result = true; 00205 } 00206 map<string, string> params; 00207 params["status"] = result?"true":"false"; 00208 sendJSONP(form().get("callback", ""), params); 00209 return; 00210 00211 } else { 00212 message = "property not found"; 00213 } 00214 } else { 00215 message = "scene not found"; 00216 } 00217 sendResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, message); 00218 } catch (...) { 00219 sendResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, Poco::format("failed set '%s'", command)); 00220 } 00221 } 00222 00223 void SwitchRequestHandler::get(const string& command) { 00224 try { 00225 string message; 00226 MainScenePtr scene = dynamic_cast<MainScenePtr>(_renderer.getScene("main")); 00227 if (scene) { 00228 if (command == "snapshot") { 00229 LPDIRECT3DTEXTURE9 texture = _renderer.getCaptureTexture(); 00230 if (texture) { 00231 // capture-lock 00232 LPD3DXBUFFER buf = NULL; 00233 if SUCCEEDED(D3DXSaveTextureToFileInMemory(&buf, D3DXIFF_PNG, texture, NULL)) { 00234 try { 00235 response().setContentType("image/png"); 00236 response().sendBuffer(buf->GetBufferPointer(), buf->GetBufferSize()); 00237 } catch (Poco::Exception& ex) { 00238 } 00239 SAFE_RELEASE(buf); 00240 } else { 00241 _log.warning("failed snapshot image"); 00242 } 00243 } 00244 return; 00245 00246 } else if (command == "camera") { 00247 CaptureScenePtr capture = dynamic_cast<CaptureScenePtr>(_renderer.getScene("capture")); 00248 if (capture) { 00249 LPDIRECT3DTEXTURE9 texture = capture->getCameraImage(); 00250 if (texture) { 00251 // capture-lock 00252 LPD3DXBUFFER buf = NULL; 00253 if SUCCEEDED(D3DXSaveTextureToFileInMemory(&buf, D3DXIFF_PNG, texture, NULL)) { 00254 try { 00255 response().setContentType("image/png"); 00256 response().sendBuffer(buf->GetBufferPointer(), buf->GetBufferSize()); 00257 } catch (Poco::Exception& ex) { 00258 } 00259 SAFE_RELEASE(buf); 00260 } else { 00261 _log.warning("failed snapshot image"); 00262 } 00263 } 00264 } 00265 return; 00266 00267 } else if (command == "fonts") { 00268 vector<string> fonts; 00269 scene->renderer().getPrivateFontFamilies(fonts); 00270 //vector<string> arrays; 00271 //for (vector<string>::iterator it = fonts.begin(); it != fonts.end(); it++) { 00272 //} 00273 00274 map<string, string> params; 00275 params["fonts"] = svvitch::formatJSONArray(fonts); 00276 sendJSONP(form().get("callback", ""), params); 00277 return; 00278 00279 } else if (command == "text") { 00280 string playlistID = form().get("pl", ""); 00281 string text = scene->getPlaylistText(playlistID); 00282 Poco::RegularExpression re("¥¥r|¥¥n"); 00283 re.subst(text, "¥¥n", Poco::RegularExpression::RE_GLOBAL); 00284 map<string, string> params; 00285 params["text"] = "¥"" + text + "¥""; 00286 sendJSONP(form().get("callback", ""), params); 00287 return; 00288 00289 } else if (command == "display-status") { 00290 map<string, string> status = scene->getStatus(); 00291 map<string, string>::const_iterator it = status.find("remote-copy"); 00292 map<string, string> params; 00293 if (it != status.end()) { 00294 params[it->first] = Poco::format("¥"%s¥"", it->second); 00295 } 00296 sendJSONP(form().get("callback", ""), params); 00297 return; 00298 00299 } else if (command == "status") { 00300 ScenePtr targetScene = dynamic_cast<MainScenePtr>(scene); 00301 string s = form().get("s", ""); 00302 string name = form().get("n", ""); 00303 if (!s.empty()) { 00304 targetScene = _renderer.getScene(s); 00305 if (!targetScene) { 00306 sendResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, "scene not found"); 00307 return; 00308 } 00309 } 00310 map<string, string> status = targetScene->getStatus(); 00311 if (!name.empty()) { 00312 map<string, string>::const_iterator it = status.find(name); 00313 string value; 00314 if (it != status.end()) value = it->second; 00315 sendResponse(HTTPResponse::HTTP_OK, value); 00316 } else { 00317 map<string, string> params; 00318 for (map<string, string>::const_iterator it = status.begin(); it != status.end(); it++) { 00319 params[it->first] = svvitch::formatJSON(it->second); 00320 } 00321 sendJSONP(form().get("callback", ""), params); 00322 } 00323 return; 00324 00325 } else { 00326 message = "property not found"; 00327 } 00328 } else { 00329 message = "scene not found"; 00330 } 00331 sendResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, message); 00332 } catch (...) { 00333 sendResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, Poco::format("failed get '%s'", command)); 00334 } 00335 } 00336 00337 void SwitchRequestHandler::files() { 00338 string path = form().get("path", ""); 00339 //_log.information(Poco::format("files: %s", path)); 00340 if (path.at(0) == '/' || path.at(0) == '¥¥') path = path.substr(1); 00341 Path dir(config().dataRoot, Path(path).toString()); 00342 //Path dir = config().dataRoot; 00343 try { 00344 //if (!path.empty()) dir = dir.append(path); 00345 map<string, string> result; 00346 result["count"] = Poco::format("%d", svvitch::fileCount(dir)); 00347 result["path"] = "¥"" + path + "¥""; 00348 result["files"] = fileToJSON(dir); 00349 sendJSONP(form().get("callback", ""), result); 00350 } catch (Poco::FileException& ex) { 00351 _log.warning(ex.displayText()); 00352 sendResponse(HTTPResponse::HTTP_NOT_FOUND, ex.displayText()); 00353 } catch (Poco::PathSyntaxException& ex) { 00354 _log.warning(ex.displayText()); 00355 sendResponse(HTTPResponse::HTTP_NOT_FOUND, ex.displayText()); 00356 } 00357 } 00358 00359 string SwitchRequestHandler::fileToJSON(const Path path) { 00360 string name = path.getFileName(); 00361 if (name.length() > 1 && (name.at(0) == '.' || name.at(0) == '$')) return ""; 00362 00363 if (path.isDirectory()) { 00364 vector<string> files; 00365 vector<File> list; 00366 File(path).list(list); 00367 for (vector<File>::iterator it = list.begin(); it != list.end(); it++) { 00368 // string json = fileToJSON(*it); 00369 // files.push_back(json); 00370 File f = *it; 00371 string subName = Path(f.path()).getFileName(); 00372 if (subName.length() > 1 && subName.at(0) != '.' && subName.at(0) != '$') { 00373 if (f.isDirectory()) { 00374 files.push_back(subName + "/"); 00375 } else { 00376 files.push_back(subName); 00377 } 00378 } 00379 } 00380 return svvitch::formatJSONArray(files); 00381 } 00382 map<string, string> params; 00383 params["name"] = svvitch::formatJSON(name); 00384 File f(path); 00385 Poco::DateTime modified(f.getLastModified()); 00386 modified.makeLocal(Poco::Timezone::tzd()); 00387 params["modified"] = "¥"" + Poco::DateTimeFormatter::format(modified, Poco::DateTimeFormat::SORTABLE_FORMAT) + "¥""; 00388 params["size"] = Poco::format("%Lu", f.getSize()); 00389 //if (f.getSize() < 10485760) { 00390 // // 10MB以下ならmd5を計算 00391 // params["md5"] = "¥"" + svvitch::md5(path) + "¥""; 00392 //} 00393 return svvitch::formatJSON(params); 00394 } 00395 00396 void SwitchRequestHandler::download() { 00397 try { 00398 string path = form().get("path", ""); 00399 if (path.at(0) == '/' || path.at(0) == '¥¥') path = path.substr(1); 00400 Path src(config().dataRoot, Path(path).toString()); 00401 _log.information(Poco::format("download: %s", src.toString())); 00402 sendFile(src); 00403 } catch (Poco::PathSyntaxException& ex) { 00404 _log.warning(ex.displayText()); 00405 sendResponse(HTTPResponse::HTTP_NOT_FOUND, ex.displayText()); 00406 } 00407 } 00408 00409 void SwitchRequestHandler::upload() { 00410 string path = form().get("path", ""); 00411 string modified = form().get("modified", ""); 00412 if (!path.empty()) { 00413 form(); // フォームをパースしuploadsフォルダにアップロードファイルを取り込む 00414 if (path.at(0) == '/' || path.at(0) == '¥¥') path = path.substr(1); 00415 boolean result = true; 00416 MainScenePtr main = dynamic_cast<MainScenePtr>(_renderer.getScene("main")); 00417 if (main) { 00418 vector<File> list; 00419 File("uploads").list(list); 00420 for (vector<File>::iterator it = list.begin(); it != list.end(); it++) { 00421 File src = *it; 00422 if (!modified.empty()) { 00423 int tz = 0; 00424 Poco::DateTime time; 00425 Poco::DateTimeParser::parse(Poco::DateTimeFormat::SORTABLE_FORMAT, modified, time, tz); 00426 src.setLastModified(time.timestamp()); 00427 } 00428 result &= main->addStock(path, src); 00429 } 00430 } 00431 map<string, string> params; 00432 params["upload"] = result?"true":"false"; 00433 sendJSONP(form().get("callback", ""), params); 00434 } else { 00435 sendResponse(HTTPResponse::HTTP_NOT_FOUND, "path not found"); 00436 } 00437 } 00438 00439 void SwitchRequestHandler::clearStock() { 00440 MainScenePtr main = dynamic_cast<MainScenePtr>(_renderer.getScene("main")); 00441 if (main) { 00442 main->clearStock(); 00443 00444 map<string, string> params; 00445 params["clear"] = "true"; 00446 sendJSONP(form().get("callback", ""), params); 00447 } 00448 } 00449 00450 00451 void SwitchRequestHandler::copy() { 00452 string remote = form().get("remote", ""); 00453 if (!remote.empty()) { 00454 MainScenePtr scene = dynamic_cast<MainScenePtr>(_renderer.getScene("main")); 00455 if (scene) { 00456 scene->activeCopyRemote(remote); 00457 00458 map<string, string> params; 00459 params["copy"] = "true"; 00460 sendJSONP(form().get("callback", ""), params); 00461 } 00462 } 00463 } 00464 00465 void SwitchRequestHandler::version() { 00466 map<string, string> params; 00467 params["version"] = svvitch::version(); 00468 sendJSONP(form().get("callback", ""), params); 00469 }