Subversion Repositories HomeAutomation

Rev

Rev 983 | Rev 995 | Go to most recent revision | Details | Compare with Previous | 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 "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
{
981 runge 47
    Thread<VirtualMachine>();
969 runge 48
}
49
 
50
VirtualMachine::~VirtualMachine()
51
{
981 runge 52
    stop();
969 runge 53
}
54
 
55
void VirtualMachine::run()
56
{
57
    SyslogStream &slog = SyslogStream::getInstance();
58
 
971 runge 59
    string basePath = Settings::get("BasePath") + "Services/";
969 runge 60
    string scriptName = "Base.js";
971 runge 61
    string scriptFileName = basePath + "System/" + scriptName;
969 runge 62
 
63
    if (!file_exists(scriptFileName))
64
    {
976 runge 65
        slog << "Failed to load :" + scriptFileName + "\n";
969 runge 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));
986 runge 80
    myGlobal->Set(String::New("sendCanNMTMessage"), FunctionTemplate::New(VirtualMachine_sendCanNMTMessage));
969 runge 81
    myGlobal->Set(String::New("loadScript"), FunctionTemplate::New(VirtualMachine_loadScript));
971 runge 82
    myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine_startIntervalThread));
83
    myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine_stopIntervalThread));
976 runge 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));
981 runge 87
    myGlobal->Set(String::New("uint2hex"), FunctionTemplate::New(VirtualMachine_uint2hex));
969 runge 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());
976 runge 106
        string sError = *error;
107
        slog << "Failed to compile script: " + sError + "\n";
969 runge 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());
976 runge 119
            string sError = *error;
120
            slog << "Constructor: Failed to run script: " << sError << "\n";
969 runge 121
        }
122
        else
123
        {
124
            loadScript("System/Startup.js");
125
 
970 runge 126
            if (file_exists(basePath + "Autostart.js"))
127
            {
128
                loadScript("Autostart.js");
129
            }
130
 
986 runge 131
            myFunctionHandleNMTMessage = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleNMTMessage")));
969 runge 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
 
986 runge 162
            if (canMessage.getClassName() == "nmt")
969 runge 163
            {
986 runge 164
                callHandleNMTMessage(canMessage);
969 runge 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
 
981 runge 194
    string basePath = Settings::get("BasePath") + "Services/";
969 runge 195
    string scriptFileName = basePath + scriptName;
196
 
197
    if (!file_exists(scriptFileName))
198
    {
981 runge 199
        slog << "Failed to load " + scriptFileName + "\n";
969 runge 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());
976 runge 221
        string sError = *error;
222
        slog << "loadScript: Failed to compile script: " + sError + "\n";
969 runge 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());
976 runge 235
            string sError = *error;
236
            slog << "loadScript: Failed to run script: " + sError + "\n";
969 runge 237
            return false;
238
        }
977 runge 239
 
240
        slog << "Loaded " + scriptName + "\n";
969 runge 241
    }
242
 
243
    return true;
244
}
245
 
986 runge 246
void VirtualMachine::callHandleNMTMessage(CanMessage canMessage)
969 runge 247
{
986 runge 248
    const int argc = 3;
969 runge 249
 
986 runge 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
969 runge 257
}
258
 
259
void VirtualMachine::callHandleMessage(CanMessage canMessage)
260
{
261
    const int argc = 6;
981 runge 262
 
263
    string jsonData = canMessage.getJSONData();
264
 
969 runge 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()),
981 runge 270
                                String::New(jsonData.c_str()) };
969 runge 271
 
272
    Handle<Value> result = myFunctionHandleMessage->Call(myFunctionHandleMessage, argc, argv); // argc and argv are your standard arguments to a function
273
}
274
 
971 runge 275
unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
969 runge 276
{
971 runge 277
    IntervalThread intervalThread(timeout);
969 runge 278
 
971 runge 279
    myIntervalThreads[intervalThread.getId()] = intervalThread;
280
    myIntervalThreads[intervalThread.getId()].start();
969 runge 281
 
971 runge 282
    return intervalThread.getId();
969 runge 283
}
284
 
971 runge 285
bool VirtualMachine::stopIntervalThread(unsigned int id)
969 runge 286
{
971 runge 287
    if (myIntervalThreads.find(id) != myIntervalThreads.end())
969 runge 288
    {
971 runge 289
        myIntervalThreads.erase(id);
969 runge 290
        return true;
291
    }
292
 
293
    return false;
294
}
295
 
976 runge 296
unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
297
{
983 runge 298
    SocketThread *socketThread = new SocketThread(address, port, reconnectTimeout);
299
    mySocketThreads[socketThread->getId()] = socketThread;
300
    mySocketThreads[socketThread->getId()]->start();
976 runge 301
 
983 runge 302
    return socketThread->getId();
976 runge 303
}
304
 
305
bool VirtualMachine::stopSocketThread(unsigned int id)
306
{
983 runge 307
 
308
 
976 runge 309
    if (mySocketThreads.find(id) != mySocketThreads.end())
310
    {
983 runge 311
        //mySocketThreads[id]->stop();
312
        delete mySocketThreads[id];
313
 
976 runge 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
    {
983 runge 325
        mySocketThreads[id]->send(data);
976 runge 326
    }
327
}
328
 
969 runge 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());
976 runge 351
        string sError = *error;
352
        slog << "runExpression: Failed to compile script: " + sError + "\n";
353
        slog << expression << "\n\n";
969 runge 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());
976 runge 366
            string sError = *error;
367
            slog << "runExpression: Failed to run script: " + sError + "\n";
969 runge 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
{
976 runge 388
    //SyslogStream &slog = SyslogStream::getInstance();
969 runge 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
 
986 runge 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
 
969 runge 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
 
971 runge 466
Handle<Value> VirtualMachine_startIntervalThread(const Arguments& args)
969 runge 467
{
468
    VirtualMachine &vm = VirtualMachine::getInstance();
469
 
971 runge 470
    unsigned int timeout = args[0]->Uint32Value();
969 runge 471
 
971 runge 472
    return Integer::New(vm.startIntervalThread(timeout));
969 runge 473
}
474
 
971 runge 475
Handle<Value> VirtualMachine_stopIntervalThread(const Arguments& args)
969 runge 476
{
477
    VirtualMachine &vm = VirtualMachine::getInstance();
478
 
973 runge 479
    unsigned int id = args[0]->Uint32Value();
969 runge 480
 
976 runge 481
    return Boolean::New(vm.stopIntervalThread(id));
969 runge 482
}
976 runge 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
 
981 runge 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