Subversion Repositories HomeAutomation

Rev

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