Subversion Repositories HomeAutomation

Rev

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