Subversion Repositories HomeAutomation

Rev

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