Subversion Repositories HomeAutomation

Rev

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