Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Details | Last modification | View Log | SVN | RSS feed

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