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