Subversion Repositories HomeAutomation

Rev

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