Subversion Repositories HomeAutomation

Rev

Rev 999 | Blame | Last modification | View Log | SVN | RSS feed

  1. /***************************************************************************
  2.  *   Copyright (C) December 10, 2008 by Mattias Runge                             *
  3.  *   mattias@runge.se                                                      *
  4.  *   virtualmachine.cpp                                            *
  5.  *                                                                         *
  6.  *   This program 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.  *   This program 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 this program; if not, write to the                         *
  18.  *   Free Software Foundation, Inc.,                                       *
  19.  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  20.  ***************************************************************************/
  21.  
  22. #include "virtualmachine.h"
  23.  
  24. VirtualMachine* VirtualMachine::myInstance = NULL;
  25.  
  26. VirtualMachine& VirtualMachine::getInstance()
  27. {
  28.     if (myInstance == NULL)
  29.     {
  30.         myInstance = new VirtualMachine();
  31.     }
  32.  
  33.     return *myInstance;
  34. }
  35.  
  36. void VirtualMachine::deleteInstance()
  37. {
  38.     if (myInstance != NULL)
  39.     {
  40.         delete myInstance;
  41.         myInstance = NULL;
  42.     }
  43. }
  44.  
  45. VirtualMachine::VirtualMachine()
  46. {
  47. }
  48.  
  49. VirtualMachine::~VirtualMachine()
  50. {
  51.     stop();
  52.  
  53.     myCommandThread.stop();
  54.  
  55.     ///FIXME: Verify that this works and does not cause segfaults
  56.     for (map<int, SocketThread*>::iterator iter = mySocketThreads.begin(); iter != mySocketThreads.end(); iter++)
  57.     {
  58.         iter->second->stop();
  59.         delete iter->second;
  60.         //mySocketThreads.erase(iter);
  61.     }
  62.  
  63.     mySocketThreads.clear();
  64.  
  65.     for (map<int, IntervalThread*>::iterator iter = myIntervalThreads.begin(); iter != myIntervalThreads.end(); iter++)
  66.     {
  67.         iter->second->stop();
  68.         delete iter->second;
  69.         //myIntervalThreads.erase(iter);
  70.     }
  71.  
  72.     myIntervalThreads.clear();
  73. }
  74.  
  75. void VirtualMachine::run()
  76. {
  77.     myGlobal = ObjectTemplate::New();
  78.     myGlobal->Set(String::New("_quit"), FunctionTemplate::New(VirtualMachine::_quit));
  79.     myGlobal->Set(String::New("_print"), FunctionTemplate::New(VirtualMachine::_print));
  80.     myGlobal->Set(String::New("log"), FunctionTemplate::New(VirtualMachine::_log));
  81.     myGlobal->Set(String::New("sendCanMessage"), FunctionTemplate::New(VirtualMachine::_sendCanMessage));
  82.     myGlobal->Set(String::New("sendCanNMTMessage"), FunctionTemplate::New(VirtualMachine::_sendCanNMTMessage));
  83.     myGlobal->Set(String::New("loadScript"), FunctionTemplate::New(VirtualMachine::_loadScript));
  84.     myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine::_startIntervalThread));
  85.     myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine::_stopIntervalThread));
  86.     myGlobal->Set(String::New("startSocketThread"), FunctionTemplate::New(VirtualMachine::_startSocketThread));
  87.     myGlobal->Set(String::New("stopSocketThread"), FunctionTemplate::New(VirtualMachine::_stopSocketThread));
  88.     myGlobal->Set(String::New("sendToSocketThread"), FunctionTemplate::New(VirtualMachine::_sendToSocketThread));
  89.     myGlobal->Set(String::New("uint2hex"), FunctionTemplate::New(VirtualMachine::_uint2hex));
  90.     myGlobal->Set(String::New("loadDataStore"), FunctionTemplate::New(VirtualMachine::_loadDataStore));
  91.     myContext = Context::New(NULL, myGlobal);
  92.  
  93.  
  94.     if (loadScript("System/Base.js"))
  95.     {
  96.         loadScript("System/Startup.js");
  97.  
  98.         loadScript("Autostart.js");
  99.  
  100.         Context::Scope contextScope(myContext);
  101.  
  102.         myFunctionStartup = Handle<Function>::Cast(myContext->Global()->Get(String::New("startup")));
  103.     }
  104.     else
  105.     {
  106.         ///FIXME: We should probably exit the application here
  107.         return;
  108.     }
  109.  
  110.     const int argc = 0;
  111.     Handle<Value> argv[argc] = { };
  112.     Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv);
  113.  
  114.  
  115.     string commandPort = Settings::get("CommandPort");
  116.     if (commandPort != "")
  117.     {
  118.         myCommandThread.setSettings(stoi(commandPort), "Command console");
  119.         myCommandThread.start();
  120.     }
  121.     else
  122.     {
  123.         SyslogStream &slog = SyslogStream::getInstance();
  124.         slog << "CommandPort is not defined, can not start Command console socket\n";
  125.     }
  126.  
  127.  
  128.     mySemaphore.lock();
  129.  
  130.     while (true)
  131.     {
  132.         while (myExpressions.size() > 0)
  133.         {
  134.             runExpression(myExpressions.pop());
  135.         }
  136.  
  137.         mySemaphore.wait();
  138.     }
  139.  
  140.     mySemaphore.unlock();
  141. }
  142.  
  143. void VirtualMachine::queueExpression(Expression expression)
  144. {
  145.     myExpressions.push(expression);
  146.     mySemaphore.broadcast();
  147. }
  148.  
  149. string VirtualMachine::formatException(TryCatch* tryCatch)
  150. {
  151.     string result;
  152.  
  153.     HandleScope handleScope;
  154.     String::Utf8Value exception(tryCatch->Exception());
  155.     Handle<v8::Message> message = tryCatch->Message();
  156.  
  157.     string strException = *exception;
  158.  
  159.     if (message.IsEmpty())
  160.     {
  161.         result += strException + "\n";
  162.     }
  163.     else
  164.     {
  165.         String::Utf8Value filename(message->GetScriptResourceName());
  166.         string strFilename = *filename;
  167.  
  168.         result += strFilename + ":" + itos(message->GetLineNumber()) + ": " + strException + "\n";
  169.  
  170.         String::Utf8Value sourceline(message->GetSourceLine());
  171.         string strSourceline = *sourceline;
  172.  
  173.         result += strSourceline + "\n";
  174.  
  175.         string underline = rpad("", message->GetStartColumn(), ' ');
  176.         underline = rpad(underline, message->GetEndColumn(), '^');
  177.  
  178.         result += underline + "\n";
  179.     }
  180.  
  181.     return result;
  182. }
  183.  
  184. bool VirtualMachine::loadDataStore(string storeName)
  185. {
  186.     SyslogStream &slog = SyslogStream::getInstance();
  187.  
  188.     string basePath = Settings::get("BasePath") + "Services/DataStores/";
  189.     string scriptFileName = basePath + storeName + ".js";
  190.  
  191.     if (!file_exists(scriptFileName))
  192.     {
  193.         slog << "Failed to load datastore " + scriptFileName + ", file does not exist.\n";
  194.         return false;
  195.     }
  196.  
  197.     string scriptSource = file_get_contents(scriptFileName);
  198.  
  199.     scriptSource = "DataStore.addStore('" + storeName + "', " + str_replace("\n", "", scriptSource) + ");";
  200.  
  201.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  202.     Handle<String> name = String::New(scriptFileName.c_str(), scriptFileName.length());
  203.  
  204.     Context::Scope contextScope(myContext);
  205.  
  206.     TryCatch tryCatch;
  207.  
  208.     Handle<Script> script = Script::Compile(source, name);
  209.  
  210.     if (script.IsEmpty())
  211.     {
  212.         slog << formatException(&tryCatch);
  213.         return false;
  214.     }
  215.     else
  216.     {
  217.         Handle<Value> result = script->Run();
  218.  
  219.         if (result.IsEmpty())
  220.         {
  221.             slog << formatException(&tryCatch);
  222.             return false;
  223.         }
  224.  
  225.         slog << "Loaded datastore " + storeName + "\n";
  226.     }
  227.  
  228.     return true;
  229. }
  230.  
  231. bool VirtualMachine::loadScript(string scriptName)
  232. {
  233.     SyslogStream &slog = SyslogStream::getInstance();
  234.  
  235.     string basePath = Settings::get("BasePath") + "Services/";
  236.     string scriptFileName = basePath + scriptName;
  237.  
  238.     if (!file_exists(scriptFileName))
  239.     {
  240.         slog << "Failed to load " + scriptFileName + ", file does not exist.\n";
  241.         return false;
  242.     }
  243.  
  244.     string scriptSource = file_get_contents(scriptFileName);
  245.  
  246.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  247.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  248.  
  249.     Context::Scope contextScope(myContext);
  250.  
  251.     TryCatch tryCatch;
  252.  
  253.     Handle<Script> script = Script::Compile(source, name);
  254.  
  255.     if (script.IsEmpty())
  256.     {
  257.         slog << formatException(&tryCatch);
  258.         return false;
  259.     }
  260.     else
  261.     {
  262.         Handle<Value> result = script->Run();
  263.  
  264.         if (result.IsEmpty())
  265.         {
  266.             slog << formatException(&tryCatch);
  267.             return false;
  268.         }
  269.  
  270.         slog << "Loaded " + scriptName + "\n";
  271.     }
  272.  
  273.     return true;
  274. }
  275.  
  276. unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
  277. {
  278.     IntervalThread *intervalThread = new IntervalThread(timeout);
  279.  
  280.     myIntervalThreads[intervalThread->getId()] = intervalThread;
  281.     myIntervalThreads[intervalThread->getId()]->start();
  282.  
  283.     return intervalThread->getId();
  284. }
  285.  
  286. bool VirtualMachine::stopIntervalThread(unsigned int id)
  287. {
  288.     if (myIntervalThreads.find(id) != myIntervalThreads.end())
  289.     {
  290.         delete myIntervalThreads[id];
  291.         myIntervalThreads.erase(id);
  292.         return true;
  293.     }
  294.  
  295.     return false;
  296. }
  297.  
  298. unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
  299. {
  300.     SocketThread *socketThread = new SocketThread(address, port, reconnectTimeout);
  301.     mySocketThreads[socketThread->getId()] = socketThread;
  302.     mySocketThreads[socketThread->getId()]->start();
  303.  
  304.     return socketThread->getId();
  305. }
  306.  
  307. bool VirtualMachine::stopSocketThread(unsigned int id)
  308. {
  309.     if (mySocketThreads.find(id) != mySocketThreads.end())
  310.     {
  311.         delete mySocketThreads[id];
  312.         mySocketThreads.erase(id);
  313.         return true;
  314.     }
  315.  
  316.     return false;
  317. }
  318.  
  319. void VirtualMachine::sendToSocketThread(unsigned int id, string data)
  320. {
  321.     if (mySocketThreads.find(id) != mySocketThreads.end())
  322.     {
  323.         mySocketThreads[id]->send(data);
  324.     }
  325. }
  326.  
  327. void VirtualMachine::disconnectCommandClient(unsigned int id)
  328. {
  329.     myCommandThread.disconnectClient(id);
  330. }
  331.  
  332. void VirtualMachine::sendToCommandClient(unsigned int id, string data)
  333. {
  334.     myCommandThread.sendTo(id, data);
  335. }
  336.  
  337. void VirtualMachine::print(unsigned int id, string data)
  338. {
  339.     if (id == 0)
  340.     {
  341.         SyslogStream &slog = SyslogStream::getInstance();
  342.         slog << data;
  343.     }
  344.     else
  345.     {
  346.         VirtualMachine &vm = VirtualMachine::getInstance();
  347.         vm.sendToCommandClient(id, data);
  348.     }
  349. }
  350.  
  351. bool VirtualMachine::runExpression(Expression expression)
  352. {
  353.     string scriptName = "runExpression";
  354.  
  355.     string scriptData = expression.getScript();
  356.  
  357.     scriptData = "setClientId(" + itos(expression.getTargetId()) + ");\n" + scriptData;
  358.  
  359.     Handle<String> source =  String::New(scriptData.c_str(), scriptData.length());
  360.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  361.  
  362.     Context::Scope contextScope(myContext);
  363.  
  364.     TryCatch tryCatch;
  365.  
  366.     Handle<Script> script = Script::Compile(source, name);
  367.  
  368.     if (script.IsEmpty())
  369.     {
  370.         print(expression.getTargetId(), formatException(&tryCatch));
  371.         return false;
  372.     }
  373.     else
  374.     {
  375.         Handle<Value> result = script->Run();
  376.  
  377.         if (result.IsEmpty())
  378.         {
  379.             print(expression.getTargetId(), formatException(&tryCatch));
  380.             return false;
  381.         }
  382.         else if (expression.getTargetId() != 0)
  383.         {
  384.              String::AsciiValue ascii(result);
  385.              string resultString = *ascii;
  386.  
  387.              if (resultString != "undefined")
  388.              {
  389.                 print(expression.getTargetId(), resultString + "\n");
  390.              }
  391.         }
  392.     }
  393.  
  394.     return true;
  395. }
  396.  
  397.  
  398. Handle<Value> VirtualMachine::_quit(const Arguments& args)
  399. {
  400.     VirtualMachine &vm = VirtualMachine::getInstance();
  401.  
  402.     vm.disconnectCommandClient(args[0]->Uint32Value());
  403.  
  404.     return Undefined();
  405. }
  406.  
  407. Handle<Value> VirtualMachine::_log(const Arguments& args)
  408. {
  409.     SyslogStream &slog = SyslogStream::getInstance();
  410.  
  411.     String::AsciiValue str(args[0]);
  412.  
  413.     slog << *str;
  414.  
  415.     return Undefined();
  416. }
  417.  
  418. Handle<Value> VirtualMachine::_print(const Arguments& args)
  419. {
  420.     VirtualMachine &vm = VirtualMachine::getInstance();
  421.  
  422.     String::AsciiValue str(args[1]);
  423.  
  424.     vm.print(args[0]->Uint32Value(), *str);
  425.  
  426.     return Undefined();
  427. }
  428.  
  429. Handle<Value> VirtualMachine::_sendCanMessage(const Arguments& args)
  430. {
  431.     CanNetManager &canMan = CanNetManager::getInstance();
  432.  
  433.     CanMessage canMessage;
  434.  
  435.     String::AsciiValue className(args[0]);
  436.     canMessage.setClassName(*className);
  437.     String::AsciiValue directionFlag(args[1]);
  438.     canMessage.setDirectionFlag(*directionFlag);
  439.     String::AsciiValue moduleName(args[2]);
  440.     canMessage.setModuleName(*moduleName);
  441.     canMessage.setModuleId(args[3]->Uint32Value());
  442.     String::AsciiValue commandName(args[4]);
  443.     canMessage.setCommandName(*commandName);
  444.  
  445.     String::AsciiValue dataString(args[5]);
  446.  
  447.     vector<string> parts = explode(",", trim(*dataString, ','));
  448.     map<string, CanVariable> data;
  449.  
  450.     for (int n = 0; n < parts.size(); n++)
  451.     {
  452.         vector<string> keyAndValue = explode(":", parts[n]);
  453.  
  454.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  455.     }
  456.  
  457.     canMessage.setData(data);
  458.    
  459.     canMan.sendMessage(canMessage);
  460.  
  461.     return Undefined();
  462. }
  463.  
  464. Handle<Value> VirtualMachine::_sendCanNMTMessage(const Arguments& args)
  465. {
  466.     CanNetManager &canMan = CanNetManager::getInstance();
  467.  
  468.     CanMessage canMessage;
  469.  
  470.     String::AsciiValue className(args[0]);
  471.     canMessage.setClassName(*className);
  472.     String::AsciiValue commandName(args[1]);
  473.     canMessage.setCommandName(*commandName);
  474.  
  475.     String::AsciiValue dataString(args[2]);
  476.  
  477.     vector<string> parts = explode(",", trim(*dataString, ','));
  478.     map<string, CanVariable> data;
  479.  
  480.     for (int n = 0; n < parts.size(); n++)
  481.     {
  482.         vector<string> keyAndValue = explode(":", parts[n]);
  483.  
  484.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  485.     }
  486.  
  487.     canMessage.setData(data);
  488.  
  489.     canMan.sendMessage(canMessage);
  490.  
  491.     return Undefined();
  492. }
  493.  
  494. Handle<Value> VirtualMachine::_loadScript(const Arguments& args)
  495. {
  496.     VirtualMachine &vm = VirtualMachine::getInstance();
  497.  
  498.     String::AsciiValue str(args[0]);
  499.  
  500.     return Boolean::New(vm.loadScript(*str));
  501. }
  502.  
  503. Handle<Value> VirtualMachine::_loadDataStore(const Arguments& args)
  504. {
  505.     VirtualMachine &vm = VirtualMachine::getInstance();
  506.  
  507.     String::AsciiValue str(args[0]);
  508.  
  509.     return Boolean::New(vm.loadDataStore(*str));
  510. }
  511.  
  512. Handle<Value> VirtualMachine::_startIntervalThread(const Arguments& args)
  513. {
  514.     VirtualMachine &vm = VirtualMachine::getInstance();
  515.     return Integer::New(vm.startIntervalThread(args[0]->Uint32Value()));
  516. }
  517.  
  518. Handle<Value> VirtualMachine::_stopIntervalThread(const Arguments& args)
  519. {
  520.     VirtualMachine &vm = VirtualMachine::getInstance();
  521.     return Boolean::New(vm.stopIntervalThread(args[0]->Uint32Value()));
  522. }
  523.  
  524. Handle<Value> VirtualMachine::_startSocketThread(const Arguments& args)
  525. {
  526.     VirtualMachine &vm = VirtualMachine::getInstance();
  527.  
  528.     String::AsciiValue address(args[0]);
  529.  
  530.     return Integer::New(vm.startSocketThread(*address, args[1]->Uint32Value(), args[2]->Uint32Value()));
  531. }
  532.  
  533. Handle<Value> VirtualMachine::_stopSocketThread(const Arguments& args)
  534. {
  535.     VirtualMachine &vm = VirtualMachine::getInstance();
  536.  
  537.     return Boolean::New(vm.stopSocketThread(args[0]->Uint32Value()));
  538. }
  539.  
  540. Handle<Value> VirtualMachine::_sendToSocketThread(const Arguments& args)
  541. {
  542.     VirtualMachine &vm = VirtualMachine::getInstance();
  543.  
  544.     String::AsciiValue data(args[1]);
  545.  
  546.     vm.sendToSocketThread(args[0]->Uint32Value(), *data);
  547.  
  548.     return Undefined();
  549. }
  550.  
  551. Handle<Value> VirtualMachine::_uint2hex(const Arguments& args)
  552. {
  553.     VirtualMachine &vm = VirtualMachine::getInstance();
  554.  
  555.     string hexId = uint2hex(args[0]->Uint32Value(), args[1]->Uint32Value());
  556.  
  557.     return String::New(hexId.c_str());
  558. }
  559.