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
{
981 runge 47
	Thread<VirtualMachine>();
969 runge 48
}
49
 
50
VirtualMachine::~VirtualMachine()
51
{
981 runge 52
	stop();
969 runge 53
}
54
 
55
void VirtualMachine::run()
56
{
57
	SyslogStream &slog = SyslogStream::getInstance();
58
 
971 runge 59
	string basePath = Settings::get("BasePath") + "Services/";
969 runge 60
	string scriptName = "Base.js";
971 runge 61
	string scriptFileName = basePath + "System/" + scriptName;
969 runge 62
 
63
	if (!file_exists(scriptFileName))
64
	{
976 runge 65
		slog << "Failed to load :" + scriptFileName + "\n";
969 runge 66
	}
67
 
68
	string scriptSource = file_get_contents(scriptFileName);
69
 
70
	Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
71
	//each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
72
	Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
73
 
74
	// Create a template for the global object.
75
	myGlobal = ObjectTemplate::New();
76
 
77
	//associates "print" on script to the Print function
78
	myGlobal->Set(String::New("log"), FunctionTemplate::New(VirtualMachine_log));
79
	myGlobal->Set(String::New("sendCanMessage"), FunctionTemplate::New(VirtualMachine_sendCanMessage));
986 runge 80
	myGlobal->Set(String::New("sendCanNMTMessage"), FunctionTemplate::New(VirtualMachine_sendCanNMTMessage));
969 runge 81
	myGlobal->Set(String::New("loadScript"), FunctionTemplate::New(VirtualMachine_loadScript));
971 runge 82
	myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine_startIntervalThread));
83
	myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine_stopIntervalThread));
976 runge 84
	myGlobal->Set(String::New("startSocketThread"), FunctionTemplate::New(VirtualMachine_startSocketThread));
85
	myGlobal->Set(String::New("stopSocketThread"), FunctionTemplate::New(VirtualMachine_stopSocketThread));
86
	myGlobal->Set(String::New("sendToSocketThread"), FunctionTemplate::New(VirtualMachine_sendToSocketThread));
981 runge 87
	myGlobal->Set(String::New("uint2hex"), FunctionTemplate::New(VirtualMachine_uint2hex));
969 runge 88
 
89
	//create context for the script
90
	myContext = Context::New(NULL, myGlobal);
91
 
92
 
93
	//access global context within this scope
94
	Context::Scope context_scope(myContext);
95
	//exception handler
96
	TryCatch try_catch;
97
	//compile script to binary code - JIT
98
	Handle<Script> script = Script::Compile(source, name);
99
 
100
	//check if we got problems on compilation
101
	if (script.IsEmpty())
102
	{
103
 
104
		// Print errors that happened during compilation.
105
		String::AsciiValue error(try_catch.Exception());
976 runge 106
		string sError = *error;
107
		slog << "Failed to compile script: " + sError + "\n";
969 runge 108
	}
109
	else
110
	{
111
		//no errors , let's continue
112
		Handle<Value> result = script->Run();
113
 
114
		//check if execution ended with errors
115
		if (result.IsEmpty())
116
		{
117
			// Print errors that happened during execution.
118
			String::AsciiValue error(try_catch.Exception());
976 runge 119
			string sError = *error;
120
			slog << "Constructor: Failed to run script: " << sError << "\n";
969 runge 121
		}
122
		else
123
		{
124
			loadScript("System/Startup.js");
125
 
970 runge 126
			if (file_exists(basePath + "Autostart.js"))
127
			{
128
				loadScript("Autostart.js");
129
			}
130
 
986 runge 131
			myFunctionHandleNMTMessage = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleNMTMessage")));
969 runge 132
			myFunctionOfflineCheck = Handle<Function>::Cast(myContext->Global()->Get(String::New("offlineCheck")));
133
			myFunctionHandleMessage = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleMessage")));
134
			myFunctionStartup = Handle<Function>::Cast(myContext->Global()->Get(String::New("startup")));
135
		}
136
	}
137
 
138
	const int argc = 0;
139
	Handle<Value> argv[argc] = { };
140
 
141
	Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv); // argc and argv are your standard arguments to a function
142
 
143
	mySemaphore.lock();
144
 
145
	while (1)
146
	{
147
		string expression;
148
 
149
		while (myExpressions.size() > 0)
150
		{
151
			expression = myExpressions.pop();
152
 
153
			runExpression(expression);
154
		}
155
 
156
		CanMessage canMessage;
157
 
158
		while (myCanMessages.size() > 0)
159
		{
160
			canMessage = myCanMessages.pop();
161
 
986 runge 162
			if (canMessage.getClassName() == "nmt")
969 runge 163
			{
986 runge 164
				callHandleNMTMessage(canMessage);
969 runge 165
			}
166
			else
167
			{
168
				callHandleMessage(canMessage);
169
			}
170
		}
171
 
172
		mySemaphore.wait();
173
	}
174
 
175
	mySemaphore.unlock();
176
}
177
 
178
void VirtualMachine::queueCanMessage(CanMessage canMessage)
179
{
180
	myCanMessages.push(canMessage);
181
	mySemaphore.broadcast();
182
}
183
 
184
void VirtualMachine::queueExpression(string expression)
185
{
186
	myExpressions.push(expression);
187
	mySemaphore.broadcast();
188
}
189
 
190
bool VirtualMachine::loadScript(string scriptName)
191
{
192
	SyslogStream &slog = SyslogStream::getInstance();
193
 
981 runge 194
	string basePath = Settings::get("BasePath") + "Services/";
969 runge 195
	string scriptFileName = basePath + scriptName;
196
 
197
	if (!file_exists(scriptFileName))
198
	{
981 runge 199
		slog << "Failed to load " + scriptFileName + "\n";
969 runge 200
		return false;
201
	}
202
 
203
	string scriptSource = file_get_contents(scriptFileName);
204
 
205
	Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
206
	//each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
207
	Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
208
 
209
	//access global context within this scope
210
	Context::Scope context_scope(myContext);
211
	//exception handler
212
	TryCatch try_catch;
213
	//compile script to binary code - JIT
214
	Handle<Script> script = Script::Compile(source, name);
215
 
216
	//check if we got problems on compilation
217
	if (script.IsEmpty())
218
	{
219
		// Print errors that happened during compilation.
220
		String::AsciiValue error(try_catch.Exception());
976 runge 221
		string sError = *error;
222
		slog << "loadScript: Failed to compile script: " + sError + "\n";
969 runge 223
		return false;
224
	}
225
	else
226
	{
227
		//no errors , let's continue
228
		Handle<Value> result = script->Run();
229
 
230
		//check if execution ended with errors
231
		if (result.IsEmpty())
232
		{
233
			// Print errors that happened during execution.
234
			String::AsciiValue error(try_catch.Exception());
976 runge 235
			string sError = *error;
236
			slog << "loadScript: Failed to run script: " + sError + "\n";
969 runge 237
			return false;
238
		}
977 runge 239
 
240
		slog << "Loaded " + scriptName + "\n";
969 runge 241
	}
242
 
243
	return true;
244
}
245
 
986 runge 246
void VirtualMachine::callHandleNMTMessage(CanMessage canMessage)
969 runge 247
{
986 runge 248
	const int argc = 3;
969 runge 249
 
986 runge 250
	string jsonData = canMessage.getJSONData();
251
 
252
	Handle<Value> argv[argc] = {String::New(canMessage.getClassName().c_str()),
253
								String::New(canMessage.getCommandName().c_str()),
254
								String::New(jsonData.c_str()) };
255
 
256
	Handle<Value> result = myFunctionHandleNMTMessage->Call(myFunctionHandleNMTMessage, argc, argv); // argc and argv are your standard arguments to a function
969 runge 257
}
258
 
259
void VirtualMachine::callHandleMessage(CanMessage canMessage)
260
{
261
	const int argc = 6;
981 runge 262
 
263
	string jsonData = canMessage.getJSONData();
264
 
969 runge 265
	Handle<Value> argv[argc] = {String::New(canMessage.getClassName().c_str()),
266
								String::New(canMessage.getDirectionFlag().c_str()),
267
								String::New(canMessage.getModuleName().c_str()),
268
								Integer::New(canMessage.getModuleId()),
269
								String::New(canMessage.getCommandName().c_str()),
981 runge 270
								String::New(jsonData.c_str()) };
969 runge 271
 
272
	Handle<Value> result = myFunctionHandleMessage->Call(myFunctionHandleMessage, argc, argv); // argc and argv are your standard arguments to a function
273
}
274
 
971 runge 275
unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
969 runge 276
{
971 runge 277
	IntervalThread intervalThread(timeout);
969 runge 278
 
971 runge 279
	myIntervalThreads[intervalThread.getId()] = intervalThread;
280
	myIntervalThreads[intervalThread.getId()].start();
969 runge 281
 
971 runge 282
	return intervalThread.getId();
969 runge 283
}
284
 
971 runge 285
bool VirtualMachine::stopIntervalThread(unsigned int id)
969 runge 286
{
971 runge 287
	if (myIntervalThreads.find(id) != myIntervalThreads.end())
969 runge 288
	{
971 runge 289
		myIntervalThreads.erase(id);
969 runge 290
		return true;
291
	}
292
 
293
	return false;
294
}
295
 
976 runge 296
unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
297
{
983 runge 298
	SocketThread *socketThread = new SocketThread(address, port, reconnectTimeout);
299
	mySocketThreads[socketThread->getId()] = socketThread;
300
	mySocketThreads[socketThread->getId()]->start();
976 runge 301
 
983 runge 302
	return socketThread->getId();
976 runge 303
}
304
 
305
bool VirtualMachine::stopSocketThread(unsigned int id)
306
{
983 runge 307
 
308
 
976 runge 309
	if (mySocketThreads.find(id) != mySocketThreads.end())
310
	{
983 runge 311
		//mySocketThreads[id]->stop();
312
		delete mySocketThreads[id];
313
 
976 runge 314
		mySocketThreads.erase(id);
315
		return true;
316
	}
317
 
318
	return false;
319
}
320
 
321
void VirtualMachine::sendToSocketThread(unsigned int id, string data)
322
{
323
	if (mySocketThreads.find(id) != mySocketThreads.end())
324
	{
983 runge 325
		mySocketThreads[id]->send(data);
976 runge 326
	}
327
}
328
 
969 runge 329
bool VirtualMachine::runExpression(string expression)
330
{
331
	SyslogStream &slog = SyslogStream::getInstance();
332
 
333
	string scriptName = "runExpression";
334
 
335
	Handle<String> source =  String::New(expression.c_str(), expression.length());
336
	//each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
337
	Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
338
 
339
	//access global context within this scope
340
	Context::Scope context_scope(myContext);
341
	//exception handler
342
	TryCatch try_catch;
343
	//compile script to binary code - JIT
344
	Handle<Script> script = Script::Compile(source, name);
345
 
346
	//check if we got problems on compilation
347
	if (script.IsEmpty())
348
	{
349
		// Print errors that happened during compilation.
350
		String::AsciiValue error(try_catch.Exception());
976 runge 351
		string sError = *error;
352
		slog << "runExpression: Failed to compile script: " + sError + "\n";
353
		slog << expression << "\n\n";
969 runge 354
		return false;
355
	}
356
	else
357
	{
358
		//no errors , let's continue
359
		Handle<Value> result = script->Run();
360
 
361
		//check if execution ended with errors
362
		if (result.IsEmpty())
363
		{
364
			// Print errors that happened during execution.
365
			String::AsciiValue error(try_catch.Exception());
976 runge 366
			string sError = *error;
367
			slog << "runExpression: Failed to run script: " + sError + "\n";
969 runge 368
			return false;
369
		}
370
	}
371
 
372
	return true;
373
}
374
 
375
Handle<Value> VirtualMachine_log(const Arguments& args)
376
{
377
	SyslogStream &slog = SyslogStream::getInstance();
378
 
379
	String::AsciiValue str(args[0]);
380
 
381
	slog << *str;
382
 
383
	return Undefined();
384
}
385
 
386
Handle<Value> VirtualMachine_sendCanMessage(const Arguments& args)
387
{
976 runge 388
	//SyslogStream &slog = SyslogStream::getInstance();
969 runge 389
	CanNetManager &canMan = CanNetManager::getInstance();
390
 
391
	CanMessage canMessage;
392
 
393
	String::AsciiValue className(args[0]);
394
	canMessage.setClassName(*className);
395
	String::AsciiValue directionFlag(args[1]);
396
	canMessage.setDirectionFlag(*directionFlag);
397
	String::AsciiValue moduleName(args[2]);
398
	canMessage.setModuleName(*moduleName);
399
	canMessage.setModuleId(args[3]->Uint32Value());
400
	String::AsciiValue commandName(args[4]);
401
	canMessage.setCommandName(*commandName);
402
 
403
	String::AsciiValue dataString(args[5]);
404
 
405
	vector<string> parts = explode(",", trim(*dataString, ','));
406
	map<string, CanVariable> data;
407
 
408
	for (int n = 0; n < parts.size(); n++)
409
	{
410
		vector<string> keyAndValue = explode(":", parts[n]);
411
 
412
		//string key = trim(keyAndValue[0], ' ');
413
		//string value = trim(keyAndValue[1], ' ');
414
		data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
415
	}
416
 
417
	canMessage.setData(data);
418
 
419
	canMan.sendMessage(canMessage);
420
 
421
	return Undefined();
422
}
423
 
986 runge 424
Handle<Value> VirtualMachine_sendCanNMTMessage(const Arguments& args)
425
{
426
	//SyslogStream &slog = SyslogStream::getInstance();
427
	CanNetManager &canMan = CanNetManager::getInstance();
428
 
429
	CanMessage canMessage;
430
 
431
	String::AsciiValue className(args[0]);
432
	canMessage.setClassName(*className);
433
	String::AsciiValue commandName(args[1]);
434
	canMessage.setCommandName(*commandName);
435
 
436
	String::AsciiValue dataString(args[2]);
437
 
438
	vector<string> parts = explode(",", trim(*dataString, ','));
439
	map<string, CanVariable> data;
440
 
441
	for (int n = 0; n < parts.size(); n++)
442
	{
443
		vector<string> keyAndValue = explode(":", parts[n]);
444
 
445
		//string key = trim(keyAndValue[0], ' ');
446
		//string value = trim(keyAndValue[1], ' ');
447
		data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
448
	}
449
 
450
	canMessage.setData(data);
451
 
452
	canMan.sendMessage(canMessage);
453
 
454
	return Undefined();
455
}
456
 
969 runge 457
Handle<Value> VirtualMachine_loadScript(const Arguments& args)
458
{
459
	VirtualMachine &vm = VirtualMachine::getInstance();
460
 
461
	String::AsciiValue str(args[0]);
462
 
463
	return Boolean::New(vm.loadScript(*str));
464
}
465
 
971 runge 466
Handle<Value> VirtualMachine_startIntervalThread(const Arguments& args)
969 runge 467
{
468
	VirtualMachine &vm = VirtualMachine::getInstance();
469
 
971 runge 470
	unsigned int timeout = args[0]->Uint32Value();
969 runge 471
 
971 runge 472
	return Integer::New(vm.startIntervalThread(timeout));
969 runge 473
}
474
 
971 runge 475
Handle<Value> VirtualMachine_stopIntervalThread(const Arguments& args)
969 runge 476
{
477
	VirtualMachine &vm = VirtualMachine::getInstance();
478
 
973 runge 479
	unsigned int id = args[0]->Uint32Value();
969 runge 480
 
976 runge 481
	return Boolean::New(vm.stopIntervalThread(id));
969 runge 482
}
976 runge 483
 
484
Handle<Value> VirtualMachine_startSocketThread(const Arguments& args)
485
{
486
	VirtualMachine &vm = VirtualMachine::getInstance();
487
 
488
	String::AsciiValue address(args[0]);
489
	int port = args[1]->Uint32Value();
490
	unsigned int reconnectTimeout = args[2]->Uint32Value();
491
 
492
	return Integer::New(vm.startSocketThread(*address, port, reconnectTimeout));
493
}
494
 
495
Handle<Value> VirtualMachine_stopSocketThread(const Arguments& args)
496
{
497
	VirtualMachine &vm = VirtualMachine::getInstance();
498
 
499
	unsigned int id = args[0]->Uint32Value();
500
 
501
	return Boolean::New(vm.stopSocketThread(id));
502
}
503
 
504
Handle<Value> VirtualMachine_sendToSocketThread(const Arguments& args)
505
{
506
	VirtualMachine &vm = VirtualMachine::getInstance();
507
 
508
	unsigned int id = args[0]->Uint32Value();
509
	String::AsciiValue data(args[1]);
510
 
511
	vm.sendToSocketThread(id, *data);
512
 
513
	return Undefined();
514
}
515
 
981 runge 516
Handle<Value> VirtualMachine_uint2hex(const Arguments& args)
517
{
518
	VirtualMachine &vm = VirtualMachine::getInstance();
519
 
520
	unsigned int id = args[0]->Uint32Value();
521
	unsigned int length = args[1]->Uint32Value();
522
	string hexId = uint2hex(id, length);
523
 
524
	return String::New(hexId.c_str());
525
}
526