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