summaryrefslogtreecommitdiff
path: root/NT/src/rotord.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'NT/src/rotord.cpp')
-rw-r--r--NT/src/rotord.cpp382
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;
+}