Subversion Repositories HomeAutomation

Rev

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 "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
 
999 runge 53
    myCommandThread.stop();
54
 
997 runge 55
    ///FIXME: Verify that this works and does not cause segfaults
56
    for (map<int, SocketThread*>::iterator iter = mySocketThreads.begin(); iter != mySocketThreads.end(); iter++)
57
    {
999 runge 58
        iter->second->stop();
997 runge 59
        delete iter->second;
999 runge 60
        //mySocketThreads.erase(iter);
997 runge 61
    }
999 runge 62
 
63
    mySocketThreads.clear();
64
 
65
    for (map<int, IntervalThread*>::iterator iter = myIntervalThreads.begin(); iter != myIntervalThreads.end(); iter++)
66
    {
67
        iter->second->stop();
68
        delete iter->second;
69
        //myIntervalThreads.erase(iter);
70
    }
71
 
72
    myIntervalThreads.clear();
969 runge 73
}
74
 
75
void VirtualMachine::run()
76
{
77
    myGlobal = ObjectTemplate::New();
999 runge 78
    myGlobal->Set(String::New("_quit"), FunctionTemplate::New(VirtualMachine::_quit));
79
    myGlobal->Set(String::New("_print"), FunctionTemplate::New(VirtualMachine::_print));
80
    myGlobal->Set(String::New("log"), FunctionTemplate::New(VirtualMachine::_log));
81
    myGlobal->Set(String::New("sendCanMessage"), FunctionTemplate::New(VirtualMachine::_sendCanMessage));
82
    myGlobal->Set(String::New("sendCanNMTMessage"), FunctionTemplate::New(VirtualMachine::_sendCanNMTMessage));
83
    myGlobal->Set(String::New("loadScript"), FunctionTemplate::New(VirtualMachine::_loadScript));
84
    myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine::_startIntervalThread));
85
    myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine::_stopIntervalThread));
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));
1007 runge 89
    myGlobal->Set(String::New("loadDataStore"), FunctionTemplate::New(VirtualMachine::_loadDataStore));
1008 runge 90
    myGlobal->Set(String::New("getFileContents"), FunctionTemplate::New(VirtualMachine::_getFileContents));
1011 runge 91
    myGlobal->Set(String::New("uint2hex"), FunctionTemplate::New(VirtualMachine::_uint2hex));
92
    myGlobal->Set(String::New("hex2bin"), FunctionTemplate::New(VirtualMachine::_hex2bin));
93
    myGlobal->Set(String::New("bin2hex"), FunctionTemplate::New(VirtualMachine::_bin2hex));
94
    myGlobal->Set(String::New("bin2float"), FunctionTemplate::New(VirtualMachine::_bin2float));
95
    myGlobal->Set(String::New("float2bin"), FunctionTemplate::New(VirtualMachine::_float2bin));
96
    myGlobal->Set(String::New("bin2uint"), FunctionTemplate::New(VirtualMachine::_bin2uint));
97
    myGlobal->Set(String::New("uint2bin"), FunctionTemplate::New(VirtualMachine::_uint2bin));
98
    myGlobal->Set(String::New("hex2uint"), FunctionTemplate::New(VirtualMachine::_hex2uint));
969 runge 99
    myContext = Context::New(NULL, myGlobal);
100
 
101
 
997 runge 102
    if (loadScript("System/Base.js"))
103
    {
104
        loadScript("System/Startup.js");
969 runge 105
 
997 runge 106
        loadScript("Autostart.js");
107
 
108
        Context::Scope contextScope(myContext);
109
 
110
        myFunctionStartup = Handle<Function>::Cast(myContext->Global()->Get(String::New("startup")));
969 runge 111
    }
112
    else
113
    {
997 runge 114
        ///FIXME: We should probably exit the application here
115
        return;
969 runge 116
    }
117
 
118
    const int argc = 0;
119
    Handle<Value> argv[argc] = { };
997 runge 120
    Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv);
969 runge 121
 
999 runge 122
 
123
    string commandPort = Settings::get("CommandPort");
124
    if (commandPort != "")
125
    {
126
        myCommandThread.setSettings(stoi(commandPort), "Command console");
127
        myCommandThread.start();
128
    }
129
    else
130
    {
1024 runge 131
        Logger &log = Logger::getInstance();
132
        log.add("CommandPort is not defined, can not start Command console socket\n");
999 runge 133
    }
134
 
135
 
969 runge 136
    mySemaphore.lock();
137
 
997 runge 138
    while (true)
969 runge 139
    {
140
        while (myExpressions.size() > 0)
141
        {
999 runge 142
            runExpression(myExpressions.pop());
969 runge 143
        }
144
 
145
        mySemaphore.wait();
146
    }
147
 
148
    mySemaphore.unlock();
149
}
150
 
999 runge 151
void VirtualMachine::queueExpression(Expression expression)
969 runge 152
{
999 runge 153
    myExpressions.push(expression);
969 runge 154
    mySemaphore.broadcast();
155
}
156
 
999 runge 157
string VirtualMachine::formatException(TryCatch* tryCatch)
969 runge 158
{
999 runge 159
    string result;
160
 
161
    HandleScope handleScope;
162
    String::Utf8Value exception(tryCatch->Exception());
163
    Handle<v8::Message> message = tryCatch->Message();
164
 
165
    string strException = *exception;
166
 
167
    if (message.IsEmpty())
168
    {
169
        result += strException + "\n";
170
    }
171
    else
172
    {
173
        String::Utf8Value filename(message->GetScriptResourceName());
174
        string strFilename = *filename;
175
 
176
        result += strFilename + ":" + itos(message->GetLineNumber()) + ": " + strException + "\n";
177
 
178
        String::Utf8Value sourceline(message->GetSourceLine());
179
        string strSourceline = *sourceline;
180
 
181
        result += strSourceline + "\n";
182
 
183
        string underline = rpad("", message->GetStartColumn(), ' ');
184
        underline = rpad(underline, message->GetEndColumn(), '^');
185
 
186
        result += underline + "\n";
187
    }
188
 
189
    return result;
969 runge 190
}
191
 
1007 runge 192
bool VirtualMachine::loadDataStore(string storeName)
193
{
1024 runge 194
    Logger &log = Logger::getInstance();
1007 runge 195
 
196
    string basePath = Settings::get("BasePath") + "Services/DataStores/";
197
    string scriptFileName = basePath + storeName + ".js";
198
 
199
    if (!file_exists(scriptFileName))
200
    {
1024 runge 201
        log.add("Failed to load datastore " + scriptFileName + ", file does not exist.\n");
1007 runge 202
        return false;
203
    }
204
 
205
    string scriptSource = file_get_contents(scriptFileName);
206
 
207
    scriptSource = "DataStore.addStore('" + storeName + "', " + str_replace("\n", "", scriptSource) + ");";
208
 
209
    Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
210
    Handle<String> name = String::New(scriptFileName.c_str(), scriptFileName.length());
211
 
212
    Context::Scope contextScope(myContext);
213
 
214
    TryCatch tryCatch;
215
 
216
    Handle<Script> script = Script::Compile(source, name);
217
 
218
    if (script.IsEmpty())
219
    {
1024 runge 220
        log.add(formatException(&tryCatch));
1007 runge 221
        return false;
222
    }
223
    else
224
    {
225
        Handle<Value> result = script->Run();
226
 
227
        if (result.IsEmpty())
228
        {
1024 runge 229
            log.add(formatException(&tryCatch));
1007 runge 230
            return false;
231
        }
232
 
1024 runge 233
        log.add("Loaded datastore " + storeName + "\n");
1007 runge 234
    }
235
 
236
    return true;
237
}
238
 
969 runge 239
bool VirtualMachine::loadScript(string scriptName)
240
{
1024 runge 241
    Logger &log = Logger::getInstance();
969 runge 242
 
981 runge 243
    string basePath = Settings::get("BasePath") + "Services/";
969 runge 244
    string scriptFileName = basePath + scriptName;
245
 
246
    if (!file_exists(scriptFileName))
247
    {
1024 runge 248
        log.add("Failed to load " + scriptFileName + ", file does not exist.\n");
969 runge 249
        return false;
250
    }
251
 
252
    string scriptSource = file_get_contents(scriptFileName);
253
 
254
    Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
255
    Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
256
 
997 runge 257
    Context::Scope contextScope(myContext);
258
 
995 runge 259
    TryCatch tryCatch;
997 runge 260
 
969 runge 261
    Handle<Script> script = Script::Compile(source, name);
262
 
263
    if (script.IsEmpty())
264
    {
1024 runge 265
        log.addToSyslog(formatException(&tryCatch));
969 runge 266
        return false;
267
    }
268
    else
269
    {
270
        Handle<Value> result = script->Run();
271
 
272
        if (result.IsEmpty())
273
        {
1024 runge 274
            log.addToSyslog(formatException(&tryCatch));
969 runge 275
            return false;
276
        }
977 runge 277
 
1024 runge 278
        log.add("Loaded " + scriptName + "\n");
969 runge 279
    }
280
 
281
    return true;
282
}
283
 
971 runge 284
unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
969 runge 285
{
999 runge 286
    IntervalThread *intervalThread = new IntervalThread(timeout);
969 runge 287
 
999 runge 288
    myIntervalThreads[intervalThread->getId()] = intervalThread;
289
    myIntervalThreads[intervalThread->getId()]->start();
969 runge 290
 
999 runge 291
    return intervalThread->getId();
969 runge 292
}
293
 
971 runge 294
bool VirtualMachine::stopIntervalThread(unsigned int id)
969 runge 295
{
971 runge 296
    if (myIntervalThreads.find(id) != myIntervalThreads.end())
969 runge 297
    {
999 runge 298
        delete myIntervalThreads[id];
971 runge 299
        myIntervalThreads.erase(id);
969 runge 300
        return true;
301
    }
302
 
303
    return false;
304
}
305
 
976 runge 306
unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
307
{
983 runge 308
    SocketThread *socketThread = new SocketThread(address, port, reconnectTimeout);
309
    mySocketThreads[socketThread->getId()] = socketThread;
310
    mySocketThreads[socketThread->getId()]->start();
976 runge 311
 
983 runge 312
    return socketThread->getId();
976 runge 313
}
314
 
315
bool VirtualMachine::stopSocketThread(unsigned int id)
316
{
317
    if (mySocketThreads.find(id) != mySocketThreads.end())
318
    {
983 runge 319
        delete mySocketThreads[id];
976 runge 320
        mySocketThreads.erase(id);
321
        return true;
322
    }
323
 
324
    return false;
325
}
326
 
327
void VirtualMachine::sendToSocketThread(unsigned int id, string data)
328
{
329
    if (mySocketThreads.find(id) != mySocketThreads.end())
330
    {
983 runge 331
        mySocketThreads[id]->send(data);
976 runge 332
    }
333
}
334
 
999 runge 335
void VirtualMachine::disconnectCommandClient(unsigned int id)
969 runge 336
{
999 runge 337
    myCommandThread.disconnectClient(id);
338
}
339
 
340
void VirtualMachine::sendToCommandClient(unsigned int id, string data)
341
{
342
    myCommandThread.sendTo(id, data);
343
}
344
 
345
void VirtualMachine::print(unsigned int id, string data)
346
{
347
    if (id == 0)
348
    {
1024 runge 349
        Logger &log = Logger::getInstance();
350
        log.add(data);
999 runge 351
    }
352
    else
353
    {
354
        VirtualMachine &vm = VirtualMachine::getInstance();
355
        vm.sendToCommandClient(id, data);
356
    }
357
}
358
 
359
bool VirtualMachine::runExpression(Expression expression)
360
{
969 runge 361
    string scriptName = "runExpression";
362
 
999 runge 363
    string scriptData = expression.getScript();
364
 
1008 runge 365
    scriptData = "setClientId(" + itos(expression.getTargetId()) + ");\n" + scriptData + "\n";
999 runge 366
 
367
    Handle<String> source =  String::New(scriptData.c_str(), scriptData.length());
969 runge 368
    Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
369
 
997 runge 370
    Context::Scope contextScope(myContext);
371
 
995 runge 372
    TryCatch tryCatch;
997 runge 373
 
969 runge 374
    Handle<Script> script = Script::Compile(source, name);
375
 
376
    if (script.IsEmpty())
377
    {
999 runge 378
        print(expression.getTargetId(), formatException(&tryCatch));
969 runge 379
        return false;
380
    }
381
    else
382
    {
383
        Handle<Value> result = script->Run();
384
 
385
        if (result.IsEmpty())
386
        {
999 runge 387
            print(expression.getTargetId(), formatException(&tryCatch));
969 runge 388
            return false;
389
        }
999 runge 390
        else if (expression.getTargetId() != 0)
391
        {
392
             String::AsciiValue ascii(result);
393
             string resultString = *ascii;
394
 
395
             if (resultString != "undefined")
396
             {
397
                print(expression.getTargetId(), resultString + "\n");
398
             }
399
        }
969 runge 400
    }
401
 
402
    return true;
403
}
404
 
999 runge 405
 
406
Handle<Value> VirtualMachine::_quit(const Arguments& args)
995 runge 407
{
999 runge 408
    VirtualMachine &vm = VirtualMachine::getInstance();
995 runge 409
 
999 runge 410
    vm.disconnectCommandClient(args[0]->Uint32Value());
995 runge 411
 
999 runge 412
    return Undefined();
413
}
995 runge 414
 
999 runge 415
Handle<Value> VirtualMachine::_log(const Arguments& args)
416
{
1024 runge 417
    Logger &log = Logger::getInstance();
995 runge 418
 
999 runge 419
    String::AsciiValue str(args[0]);
995 runge 420
 
1024 runge 421
    log.add(*str);
995 runge 422
 
999 runge 423
    return Undefined();
995 runge 424
}
425
 
999 runge 426
Handle<Value> VirtualMachine::_print(const Arguments& args)
969 runge 427
{
999 runge 428
    VirtualMachine &vm = VirtualMachine::getInstance();
969 runge 429
 
999 runge 430
    String::AsciiValue str(args[1]);
969 runge 431
 
999 runge 432
    vm.print(args[0]->Uint32Value(), *str);
969 runge 433
 
434
    return Undefined();
435
}
436
 
999 runge 437
Handle<Value> VirtualMachine::_sendCanMessage(const Arguments& args)
969 runge 438
{
439
    CanNetManager &canMan = CanNetManager::getInstance();
440
 
441
    CanMessage canMessage;
442
 
443
    String::AsciiValue className(args[0]);
444
    canMessage.setClassName(*className);
445
    String::AsciiValue directionFlag(args[1]);
446
    canMessage.setDirectionFlag(*directionFlag);
447
    String::AsciiValue moduleName(args[2]);
448
    canMessage.setModuleName(*moduleName);
449
    canMessage.setModuleId(args[3]->Uint32Value());
450
    String::AsciiValue commandName(args[4]);
451
    canMessage.setCommandName(*commandName);
452
 
453
    String::AsciiValue dataString(args[5]);
454
 
455
    vector<string> parts = explode(",", trim(*dataString, ','));
456
    map<string, CanVariable> data;
457
 
458
    for (int n = 0; n < parts.size(); n++)
459
    {
460
        vector<string> keyAndValue = explode(":", parts[n]);
461
 
462
        data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
463
    }
464
 
465
    canMessage.setData(data);
466
 
467
    canMan.sendMessage(canMessage);
468
 
469
    return Undefined();
470
}
471
 
999 runge 472
Handle<Value> VirtualMachine::_sendCanNMTMessage(const Arguments& args)
986 runge 473
{
474
    CanNetManager &canMan = CanNetManager::getInstance();
475
 
476
    CanMessage canMessage;
477
 
478
    String::AsciiValue className(args[0]);
479
    canMessage.setClassName(*className);
480
    String::AsciiValue commandName(args[1]);
481
    canMessage.setCommandName(*commandName);
482
 
483
    String::AsciiValue dataString(args[2]);
484
 
485
    vector<string> parts = explode(",", trim(*dataString, ','));
486
    map<string, CanVariable> data;
487
 
488
    for (int n = 0; n < parts.size(); n++)
489
    {
490
        vector<string> keyAndValue = explode(":", parts[n]);
491
 
492
        data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
493
    }
494
 
495
    canMessage.setData(data);
496
 
497
    canMan.sendMessage(canMessage);
498
 
499
    return Undefined();
500
}
501
 
999 runge 502
Handle<Value> VirtualMachine::_loadScript(const Arguments& args)
969 runge 503
{
504
    VirtualMachine &vm = VirtualMachine::getInstance();
505
 
506
    String::AsciiValue str(args[0]);
507
 
508
    return Boolean::New(vm.loadScript(*str));
509
}
510
 
1007 runge 511
Handle<Value> VirtualMachine::_loadDataStore(const Arguments& args)
512
{
513
    VirtualMachine &vm = VirtualMachine::getInstance();
514
 
515
    String::AsciiValue str(args[0]);
516
 
517
    return Boolean::New(vm.loadDataStore(*str));
518
}
519
 
999 runge 520
Handle<Value> VirtualMachine::_startIntervalThread(const Arguments& args)
969 runge 521
{
522
    VirtualMachine &vm = VirtualMachine::getInstance();
999 runge 523
    return Integer::New(vm.startIntervalThread(args[0]->Uint32Value()));
969 runge 524
}
525
 
999 runge 526
Handle<Value> VirtualMachine::_stopIntervalThread(const Arguments& args)
969 runge 527
{
528
    VirtualMachine &vm = VirtualMachine::getInstance();
999 runge 529
    return Boolean::New(vm.stopIntervalThread(args[0]->Uint32Value()));
969 runge 530
}
976 runge 531
 
999 runge 532
Handle<Value> VirtualMachine::_startSocketThread(const Arguments& args)
976 runge 533
{
534
    VirtualMachine &vm = VirtualMachine::getInstance();
535
 
536
    String::AsciiValue address(args[0]);
537
 
999 runge 538
    return Integer::New(vm.startSocketThread(*address, args[1]->Uint32Value(), args[2]->Uint32Value()));
976 runge 539
}
540
 
999 runge 541
Handle<Value> VirtualMachine::_stopSocketThread(const Arguments& args)
976 runge 542
{
543
    VirtualMachine &vm = VirtualMachine::getInstance();
544
 
999 runge 545
    return Boolean::New(vm.stopSocketThread(args[0]->Uint32Value()));
976 runge 546
}
547
 
999 runge 548
Handle<Value> VirtualMachine::_sendToSocketThread(const Arguments& args)
976 runge 549
{
550
    VirtualMachine &vm = VirtualMachine::getInstance();
551
 
552
    String::AsciiValue data(args[1]);
553
 
999 runge 554
    vm.sendToSocketThread(args[0]->Uint32Value(), *data);
976 runge 555
 
556
    return Undefined();
557
}
558
 
1008 runge 559
Handle<Value> VirtualMachine::_getFileContents(const Arguments& args)
560
{
561
    String::AsciiValue filename(args[0]);
562
 
563
    if (!file_exists(*filename))
564
    {
565
        return Undefined();
566
    }
567
 
568
    string content = file_get_contents(*filename);
569
 
570
    return String::New(content.c_str());
571
}
572
 
1010 runge 573
Handle<Value> VirtualMachine::_uint2hex(const Arguments& args)
574
{
575
    string hex = uint2hex(args[0]->Uint32Value(), args[1]->Uint32Value());
576
    return String::New(hex.c_str());
577
}
578
 
579
Handle<Value> VirtualMachine::_hex2bin(const Arguments& args)
580
{
581
    String::AsciiValue hex(args[0]);
582
    string bin = hex2bin(*hex);
583
    return String::New(bin.c_str());
584
}
585
 
586
Handle<Value> VirtualMachine::_bin2hex(const Arguments& args)
587
{
588
    String::AsciiValue bin(args[0]);
589
    string hex = bin2hex(*bin);
590
    return String::New(hex.c_str());
591
}
592
 
593
Handle<Value> VirtualMachine::_bin2float(const Arguments& args)
594
{
595
    String::AsciiValue bin(args[0]);
596
    float f = bin2float(*bin);
597
    return Number::New(f);
598
}
599
 
600
Handle<Value> VirtualMachine::_float2bin(const Arguments& args)
601
{
602
    string bin = float2bin(args[0]->NumberValue(), args[1]->Uint32Value());
603
    return String::New(bin.c_str());
604
}
605
 
606
Handle<Value> VirtualMachine::_bin2uint(const Arguments& args)
607
{
608
    String::AsciiValue bin(args[0]);
609
    unsigned int num = bin2uint(*bin);
1012 runge 610
    return Number::New(num);
1010 runge 611
}
612
 
613
Handle<Value> VirtualMachine::_uint2bin(const Arguments& args)
614
{
615
    string bin = uint2bin(args[0]->Uint32Value(), args[1]->Uint32Value());
616
    return String::New(bin.c_str());
617
}
618
 
1011 runge 619
Handle<Value> VirtualMachine::_hex2uint(const Arguments& args)
620
{
621
    String::AsciiValue hex(args[0]);
622
    unsigned int num = hex2uint(*hex);
1012 runge 623
    return Number::New(num);
1011 runge 624
}