Subversion Repositories HomeAutomation

Rev

Rev 995 | Rev 999 | 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
{
47
}
48
 
49
VirtualMachine::~VirtualMachine()
50
{
981 runge 51
    stop();
997 runge 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
    }
969 runge 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));
986 runge 66
    myGlobal->Set(String::New("sendCanNMTMessage"), FunctionTemplate::New(VirtualMachine_sendCanNMTMessage));
969 runge 67
    myGlobal->Set(String::New("loadScript"), FunctionTemplate::New(VirtualMachine_loadScript));
971 runge 68
    myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine_startIntervalThread));
69
    myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine_stopIntervalThread));
976 runge 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));
981 runge 73
    myGlobal->Set(String::New("uint2hex"), FunctionTemplate::New(VirtualMachine_uint2hex));
969 runge 74
    myContext = Context::New(NULL, myGlobal);
75
 
76
 
997 runge 77
    if (loadScript("System/Base.js"))
78
    {
79
        loadScript("System/Startup.js");
969 runge 80
 
997 runge 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")));
969 runge 89
    }
90
    else
91
    {
997 runge 92
        ///FIXME: We should probably exit the application here
93
        return;
969 runge 94
    }
95
 
96
    const int argc = 0;
97
    Handle<Value> argv[argc] = { };
997 runge 98
    Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv);
969 runge 99
 
100
    mySemaphore.lock();
101
 
997 runge 102
    string expression;
103
    CanMessage canMessage;
104
 
105
    while (true)
969 runge 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
 
986 runge 117
            if (canMessage.getClassName() == "nmt")
969 runge 118
            {
997 runge 119
                expression = "handleNMTMessage(";
120
                expression += "'" + canMessage.getClassName() + "', ";
121
                expression += "'" + canMessage.getCommandName() + "', ";
122
                expression += canMessage.getJSONData();
123
                expression += ");";
124
                runExpression(expression);
969 runge 125
            }
126
            else
127
            {
997 runge 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);
969 runge 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
 
981 runge 162
    string basePath = Settings::get("BasePath") + "Services/";
969 runge 163
    string scriptFileName = basePath + scriptName;
164
 
165
    if (!file_exists(scriptFileName))
166
    {
997 runge 167
        slog << "Failed to load " + scriptFileName + ", file does not exist.\n";
969 runge 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
 
997 runge 176
    Context::Scope contextScope(myContext);
177
 
995 runge 178
    TryCatch tryCatch;
997 runge 179
 
969 runge 180
    Handle<Script> script = Script::Compile(source, name);
181
 
182
    if (script.IsEmpty())
183
    {
995 runge 184
        printException(&tryCatch);
969 runge 185
        return false;
186
    }
187
    else
188
    {
189
        Handle<Value> result = script->Run();
190
 
191
        if (result.IsEmpty())
192
        {
995 runge 193
            printException(&tryCatch);
969 runge 194
            return false;
195
        }
977 runge 196
 
197
        slog << "Loaded " + scriptName + "\n";
969 runge 198
    }
199
 
200
    return true;
201
}
202
 
986 runge 203
void VirtualMachine::callHandleNMTMessage(CanMessage canMessage)
969 runge 204
{
986 runge 205
    const int argc = 3;
969 runge 206
 
986 runge 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
969 runge 214
}
215
 
216
void VirtualMachine::callHandleMessage(CanMessage canMessage)
217
{
218
    const int argc = 6;
981 runge 219
 
220
    string jsonData = canMessage.getJSONData();
221
 
969 runge 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()),
981 runge 227
                                String::New(jsonData.c_str()) };
969 runge 228
 
229
    Handle<Value> result = myFunctionHandleMessage->Call(myFunctionHandleMessage, argc, argv); // argc and argv are your standard arguments to a function
230
}
231
 
971 runge 232
unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
969 runge 233
{
971 runge 234
    IntervalThread intervalThread(timeout);
969 runge 235
 
971 runge 236
    myIntervalThreads[intervalThread.getId()] = intervalThread;
237
    myIntervalThreads[intervalThread.getId()].start();
969 runge 238
 
971 runge 239
    return intervalThread.getId();
969 runge 240
}
241
 
971 runge 242
bool VirtualMachine::stopIntervalThread(unsigned int id)
969 runge 243
{
971 runge 244
    if (myIntervalThreads.find(id) != myIntervalThreads.end())
969 runge 245
    {
971 runge 246
        myIntervalThreads.erase(id);
969 runge 247
        return true;
248
    }
249
 
250
    return false;
251
}
252
 
976 runge 253
unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
254
{
983 runge 255
    SocketThread *socketThread = new SocketThread(address, port, reconnectTimeout);
256
    mySocketThreads[socketThread->getId()] = socketThread;
257
    mySocketThreads[socketThread->getId()]->start();
976 runge 258
 
983 runge 259
    return socketThread->getId();
976 runge 260
}
261
 
262
bool VirtualMachine::stopSocketThread(unsigned int id)
263
{
264
    if (mySocketThreads.find(id) != mySocketThreads.end())
265
    {
983 runge 266
        delete mySocketThreads[id];
267
 
976 runge 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
    {
983 runge 279
        mySocketThreads[id]->send(data);
976 runge 280
    }
281
}
282
 
969 runge 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
 
997 runge 290
    Context::Scope contextScope(myContext);
291
 
995 runge 292
    TryCatch tryCatch;
997 runge 293
 
969 runge 294
    Handle<Script> script = Script::Compile(source, name);
295
 
296
    if (script.IsEmpty())
297
    {
995 runge 298
        printException(&tryCatch);
969 runge 299
        return false;
300
    }
301
    else
302
    {
303
        Handle<Value> result = script->Run();
304
 
305
        if (result.IsEmpty())
306
        {
995 runge 307
            printException(&tryCatch);
969 runge 308
            return false;
309
        }
310
    }
311
 
312
    return true;
313
}
314
 
995 runge 315
void VirtualMachine::printException(TryCatch* tryCatch)
316
{
317
    SyslogStream &slog = SyslogStream::getInstance();
318
 
997 runge 319
    HandleScope handleScope;
995 runge 320
    String::Utf8Value exception(tryCatch->Exception());
321
    Handle<v8::Message> message = tryCatch->Message();
322
 
323
    string strException = *exception;
324
 
325
    if (message.IsEmpty())
326
    {
997 runge 327
        slog << strException + "\n\n";
995 runge 328
    }
329
    else
330
    {
331
        String::Utf8Value filename(message->GetScriptResourceName());
332
        string strFilename = *filename;
333
 
997 runge 334
        slog << strFilename + ":" + itos(message->GetLineNumber()) + ": " + strException + "\n";
995 runge 335
 
336
        String::Utf8Value sourceline(message->GetSourceLine());
337
        string strSourceline = *sourceline;
338
 
339
        slog << strSourceline + "\n";
340
 
997 runge 341
        string underline = rpad("", message->GetStartColumn(), ' ');
342
        underline = rpad(underline, message->GetEndColumn(), '^');
995 runge 343
 
997 runge 344
        slog << underline + "\n\n";
995 runge 345
    }
346
}
347
 
348
 
969 runge 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
 
986 runge 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
 
969 runge 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
 
971 runge 434
Handle<Value> VirtualMachine_startIntervalThread(const Arguments& args)
969 runge 435
{
436
    VirtualMachine &vm = VirtualMachine::getInstance();
437
 
971 runge 438
    unsigned int timeout = args[0]->Uint32Value();
969 runge 439
 
971 runge 440
    return Integer::New(vm.startIntervalThread(timeout));
969 runge 441
}
442
 
971 runge 443
Handle<Value> VirtualMachine_stopIntervalThread(const Arguments& args)
969 runge 444
{
445
    VirtualMachine &vm = VirtualMachine::getInstance();
446
 
973 runge 447
    unsigned int id = args[0]->Uint32Value();
969 runge 448
 
976 runge 449
    return Boolean::New(vm.stopIntervalThread(id));
969 runge 450
}
976 runge 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
 
981 runge 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