Subversion Repositories HomeAutomation

Rev

Rev 997 | Go to most recent revision | 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.     myContext = Context::New(NULL, myGlobal);
  91.  
  92.  
  93.     if (loadScript("System/Base.js"))
  94.     {
  95.         loadScript("System/Startup.js");
  96.  
  97.         loadScript("Autostart.js");
  98.  
  99.         Context::Scope contextScope(myContext);
  100.  
  101.         myFunctionStartup = Handle<Function>::Cast(myContext->Global()->Get(String::New("startup")));
  102.     }
  103.     else
  104.     {
  105.         ///FIXME: We should probably exit the application here
  106.         return;
  107.     }
  108.  
  109.     const int argc = 0;
  110.     Handle<Value> argv[argc] = { };
  111.     Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv);
  112.  
  113.  
  114.     string commandPort = Settings::get("CommandPort");
  115.     if (commandPort != "")
  116.     {
  117.         myCommandThread.setSettings(stoi(commandPort), "Command console");
  118.         myCommandThread.start();
  119.     }
  120.     else
  121.     {
  122.         SyslogStream &slog = SyslogStream::getInstance();
  123.         slog << "CommandPort is not defined, can not start Command console socket\n";
  124.     }
  125.  
  126.  
  127.     mySemaphore.lock();
  128.  
  129.     while (true)
  130.     {
  131.         while (myExpressions.size() > 0)
  132.         {
  133.             runExpression(myExpressions.pop());
  134.         }
  135.  
  136.         mySemaphore.wait();
  137.     }
  138.  
  139.     mySemaphore.unlock();
  140. }
  141.  
  142. void VirtualMachine::queueExpression(Expression expression)
  143. {
  144.     myExpressions.push(expression);
  145.     mySemaphore.broadcast();
  146. }
  147.  
  148. string VirtualMachine::formatException(TryCatch* tryCatch)
  149. {
  150.     string result;
  151.  
  152.     HandleScope handleScope;
  153.     String::Utf8Value exception(tryCatch->Exception());
  154.     Handle<v8::Message> message = tryCatch->Message();
  155.  
  156.     string strException = *exception;
  157.  
  158.     if (message.IsEmpty())
  159.     {
  160.         result += strException + "\n";
  161.     }
  162.     else
  163.     {
  164.         String::Utf8Value filename(message->GetScriptResourceName());
  165.         string strFilename = *filename;
  166.  
  167.         result += strFilename + ":" + itos(message->GetLineNumber()) + ": " + strException + "\n";
  168.  
  169.         String::Utf8Value sourceline(message->GetSourceLine());
  170.         string strSourceline = *sourceline;
  171.  
  172.         result += strSourceline + "\n";
  173.  
  174.         string underline = rpad("", message->GetStartColumn(), ' ');
  175.         underline = rpad(underline, message->GetEndColumn(), '^');
  176.  
  177.         result += underline + "\n";
  178.     }
  179.  
  180.     return result;
  181. }
  182.  
  183. bool VirtualMachine::loadScript(string scriptName)
  184. {
  185.     SyslogStream &slog = SyslogStream::getInstance();
  186.  
  187.     string basePath = Settings::get("BasePath") + "Services/";
  188.     string scriptFileName = basePath + scriptName;
  189.  
  190.     if (!file_exists(scriptFileName))
  191.     {
  192.         slog << "Failed to load " + scriptFileName + ", file does not exist.\n";
  193.         return false;
  194.     }
  195.  
  196.     string scriptSource = file_get_contents(scriptFileName);
  197.  
  198.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  199.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  200.  
  201.     Context::Scope contextScope(myContext);
  202.  
  203.     TryCatch tryCatch;
  204.  
  205.     Handle<Script> script = Script::Compile(source, name);
  206.  
  207.     if (script.IsEmpty())
  208.     {
  209.         slog << formatException(&tryCatch);
  210.         return false;
  211.     }
  212.     else
  213.     {
  214.         Handle<Value> result = script->Run();
  215.  
  216.         if (result.IsEmpty())
  217.         {
  218.             slog << formatException(&tryCatch);
  219.             return false;
  220.         }
  221.  
  222.         slog << "Loaded " + scriptName + "\n";
  223.     }
  224.  
  225.     return true;
  226. }
  227.  
  228. unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
  229. {
  230.     IntervalThread *intervalThread = new IntervalThread(timeout);
  231.  
  232.     myIntervalThreads[intervalThread->getId()] = intervalThread;
  233.     myIntervalThreads[intervalThread->getId()]->start();
  234.  
  235.     return intervalThread->getId();
  236. }
  237.  
  238. bool VirtualMachine::stopIntervalThread(unsigned int id)
  239. {
  240.     if (myIntervalThreads.find(id) != myIntervalThreads.end())
  241.     {
  242.         delete myIntervalThreads[id];
  243.         myIntervalThreads.erase(id);
  244.         return true;
  245.     }
  246.  
  247.     return false;
  248. }
  249.  
  250. unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
  251. {
  252.     SocketThread *socketThread = new SocketThread(address, port, reconnectTimeout);
  253.     mySocketThreads[socketThread->getId()] = socketThread;
  254.     mySocketThreads[socketThread->getId()]->start();
  255.  
  256.     return socketThread->getId();
  257. }
  258.  
  259. bool VirtualMachine::stopSocketThread(unsigned int id)
  260. {
  261.     if (mySocketThreads.find(id) != mySocketThreads.end())
  262.     {
  263.         delete mySocketThreads[id];
  264.         mySocketThreads.erase(id);
  265.         return true;
  266.     }
  267.  
  268.     return false;
  269. }
  270.  
  271. void VirtualMachine::sendToSocketThread(unsigned int id, string data)
  272. {
  273.     if (mySocketThreads.find(id) != mySocketThreads.end())
  274.     {
  275.         mySocketThreads[id]->send(data);
  276.     }
  277. }
  278.  
  279. void VirtualMachine::disconnectCommandClient(unsigned int id)
  280. {
  281.     myCommandThread.disconnectClient(id);
  282. }
  283.  
  284. void VirtualMachine::sendToCommandClient(unsigned int id, string data)
  285. {
  286.     myCommandThread.sendTo(id, data);
  287. }
  288.  
  289. void VirtualMachine::print(unsigned int id, string data)
  290. {
  291.     if (id == 0)
  292.     {
  293.         SyslogStream &slog = SyslogStream::getInstance();
  294.         slog << data;
  295.     }
  296.     else
  297.     {
  298.         VirtualMachine &vm = VirtualMachine::getInstance();
  299.         vm.sendToCommandClient(id, data);
  300.     }
  301. }
  302.  
  303. bool VirtualMachine::runExpression(Expression expression)
  304. {
  305.     string scriptName = "runExpression";
  306.  
  307.     string scriptData = expression.getScript();
  308.  
  309.     scriptData = "setClientId(" + itos(expression.getTargetId()) + ");\n" + scriptData;
  310.  
  311.     Handle<String> source =  String::New(scriptData.c_str(), scriptData.length());
  312.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  313.  
  314.     Context::Scope contextScope(myContext);
  315.  
  316.     TryCatch tryCatch;
  317.  
  318.     Handle<Script> script = Script::Compile(source, name);
  319.  
  320.     if (script.IsEmpty())
  321.     {
  322.         print(expression.getTargetId(), formatException(&tryCatch));
  323.         return false;
  324.     }
  325.     else
  326.     {
  327.         Handle<Value> result = script->Run();
  328.  
  329.         if (result.IsEmpty())
  330.         {
  331.             print(expression.getTargetId(), formatException(&tryCatch));
  332.             return false;
  333.         }
  334.         else if (expression.getTargetId() != 0)
  335.         {
  336.              String::AsciiValue ascii(result);
  337.              string resultString = *ascii;
  338.  
  339.              if (resultString != "undefined")
  340.              {
  341.                 print(expression.getTargetId(), resultString + "\n");
  342.              }
  343.         }
  344.     }
  345.  
  346.     return true;
  347. }
  348.  
  349.  
  350. Handle<Value> VirtualMachine::_quit(const Arguments& args)
  351. {
  352.     VirtualMachine &vm = VirtualMachine::getInstance();
  353.  
  354.     vm.disconnectCommandClient(args[0]->Uint32Value());
  355.  
  356.     return Undefined();
  357. }
  358.  
  359. Handle<Value> VirtualMachine::_log(const Arguments& args)
  360. {
  361.     SyslogStream &slog = SyslogStream::getInstance();
  362.  
  363.     String::AsciiValue str(args[0]);
  364.  
  365.     slog << *str;
  366.  
  367.     return Undefined();
  368. }
  369.  
  370. Handle<Value> VirtualMachine::_print(const Arguments& args)
  371. {
  372.     VirtualMachine &vm = VirtualMachine::getInstance();
  373.  
  374.     String::AsciiValue str(args[1]);
  375.  
  376.     vm.print(args[0]->Uint32Value(), *str);
  377.  
  378.     return Undefined();
  379. }
  380.  
  381. Handle<Value> VirtualMachine::_sendCanMessage(const Arguments& args)
  382. {
  383.     CanNetManager &canMan = CanNetManager::getInstance();
  384.  
  385.     CanMessage canMessage;
  386.  
  387.     String::AsciiValue className(args[0]);
  388.     canMessage.setClassName(*className);
  389.     String::AsciiValue directionFlag(args[1]);
  390.     canMessage.setDirectionFlag(*directionFlag);
  391.     String::AsciiValue moduleName(args[2]);
  392.     canMessage.setModuleName(*moduleName);
  393.     canMessage.setModuleId(args[3]->Uint32Value());
  394.     String::AsciiValue commandName(args[4]);
  395.     canMessage.setCommandName(*commandName);
  396.  
  397.     String::AsciiValue dataString(args[5]);
  398.  
  399.     vector<string> parts = explode(",", trim(*dataString, ','));
  400.     map<string, CanVariable> data;
  401.  
  402.     for (int n = 0; n < parts.size(); n++)
  403.     {
  404.         vector<string> keyAndValue = explode(":", parts[n]);
  405.  
  406.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  407.     }
  408.  
  409.     canMessage.setData(data);
  410.    
  411.     canMan.sendMessage(canMessage);
  412.  
  413.     return Undefined();
  414. }
  415.  
  416. Handle<Value> VirtualMachine::_sendCanNMTMessage(const Arguments& args)
  417. {
  418.     CanNetManager &canMan = CanNetManager::getInstance();
  419.  
  420.     CanMessage canMessage;
  421.  
  422.     String::AsciiValue className(args[0]);
  423.     canMessage.setClassName(*className);
  424.     String::AsciiValue commandName(args[1]);
  425.     canMessage.setCommandName(*commandName);
  426.  
  427.     String::AsciiValue dataString(args[2]);
  428.  
  429.     vector<string> parts = explode(",", trim(*dataString, ','));
  430.     map<string, CanVariable> data;
  431.  
  432.     for (int n = 0; n < parts.size(); n++)
  433.     {
  434.         vector<string> keyAndValue = explode(":", parts[n]);
  435.  
  436.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  437.     }
  438.  
  439.     canMessage.setData(data);
  440.  
  441.     canMan.sendMessage(canMessage);
  442.  
  443.     return Undefined();
  444. }
  445.  
  446. Handle<Value> VirtualMachine::_loadScript(const Arguments& args)
  447. {
  448.     VirtualMachine &vm = VirtualMachine::getInstance();
  449.  
  450.     String::AsciiValue str(args[0]);
  451.  
  452.     return Boolean::New(vm.loadScript(*str));
  453. }
  454.  
  455. Handle<Value> VirtualMachine::_startIntervalThread(const Arguments& args)
  456. {
  457.     VirtualMachine &vm = VirtualMachine::getInstance();
  458.     return Integer::New(vm.startIntervalThread(args[0]->Uint32Value()));
  459. }
  460.  
  461. Handle<Value> VirtualMachine::_stopIntervalThread(const Arguments& args)
  462. {
  463.     VirtualMachine &vm = VirtualMachine::getInstance();
  464.     return Boolean::New(vm.stopIntervalThread(args[0]->Uint32Value()));
  465. }
  466.  
  467. Handle<Value> VirtualMachine::_startSocketThread(const Arguments& args)
  468. {
  469.     VirtualMachine &vm = VirtualMachine::getInstance();
  470.  
  471.     String::AsciiValue address(args[0]);
  472.  
  473.     return Integer::New(vm.startSocketThread(*address, args[1]->Uint32Value(), args[2]->Uint32Value()));
  474. }
  475.  
  476. Handle<Value> VirtualMachine::_stopSocketThread(const Arguments& args)
  477. {
  478.     VirtualMachine &vm = VirtualMachine::getInstance();
  479.  
  480.     return Boolean::New(vm.stopSocketThread(args[0]->Uint32Value()));
  481. }
  482.  
  483. Handle<Value> VirtualMachine::_sendToSocketThread(const Arguments& args)
  484. {
  485.     VirtualMachine &vm = VirtualMachine::getInstance();
  486.  
  487.     String::AsciiValue data(args[1]);
  488.  
  489.     vm.sendToSocketThread(args[0]->Uint32Value(), *data);
  490.  
  491.     return Undefined();
  492. }
  493.  
  494. Handle<Value> VirtualMachine::_uint2hex(const Arguments& args)
  495. {
  496.     VirtualMachine &vm = VirtualMachine::getInstance();
  497.  
  498.     string hexId = uint2hex(args[0]->Uint32Value(), args[1]->Uint32Value());
  499.  
  500.     return String::New(hexId.c_str());
  501. }
  502.  
  503.