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));
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
	{
131
		SyslogStream &slog = SyslogStream::getInstance();
132
		slog << "CommandPort is not defined, can not start Command console socket\n";
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
{
194
	SyslogStream &slog = SyslogStream::getInstance();
195
 
196
	string basePath = Settings::get("BasePath") + "Services/DataStores/";
197
	string scriptFileName = basePath + storeName + ".js";
198
 
199
	if (!file_exists(scriptFileName))
200
	{
201
		slog << "Failed to load datastore " + scriptFileName + ", file does not exist.\n";
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
	{
220
		slog << formatException(&tryCatch);
221
		return false;
222
	}
223
	else
224
	{
225
		Handle<Value> result = script->Run();
226
 
227
		if (result.IsEmpty())
228
		{
229
			slog << formatException(&tryCatch);
230
			return false;
231
		}
232
 
233
		slog << "Loaded datastore " + storeName + "\n";
234
	}
235
 
236
	return true;
237
}
238
 
969 runge 239
bool VirtualMachine::loadScript(string scriptName)
240
{
241
	SyslogStream &slog = SyslogStream::getInstance();
242
 
981 runge 243
	string basePath = Settings::get("BasePath") + "Services/";
969 runge 244
	string scriptFileName = basePath + scriptName;
245
 
246
	if (!file_exists(scriptFileName))
247
	{
997 runge 248
		slog << "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
	{
999 runge 265
		slog << formatException(&tryCatch);
969 runge 266
		return false;
267
	}
268
	else
269
	{
270
		Handle<Value> result = script->Run();
271
 
272
		if (result.IsEmpty())
273
		{
999 runge 274
			slog << formatException(&tryCatch);
969 runge 275
			return false;
276
		}
977 runge 277
 
278
		slog << "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
	{
349
		SyslogStream &slog = SyslogStream::getInstance();
350
		slog << data;
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
{
417
	SyslogStream &slog = SyslogStream::getInstance();
995 runge 418
 
999 runge 419
	String::AsciiValue str(args[0]);
995 runge 420
 
999 runge 421
	slog << *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
}