diff options
| author | Tim Redfern <tim@eclectronics.org> | 2014-01-27 12:24:41 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2014-01-27 12:24:41 +0000 |
| commit | 487fcf990f3c536d7e1d2f66daa0c34c0407eac5 (patch) | |
| tree | 4f0dd5aa9d74af5e3e7628fbe20e1f0af60f512a /NT/src/rotord.cpp | |
| parent | 1f2bc21fd5ee9bff4fce190d7bb0ee4462e76e87 (diff) | |
NT resinstated as HTTP server
Diffstat (limited to 'NT/src/rotord.cpp')
| -rw-r--r-- | NT/src/rotord.cpp | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/NT/src/rotord.cpp b/NT/src/rotord.cpp new file mode 100644 index 0000000..d1c1e66 --- /dev/null +++ b/NT/src/rotord.cpp @@ -0,0 +1,382 @@ +#include "rotord.h" + +using namespace Rotor; + +RenderContextHandler::RenderContextHandler(const std::string _content,const HTTPServerResponse::HTTPStatus _status){ + content=_content; + status=_status; +} + + +void RenderContextHandler::handleRequest(HTTPServerRequest& request,HTTPServerResponse& response) { + + response.setChunkedTransferEncoding(true); + response.setContentType("text/html"); + response.setStatus(status); + + std::ostream& ostr = response.send(); + + ostr << content; + +} + + +HTTPRequestHandler* RotorRequestHandlerFactory::createRequestHandler(const HTTPServerRequest& request){ + + + Poco::URI theuri=Poco::URI(request.getURI()); + std::vector <std::string> command; + theuri.getPathSegments(command); + + Logger& logger = Logger::get("Rotor"); + //logger.information(request.clientAddress().toString()+" "+request.getMethod()); + + HTTPResponse::HTTPStatus status=HTTPResponse::HTTP_BAD_REQUEST; //by default + + std::string body; + std::ostringstream os; + os<<request.stream().rdbuf(); + body=os.str(); + + xmlIO XML; //xml object handles the servers responses + XML.addTag("rotor"); + + //can we create a tinyxml object here and pass a pointer to it to the render context? + //can tinyxml output to a string? is there any reason to use poco instead? + + + if (command.size()) { + /* + if (command[0]=="thumbnail") { + XML.pushTag("rotor"); + if (request.getMethod()=="POST") { + if (body.size()){ + int w=320; + int h=180; + if (command.size()>1){ + Poco::StringTokenizer t1(command[1],","); + if (t1.count()>1){ + int _w=toInt(t1[0]); + int _h=toInt(t1[1]); + if (_h>16&&_w>16){ + w=_w; + h=_h; + } + } + } + Thumbnailer thumb; + Poco::StringTokenizer t1(body,"."); + if (t1.count()>1){ + if (thumb.make(media_dir+body,w,h,thumbnail_dir+t1[0]+".jpg")){ + status=HTTPResponse::HTTP_OK; + XML.addValue("thumbnail",t1[0]+".jpg"); + } + else { + status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; + logger.error("ERROR: could not create thumbnail for "+media_dir+body); + XML.addValue("error","could not create thumbnail for "+media_dir+body); + } + } + else { + if (thumb.make(media_dir+body,w,h,thumbnail_dir+body+".jpg")){ + status=HTTPResponse::HTTP_OK; + XML.addValue("thumbnail",body+".jpg"); + } + else { + status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; + logger.error("ERROR: could not create thumbnail for "+media_dir+body); + XML.addValue("error","could not create thumbnail for "+media_dir+body); + } + } + } + else { + status=HTTPResponse::HTTP_BAD_REQUEST; + logger.error("ERROR: Body missing"); + XML.addValue("error","Body missing"); + } + } + else { + status=HTTPResponse::HTTP_BAD_REQUEST; + logger.error("ERROR: Invalid command combination"); + XML.addValue("error","Invalid command combination"); + } + } + else */ if (command[0]=="new") { + XML.pushTag("rotor"); + if (request.getMethod()=="GET") { + string sID=idGen.createOne().toString(); //create() seems to cause problems + //Creates a new time-based UUID, using the MAC address of one of the system's ethernet adapters. + //Throws a SystemException if no MAC address can be obtained. + // + //seems to hang, to me + logger.information("starting thread "+sID); + manager.start(new Rotor::Render_context(sID)); + //XML.addTag("sID"); + XML.addValue("sID",sID); + status=HTTPResponse::HTTP_OK; + } + else if (request.getMethod()=="PUT") { //unofficial manual thread name + if (body.size()) { + string sID=body; + bool found=false; + for (auto& task: manager.taskList()) { + if(task->name()==sID) { + logger.error("ERROR: tried to create thread with existing name "+sID); + XML.addValue("error","Render context /"+sID+"/ exists already"); + found=true; + } + } + if (!found){ + logger.information("starting thread "+sID); + manager.start(new Rotor::Render_context(sID)); + XML.addValue("sID",sID); + status=HTTPResponse::HTTP_OK; + } + } + } + else { + status=HTTPResponse::HTTP_BAD_REQUEST; + logger.error("ERROR: Body missing"); + XML.addValue("error","Body missing"); + } + } + else if (command[0]=="list") { + XML.pushTag("rotor"); + if (request.getMethod()=="GET") { + logger.information("sending tasklist"); + //std::list < Poco::AutoPtr < Poco::Task > >::iterator it; + //it=manager.taskList().begin(); + //for (it=manager.taskList().begin();it !=manager.taskList().end();++it) { + //content+="<sID>"+(*it)->name()+"</sID>\n"; + //} + + //massive problems making an iterator for the tasklist, the above crashes + //solution: auto type range-based for-loop + //this is c++11 specific but works + + for (auto& task: manager.taskList()) { //c++11 + XML.addValue("sID",task->name()); + } + status=HTTPResponse::HTTP_OK; + } + else { + status=HTTPResponse::HTTP_BAD_REQUEST; + logger.error("ERROR: Invalid command combination"); + XML.addValue("error","Invalid command combination"); + } + } + else if (command[0]=="listnodes") { + Node_factory factory; + Json::Value root=factory.list_nodes(); + Json::StyledWriter writer; + string content = writer.write(root); + status=HTTPResponse::HTTP_OK; + return new RenderContextHandler(content, status); + } + else if (command[0]=="listcategories") { + Node_factory factory; + Json::Value root=factory.list_categories(); + Json::StyledWriter writer; + string content = writer.write(root); + status=HTTPResponse::HTTP_OK; + return new RenderContextHandler(content, status); + } + else if (command[0]=="listnode") { + if (request.getMethod()=="GET") { + Node_factory factory; + Json::Value root=factory.list_node(body); + Json::StyledWriter writer; + string content = writer.write(root); + status=HTTPResponse::HTTP_OK; + return new RenderContextHandler(content, status); + } + else { + status=HTTPResponse::HTTP_BAD_REQUEST; + logger.error("ERROR: Invalid command combination"); + XML.addValue("error","Invalid command combination"); + } + } + else if (command[0]=="listrenders") { + XML.pushTag("rotor"); + if (request.getMethod()=="GET") { + int i=0; + for (auto r: renders){ + XML.addTag("render"); + XML.addAttribute("render","ID",r.first,i); + bool context_found=false; + for (auto& task: manager.taskList()) { + if(task->name()==r.second) { + Render_status status=((Poco::AutoPtr<Rotor::Render_context>)task)->get_render_status(r.first); + //cerr<<"render "<<r.first<<" found, context "<<r.second<<", status: "<<status.status<<endl; + switch (status.status) { + case RENDERING: + XML.addAttribute("render","status","rendering",i); + XML.addAttribute("render","progress",status.progress,i); + break; + case RENDER_READY: + XML.addAttribute("render","status","complete",i); + break; + case FAILED: + XML.addAttribute("render","status","failed",i); + break; + case NOT_FOUND: + XML.addAttribute("render","error","not found",i); + break; + case CANCELLED: + XML.addAttribute("render","status","cancelled",i); + break; + } + context_found=true; + } + } + if (!context_found) XML.addAttribute("render","status","context unavailable",i); + i++; + } + status=HTTPResponse::HTTP_OK; + } + else { + status=HTTPResponse::HTTP_BAD_REQUEST; + logger.error("ERROR: Invalid command combination"); + XML.addValue("error","Invalid command combination"); + } + } + else if (command[0]=="exit") { + logger.information("exiting"); + exit(0); + } + else { + bool found=false; + for (auto& task: manager.taskList()) { //c++11 + if(task->name()==command[0]) { + //valid session command + + /* + found=true; + XML.addAttribute("rotor","context",task->name(),0); + XML.pushTag("rotor"); + if (command.size()==1) { + //just invoking sID + if (request.getMethod()=="DELETE") { + task->cancel(); + status=HTTPResponse::HTTP_OK; + logger.information("deleted context "+command[0]); + XML.addValue("status","context deleted successfully"); + } + else { + logger.error("ERROR: Render context invoked with no command: "+command[0]); + XML.addValue("error","Render context invoked with no command"); + } + } + else { //session modifier command- to be passed to render context + //some commands need to return error codes + //ie where the audio file isn't found + //on the other hand, some commands need to know state of the renderer? + + + Session_command SC; + vector<string> sc; //uid,method,id,command1,{command2,}{body} + SC.uid=idGen.createOne().toString(); + sc.push_back(request.getMethod()); + SC.method=request.getMethod(); + for (auto& i: command){ + sc.push_back(i); + SC.commands.push_back(i); + } + sc.push_back(body); + SC.body=body; + + ((Poco::AutoPtr<Rotor::Render_context>)task)->session_command(SC,XML,status); + if (XML.tagExists("render_id")){ + //cerr<<"render started: "<<SC.uid<<" in context: "<<command[0]<<endl; + renders[SC.uid]=command[0]; + } + } + */ + } + } + if (!found) { + status=HTTPResponse::HTTP_NOT_FOUND; + logger.error("ERROR: context not found: "+command[0]); + XML.pushTag("rotor"); + XML.addValue("error","Render context not found"); + } + } + } + else { + logger.error("ERROR: Empty request"); + XML.addValue("error","Empty request"); + } + string header="<?xml version='1.0' encoding='ISO-8859-1'?>\n"; + string content; + XML.copyXmlToString(content); + header+=content; + return new RenderContextHandler(header, status); + +} + + +RotorServer::RotorServer(): _helpRequested(false) +{ +} + +RotorServer::~RotorServer() +{ +} + +void RotorServer::initialize(Application& self){ + loadConfiguration(); + ServerApplication::initialize(self); +} + +void RotorServer::uninitialize(){ + ServerApplication::uninitialize(); +} + +void RotorServer::defineOptions(OptionSet& options) { + ServerApplication::defineOptions(options); + options.addOption( + Option("help", "h", "display argument help information") + .required(false) + .repeatable(false) + .callback(OptionCallback<RotorServer>(this, &RotorServer::handleHelp) + ) + ); +} + +void RotorServer::handleHelp(const std::string& name, const std::string& value){ + HelpFormatter helpFormatter(options()); + helpFormatter.setCommand(commandName()); + helpFormatter.setUsage("OPTIONS"); + helpFormatter.setHeader( + "Rotor"); + helpFormatter.format(std::cout); + stopOptionsProcessing(); + _helpRequested = true; +} + +int RotorServer::main(const std::vector<std::string>& args){ + if (!_helpRequested) { + + unsigned short port=9000; + static Logger& logger = Logger::get("Rotor"); + + xmlIO xml; + if(xml.loadFile("settings.xml") ){ + port=xml.getAttribute("Rotor","port",9000,0); + } + else logger.information("settings.xml not found, using defaults"); + + logger.information("rotord running on port "+toString(port)); + + port = (unsigned short) config().getInt("port", port); //override from command line + + std::string format(config().getString("format", DateTimeFormat::SORTABLE_FORMAT)); + + ServerSocket svs(port); + HTTPServer srv(new RotorRequestHandlerFactory(),svs, new HTTPServerParams); + srv.start(); + waitForTerminationRequest(); + srv.stop(); + } + return Application::EXIT_OK; +} |
