Subversion Repositories HomeAutomation

Rev

Rev 983 | Rev 995 | 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.     Thread<VirtualMachine>();
  48. }
  49.  
  50. VirtualMachine::~VirtualMachine()
  51. {
  52.     stop();
  53. }
  54.  
  55. void VirtualMachine::run()
  56. {
  57.     SyslogStream &slog = SyslogStream::getInstance();
  58.  
  59.     string basePath = Settings::get("BasePath") + "Services/";
  60.     string scriptName = "Base.js";
  61.     string scriptFileName = basePath + "System/" + scriptName;
  62.  
  63.     if (!file_exists(scriptFileName))
  64.     {
  65.         slog << "Failed to load :" + scriptFileName + "\n";
  66.     }
  67.  
  68.     string scriptSource = file_get_contents(scriptFileName);
  69.  
  70.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  71.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  72.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  73.  
  74.     // Create a template for the global object.
  75.     myGlobal = ObjectTemplate::New();
  76.  
  77.     //associates "print" on script to the Print function
  78.     myGlobal->Set(String::New("log"), FunctionTemplate::New(VirtualMachine_log));
  79.     myGlobal->Set(String::New("sendCanMessage"), FunctionTemplate::New(VirtualMachine_sendCanMessage));
  80.     myGlobal->Set(String::New("sendCanNMTMessage"), FunctionTemplate::New(VirtualMachine_sendCanNMTMessage));
  81.     myGlobal->Set(String::New("loadScript"), FunctionTemplate::New(VirtualMachine_loadScript));
  82.     myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine_startIntervalThread));
  83.     myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine_stopIntervalThread));
  84.     myGlobal->Set(String::New("startSocketThread"), FunctionTemplate::New(VirtualMachine_startSocketThread));
  85.     myGlobal->Set(String::New("stopSocketThread"), FunctionTemplate::New(VirtualMachine_stopSocketThread));
  86.     myGlobal->Set(String::New("sendToSocketThread"), FunctionTemplate::New(VirtualMachine_sendToSocketThread));
  87.     myGlobal->Set(String::New("uint2hex"), FunctionTemplate::New(VirtualMachine_uint2hex));
  88.  
  89.     //create context for the script
  90.     myContext = Context::New(NULL, myGlobal);
  91.  
  92.  
  93.     //access global context within this scope
  94.     Context::Scope context_scope(myContext);
  95.     //exception handler
  96.     TryCatch try_catch;
  97.     //compile script to binary code - JIT
  98.     Handle<Script> script = Script::Compile(source, name);
  99.  
  100.     //check if we got problems on compilation
  101.     if (script.IsEmpty())
  102.     {
  103.  
  104.         // Print errors that happened during compilation.
  105.         String::AsciiValue error(try_catch.Exception());
  106.         string sError = *error;
  107.         slog << "Failed to compile script: " + sError + "\n";
  108.     }
  109.     else
  110.     {
  111.         //no errors , let's continue
  112.         Handle<Value> result = script->Run();
  113.  
  114.         //check if execution ended with errors
  115.         if (result.IsEmpty())
  116.         {
  117.             // Print errors that happened during execution.
  118.             String::AsciiValue error(try_catch.Exception());
  119.             string sError = *error;
  120.             slog << "Constructor: Failed to run script: " << sError << "\n";
  121.         }
  122.         else
  123.         {
  124.             loadScript("System/Startup.js");
  125.  
  126.             if (file_exists(basePath + "Autostart.js"))
  127.             {
  128.                 loadScript("Autostart.js");
  129.             }
  130.            
  131.             myFunctionHandleNMTMessage = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleNMTMessage")));
  132.             myFunctionOfflineCheck = Handle<Function>::Cast(myContext->Global()->Get(String::New("offlineCheck")));
  133.             myFunctionHandleMessage = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleMessage")));
  134.             myFunctionStartup = Handle<Function>::Cast(myContext->Global()->Get(String::New("startup")));
  135.         }
  136.     }
  137.  
  138.     const int argc = 0;
  139.     Handle<Value> argv[argc] = { };
  140.  
  141.     Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv); // argc and argv are your standard arguments to a function
  142.  
  143.     mySemaphore.lock();
  144.  
  145.     while (1)
  146.     {
  147.         string expression;
  148.  
  149.         while (myExpressions.size() > 0)
  150.         {
  151.             expression = myExpressions.pop();
  152.  
  153.             runExpression(expression);
  154.         }
  155.  
  156.         CanMessage canMessage;
  157.  
  158.         while (myCanMessages.size() > 0)
  159.         {
  160.             canMessage = myCanMessages.pop();
  161.  
  162.             if (canMessage.getClassName() == "nmt")
  163.             {
  164.                 callHandleNMTMessage(canMessage);
  165.             }
  166.             else
  167.             {
  168.                 callHandleMessage(canMessage);
  169.             }
  170.         }
  171.  
  172.         mySemaphore.wait();
  173.     }
  174.  
  175.     mySemaphore.unlock();
  176. }
  177.  
  178. void VirtualMachine::queueCanMessage(CanMessage canMessage)
  179. {
  180.     myCanMessages.push(canMessage);
  181.     mySemaphore.broadcast();
  182. }
  183.  
  184. void VirtualMachine::queueExpression(string expression)
  185. {
  186.     myExpressions.push(expression);
  187.     mySemaphore.broadcast();
  188. }
  189.  
  190. bool VirtualMachine::loadScript(string scriptName)
  191. {
  192.     SyslogStream &slog = SyslogStream::getInstance();
  193.  
  194.     string basePath = Settings::get("BasePath") + "Services/";
  195.     string scriptFileName = basePath + scriptName;
  196.  
  197.     if (!file_exists(scriptFileName))
  198.     {
  199.         slog << "Failed to load " + scriptFileName + "\n";
  200.         return false;
  201.     }
  202.  
  203.     string scriptSource = file_get_contents(scriptFileName);
  204.  
  205.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  206.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  207.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  208.  
  209.     //access global context within this scope
  210.     Context::Scope context_scope(myContext);
  211.     //exception handler
  212.     TryCatch try_catch;
  213.     //compile script to binary code - JIT
  214.     Handle<Script> script = Script::Compile(source, name);
  215.  
  216.     //check if we got problems on compilation
  217.     if (script.IsEmpty())
  218.     {
  219.         // Print errors that happened during compilation.
  220.         String::AsciiValue error(try_catch.Exception());
  221.         string sError = *error;
  222.         slog << "loadScript: Failed to compile script: " + sError + "\n";
  223.         return false;
  224.     }
  225.     else
  226.     {
  227.         //no errors , let's continue
  228.         Handle<Value> result = script->Run();
  229.  
  230.         //check if execution ended with errors
  231.         if (result.IsEmpty())
  232.         {
  233.             // Print errors that happened during execution.
  234.             String::AsciiValue error(try_catch.Exception());
  235.             string sError = *error;
  236.             slog << "loadScript: Failed to run script: " + sError + "\n";
  237.             return false;
  238.         }
  239.  
  240.         slog << "Loaded " + scriptName + "\n";
  241.     }
  242.  
  243.     return true;
  244. }
  245.  
  246. void VirtualMachine::callHandleNMTMessage(CanMessage canMessage)
  247. {
  248.     const int argc = 3;
  249.  
  250.     string jsonData = canMessage.getJSONData();
  251.  
  252.     Handle<Value> argv[argc] = {String::New(canMessage.getClassName().c_str()),
  253.                                 String::New(canMessage.getCommandName().c_str()),
  254.                                 String::New(jsonData.c_str()) };
  255.  
  256.     Handle<Value> result = myFunctionHandleNMTMessage->Call(myFunctionHandleNMTMessage, argc, argv); // argc and argv are your standard arguments to a function
  257. }
  258.  
  259. void VirtualMachine::callHandleMessage(CanMessage canMessage)
  260. {
  261.     const int argc = 6;
  262.  
  263.     string jsonData = canMessage.getJSONData();
  264.  
  265.     Handle<Value> argv[argc] = {String::New(canMessage.getClassName().c_str()),
  266.                                 String::New(canMessage.getDirectionFlag().c_str()),
  267.                                 String::New(canMessage.getModuleName().c_str()),
  268.                                 Integer::New(canMessage.getModuleId()),
  269.                                 String::New(canMessage.getCommandName().c_str()),
  270.                                 String::New(jsonData.c_str()) };
  271.  
  272.     Handle<Value> result = myFunctionHandleMessage->Call(myFunctionHandleMessage, argc, argv); // argc and argv are your standard arguments to a function
  273. }
  274.  
  275. unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
  276. {
  277.     IntervalThread intervalThread(timeout);
  278.  
  279.     myIntervalThreads[intervalThread.getId()] = intervalThread;
  280.     myIntervalThreads[intervalThread.getId()].start();
  281.  
  282.     return intervalThread.getId();
  283. }
  284.  
  285. bool VirtualMachine::stopIntervalThread(unsigned int id)
  286. {
  287.     if (myIntervalThreads.find(id) != myIntervalThreads.end())
  288.     {
  289.         myIntervalThreads.erase(id);
  290.         return true;
  291.     }
  292.  
  293.     return false;
  294. }
  295.  
  296. unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
  297. {
  298.     SocketThread *socketThread = new SocketThread(address, port, reconnectTimeout);
  299.     mySocketThreads[socketThread->getId()] = socketThread;
  300.     mySocketThreads[socketThread->getId()]->start();
  301.  
  302.     return socketThread->getId();
  303. }
  304.  
  305. bool VirtualMachine::stopSocketThread(unsigned int id)
  306. {
  307.    
  308.  
  309.     if (mySocketThreads.find(id) != mySocketThreads.end())
  310.     {
  311.         //mySocketThreads[id]->stop();
  312.         delete mySocketThreads[id];
  313.  
  314.         mySocketThreads.erase(id);
  315.         return true;
  316.     }
  317.  
  318.     return false;
  319. }
  320.  
  321. void VirtualMachine::sendToSocketThread(unsigned int id, string data)
  322. {
  323.     if (mySocketThreads.find(id) != mySocketThreads.end())
  324.     {
  325.         mySocketThreads[id]->send(data);
  326.     }
  327. }
  328.  
  329. bool VirtualMachine::runExpression(string expression)
  330. {
  331.     SyslogStream &slog = SyslogStream::getInstance();
  332.  
  333.     string scriptName = "runExpression";
  334.  
  335.     Handle<String> source =  String::New(expression.c_str(), expression.length());
  336.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  337.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  338.  
  339.     //access global context within this scope
  340.     Context::Scope context_scope(myContext);
  341.     //exception handler
  342.     TryCatch try_catch;
  343.     //compile script to binary code - JIT
  344.     Handle<Script> script = Script::Compile(source, name);
  345.  
  346.     //check if we got problems on compilation
  347.     if (script.IsEmpty())
  348.     {
  349.         // Print errors that happened during compilation.
  350.         String::AsciiValue error(try_catch.Exception());
  351.         string sError = *error;
  352.         slog << "runExpression: Failed to compile script: " + sError + "\n";
  353.         slog << expression << "\n\n";
  354.         return false;
  355.     }
  356.     else
  357.     {
  358.         //no errors , let's continue
  359.         Handle<Value> result = script->Run();
  360.  
  361.         //check if execution ended with errors
  362.         if (result.IsEmpty())
  363.         {
  364.             // Print errors that happened during execution.
  365.             String::AsciiValue error(try_catch.Exception());
  366.             string sError = *error;
  367.             slog << "runExpression: Failed to run script: " + sError + "\n";
  368.             return false;
  369.         }
  370.     }
  371.  
  372.     return true;
  373. }
  374.  
  375. Handle<Value> VirtualMachine_log(const Arguments& args)
  376. {
  377.     SyslogStream &slog = SyslogStream::getInstance();
  378.  
  379.     String::AsciiValue str(args[0]);
  380.  
  381.     slog << *str;
  382.  
  383.     return Undefined();
  384. }
  385.  
  386. Handle<Value> VirtualMachine_sendCanMessage(const Arguments& args)
  387. {
  388.     //SyslogStream &slog = SyslogStream::getInstance();
  389.     CanNetManager &canMan = CanNetManager::getInstance();
  390.  
  391.     CanMessage canMessage;
  392.  
  393.     String::AsciiValue className(args[0]);
  394.     canMessage.setClassName(*className);
  395.     String::AsciiValue directionFlag(args[1]);
  396.     canMessage.setDirectionFlag(*directionFlag);
  397.     String::AsciiValue moduleName(args[2]);
  398.     canMessage.setModuleName(*moduleName);
  399.     canMessage.setModuleId(args[3]->Uint32Value());
  400.     String::AsciiValue commandName(args[4]);
  401.     canMessage.setCommandName(*commandName);
  402.  
  403.     String::AsciiValue dataString(args[5]);
  404.  
  405.     vector<string> parts = explode(",", trim(*dataString, ','));
  406.     map<string, CanVariable> data;
  407.  
  408.     for (int n = 0; n < parts.size(); n++)
  409.     {
  410.         vector<string> keyAndValue = explode(":", parts[n]);
  411.  
  412.         //string key = trim(keyAndValue[0], ' ');
  413.         //string value = trim(keyAndValue[1], ' ');
  414.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  415.     }
  416.  
  417.     canMessage.setData(data);
  418.    
  419.     canMan.sendMessage(canMessage);
  420.  
  421.     return Undefined();
  422. }
  423.  
  424. Handle<Value> VirtualMachine_sendCanNMTMessage(const Arguments& args)
  425. {
  426.     //SyslogStream &slog = SyslogStream::getInstance();
  427.     CanNetManager &canMan = CanNetManager::getInstance();
  428.  
  429.     CanMessage canMessage;
  430.  
  431.     String::AsciiValue className(args[0]);
  432.     canMessage.setClassName(*className);
  433.     String::AsciiValue commandName(args[1]);
  434.     canMessage.setCommandName(*commandName);
  435.  
  436.     String::AsciiValue dataString(args[2]);
  437.  
  438.     vector<string> parts = explode(",", trim(*dataString, ','));
  439.     map<string, CanVariable> data;
  440.  
  441.     for (int n = 0; n < parts.size(); n++)
  442.     {
  443.         vector<string> keyAndValue = explode(":", parts[n]);
  444.  
  445.         //string key = trim(keyAndValue[0], ' ');
  446.         //string value = trim(keyAndValue[1], ' ');
  447.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  448.     }
  449.  
  450.     canMessage.setData(data);
  451.  
  452.     canMan.sendMessage(canMessage);
  453.  
  454.     return Undefined();
  455. }
  456.  
  457. Handle<Value> VirtualMachine_loadScript(const Arguments& args)
  458. {
  459.     VirtualMachine &vm = VirtualMachine::getInstance();
  460.  
  461.     String::AsciiValue str(args[0]);
  462.  
  463.     return Boolean::New(vm.loadScript(*str));
  464. }
  465.  
  466. Handle<Value> VirtualMachine_startIntervalThread(const Arguments& args)
  467. {
  468.     VirtualMachine &vm = VirtualMachine::getInstance();
  469.  
  470.     unsigned int timeout = args[0]->Uint32Value();
  471.  
  472.     return Integer::New(vm.startIntervalThread(timeout));
  473. }
  474.  
  475. Handle<Value> VirtualMachine_stopIntervalThread(const Arguments& args)
  476. {
  477.     VirtualMachine &vm = VirtualMachine::getInstance();
  478.  
  479.     unsigned int id = args[0]->Uint32Value();
  480.  
  481.     return Boolean::New(vm.stopIntervalThread(id));
  482. }
  483.  
  484. Handle<Value> VirtualMachine_startSocketThread(const Arguments& args)
  485. {
  486.     VirtualMachine &vm = VirtualMachine::getInstance();
  487.  
  488.     String::AsciiValue address(args[0]);
  489.     int port = args[1]->Uint32Value();
  490.     unsigned int reconnectTimeout = args[2]->Uint32Value();
  491.  
  492.     return Integer::New(vm.startSocketThread(*address, port, reconnectTimeout));
  493. }
  494.  
  495. Handle<Value> VirtualMachine_stopSocketThread(const Arguments& args)
  496. {
  497.     VirtualMachine &vm = VirtualMachine::getInstance();
  498.  
  499.     unsigned int id = args[0]->Uint32Value();
  500.  
  501.     return Boolean::New(vm.stopSocketThread(id));
  502. }
  503.  
  504. Handle<Value> VirtualMachine_sendToSocketThread(const Arguments& args)
  505. {
  506.     VirtualMachine &vm = VirtualMachine::getInstance();
  507.  
  508.     unsigned int id = args[0]->Uint32Value();
  509.     String::AsciiValue data(args[1]);
  510.  
  511.     vm.sendToSocketThread(id, *data);
  512.  
  513.     return Undefined();
  514. }
  515.  
  516. Handle<Value> VirtualMachine_uint2hex(const Arguments& args)
  517. {
  518.     VirtualMachine &vm = VirtualMachine::getInstance();
  519.  
  520.     unsigned int id = args[0]->Uint32Value();
  521.     unsigned int length = args[1]->Uint32Value();
  522.     string hexId = uint2hex(id, length);
  523.  
  524.     return String::New(hexId.c_str());
  525. }
  526.  
  527.