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