source: trunk/FACT++/src/InterpreterV8.cc@ 14597

Last change on this file since 14597 was 14591, checked in by tbretz, 12 years ago
Some improvements to exeption texts; stored the issued query for reference in the DB object; added function to calculate the distance between two points on the local sphere
File size: 49.1 KB
Line 
1#include "InterpreterV8.h"
2
3#ifdef HAVE_NOVA
4#include <libnova/lunar.h>
5#include <libnova/transform.h>
6#endif
7
8#ifdef HAVE_SQL
9#include "Database.h"
10#endif
11
12#include <boost/tokenizer.hpp>
13
14InterpreterV8 *InterpreterV8::This = 0;
15
16#ifdef HAVE_V8
17
18#include <v8.h>
19#include <fstream>
20#include <sstream>
21#include <iomanip>
22
23using namespace std;
24using namespace v8;
25
26
27// ==========================================================================
28// Simple interface
29// ==========================================================================
30
31Handle<Value> InterpreterV8::FuncExit(const Arguments &)
32{
33 V8::TerminateExecution(fThreadId);
34 return ThrowException(String::New("exit"));
35/*
36 if (args.Length()!=1)
37 return ThrowException(String::New("Number of arguments must be exactly 1."));
38
39 if (!args[0]->IsUint32())
40 return ThrowException(String::New("Argument 1 must be an uint32."));
41
42 const HandleScope handle_scope;
43
44 JsSleep(args[0]->Int32Value());
45*/
46 return Undefined();
47}
48
49
50Handle<Value> InterpreterV8::FuncSleep(const Arguments& args)
51{
52 if (args.Length()==0)
53 {
54 // Theoretically, the CPU usage can be reduced by maybe a factor
55 // of four using a larger value, but this also means that the
56 // JavaScript is locked for a longer time.
57 usleep(1000);
58 return Undefined();
59 }
60
61 if (args.Length()!=1)
62 return ThrowException(String::New("Number of arguments must be exactly 1."));
63
64 if (!args[0]->IsUint32())
65 return ThrowException(String::New("Argument 1 must be an uint32."));
66
67 // Using a Javascript function has the advantage that it is fully
68 // interruptable without the need of C++ code
69
70 const string code =
71 "(function(){"
72 "var t=new Date();"
73 "while ((new Date()-t)<"+to_string(args[0]->Int32Value())+") dim.sleep();"
74 "})();";
75
76 HandleScope handle_scope;
77
78 const Handle<Script> script = Script::Compile(String::New(code.c_str()));
79
80 return handle_scope.Close(script->Run());
81
82 //JsSleep(args[0]->Int32Value());
83 //return Undefined();
84}
85
86Handle<Value> InterpreterV8::FuncSend(const Arguments& args)
87{
88 if (args.Length()==0)
89 return ThrowException(String::New("Number of arguments must be at least 1."));
90
91 if (!args[0]->IsString())
92 return ThrowException(String::New("Argument 1 must be a string."));
93
94 HandleScope handle_scope;
95
96 const String::Utf8Value str(args[0]);
97
98 string command = *str;
99
100 // Escape all string arguments. All others can be kept as they are.
101 for (int i=1; i<args.Length(); i++)
102 {
103 const String::Utf8Value arg(args[i]);
104 if (args[i]->IsString())
105 command += " \""+string(*arg)+"\"";
106 else
107 command += " "+string(*arg);
108 }
109
110 return handle_scope.Close(Boolean::New(JsSend(command)));
111}
112
113// ==========================================================================
114// State control
115// ==========================================================================
116
117Handle<Value> InterpreterV8::FuncWait(const Arguments& args)
118{
119 if (args.Length()!=2 && args.Length()!=3)
120 return ThrowException(String::New("Number of arguments must be 2 or 3."));
121
122 if (!args[0]->IsString())
123 return ThrowException(String::New("Argument 1 not a string."));
124
125 if (!args[1]->IsInt32() && !args[1]->IsString())
126 return ThrowException(String::New("Argument 2 not an int32 and not a string."));
127
128 if (args.Length()==3 && !args[2]->IsUint32())
129 return ThrowException(String::New("Argument 3 not an uint32."));
130
131 // Using a Javascript function has the advantage that it is fully
132 // interruptable without the need of C++ code
133
134 const string index = args[1]->IsInt32() ? "s.index" : "s.name";
135 const bool timeout = args.Length()==3;
136 const string arg0 = *String::Utf8Value(args[0]);
137 const string state = args[1]->IsString() ? *String::Utf8Value(args[1]) : "";
138 const string arg1 = args[1]->IsString() ? ("\""+state+"\"") : to_string(args[1]->Int32Value());
139
140 if (arg0.find_first_of("\"'")!=string::npos)
141 return ThrowException(String::New("Server name must not contain quotation marks."));
142
143 if (args[1]->IsString())
144 if (state.find_first_of("\"'")!=string::npos)
145 return ThrowException(String::New("State name must not contain quotation marks."));
146
147 string code = "(function(name,state,ms)"
148 "{";
149 if (timeout)
150 code += "var t = new Date();";
151 code += "while (1)"
152 "{"
153 "var s = dim.state(name);"
154 "if(!"+index+")throw 'Waitig for state "+arg1+" of server "+arg0+" failed.';"
155 "if(state=="+index+")return true;";
156 if (timeout)
157 code += "if((new Date()-t)>ms)return false;";
158
159 code += "dim.sleep();"
160 "}"
161 "})('"+arg0+"',"+arg1;
162 if (timeout)
163 code += "," + to_string(args[2]->Int32Value());
164 code += ");";
165
166 HandleScope handle_scope;
167
168 // It is not strictly necessary to catch the exception, instead
169 // script->Run() could just be returned, but catching the
170 // exception allow to print the position in the file in
171 // the exception handler instead of just the posiiton in the script.
172 TryCatch exception;
173
174 const Handle<Script> script = Script::Compile(String::New(code.c_str()));
175 const Handle<Value> result = script->Run();
176
177 return exception.HasCaught() ? exception.ReThrow() : handle_scope.Close(result);
178
179 /*
180 const string server = *String::Utf8Value(args[0]);
181 const int32_t state = args[1]->Int32Value();
182 const uint32_t millisec = args.Length()==3 ? args[2]->Int32Value() : 0;
183
184 const int rc = JsWait(server, state, millisec);
185
186 if (rc==0 || rc==1)
187 return Boolean::New(rc);
188
189 return ThrowException(String::New(("Waitig for state "+to_string(state)+" of server '"+server+"' failed.").c_str()));
190 */
191}
192
193Handle<Value> InterpreterV8::FuncState(const Arguments& args)
194{
195 if (args.Length()!=1)
196 return ThrowException(String::New("Number of arguments must be exactly 1."));
197
198 if (!args[0]->IsString())
199 return ThrowException(String::New("Argument 1 must be a string."));
200
201 // Return state.name/state.index
202
203 const String::Utf8Value str(args[0]);
204
205 const State rc = JsState(*str);
206
207 //if (rc.first<=-256)
208 // return Undefined();
209
210 HandleScope handle_scope;
211
212 // It is important to catch the exception thrown
213 // by Date::New in case of thread termination!
214 Local<Value> date;
215 {
216 TryCatch exception;
217 date = Date::New(rc.time.JavaDate());
218 if (exception.HasCaught())
219 return exception.ReThrow();
220 }
221
222 Handle<ObjectTemplate> obj = ObjectTemplate::New();
223 obj->Set(String::New("index"), rc.index<=-256?Undefined():Integer::New(rc.index), ReadOnly);
224 obj->Set(String::New("name"), rc.index<=-256?Undefined():String::New(rc.name.c_str()), ReadOnly);
225 if (rc.index>-256)
226 obj->Set(String::New("time"), date);
227 //obj->Set(String::New("toString"), String::New(("[Object state "+string(*str)+":"+to_string(rc.index)+"]").c_str()));
228
229 return handle_scope.Close(obj->NewInstance());
230}
231
232Handle<Value> InterpreterV8::FuncNewState(const Arguments& args)
233{
234 if (args.Length()<1 || args.Length()>3)
235 return ThrowException(String::New("Number of arguments must be 1, 2 or 3."));
236
237 if (!args[0]->IsUint32())
238 return ThrowException(String::New("Argument 1 must be an uint32."));
239 if (args.Length()>1 && !args[1]->IsString())
240 return ThrowException(String::New("Argument 2 must be a string."));
241 if (args.Length()>2 && !args[2]->IsString())
242 return ThrowException(String::New("Argument 3 must be a string."));
243
244 HandleScope handle_scope;
245
246 const uint32_t index = args[0]->Int32Value();
247 const string name = *String::Utf8Value(args[1]);
248 const string comment = *String::Utf8Value(args[2]);
249
250 if (index<10 || index>255)
251 return ThrowException(String::New("State must be in the range [10, 255]."));
252
253 if (name.empty())
254 return ThrowException(String::New("State name must not be empty."));
255
256 if (name.find_first_of(':')!=string::npos || name.find_first_of('=')!=string::npos)
257 return ThrowException(String::New("State name must not contain : or =."));
258
259 if (JsHasState(index) || JsHasState(name))
260 {
261 const string what =
262 "State index ["+to_string(index)+"] or name ["+name+"] already defined.";
263
264 return ThrowException(String::New(what.c_str()));
265 }
266
267 return handle_scope.Close(Boolean::New(JsNewState(index, name, comment)));
268}
269
270Handle<Value> InterpreterV8::FuncSetState(const Arguments& args)
271{
272 if (args.Length()!=1)
273 return ThrowException(String::New("Number of arguments must be exactly 1."));
274
275 if (!args[0]->IsUint32() && !args[0]->IsString())
276 return ThrowException(String::New("Argument must be an unint32 or a string."));
277
278 HandleScope handle_scope;
279
280 int index = -2;
281 if (args[0]->IsUint32())
282 {
283 index = args[0]->Int32Value();
284 }
285 else
286 {
287 const string name = *String::Utf8Value(args[0]);
288 index = JsGetState(name);
289 if (index==-2)
290 return ThrowException(String::New(("State '"+name+"' not found.").c_str()));
291 }
292
293 if (index<10 || index>255)
294 return ThrowException(String::New("State must be in the range [10, 255]."));
295
296 return handle_scope.Close(Boolean::New(JsSetState(index)));
297}
298
299// ==========================================================================
300// Internal functions
301// ==========================================================================
302
303
304// The callback that is invoked by v8 whenever the JavaScript 'print'
305// function is called. Prints its arguments on stdout separated by
306// spaces and ending with a newline.
307Handle<Value> InterpreterV8::FuncPrint(const Arguments& args)
308{
309 for (int i=0; i<args.Length(); i++)
310 {
311 const HandleScope handle_scope;
312
313 const String::Utf8Value str(args[i]);
314 if (*str)
315 JsPrint(*str);
316 }
317 return Undefined();
318}
319
320Handle<Value> InterpreterV8::FuncAlarm(const Arguments& args)
321{
322 for (int i=0; i<args.Length(); i++)
323 {
324 const HandleScope handle_scope;
325
326 const String::Utf8Value str(args[i]);
327 if (*str)
328 JsAlarm(*str);
329 }
330
331 if (args.Length()==0)
332 JsAlarm();
333
334 return Undefined();
335}
336
337Handle<Value> InterpreterV8::FuncOut(const Arguments& args)
338{
339 for (int i=0; i<args.Length(); i++)
340 {
341 const HandleScope handle_scope;
342
343 const String::Utf8Value str(args[i]);
344 if (*str)
345 JsOut(*str);
346 }
347 return Undefined();
348}
349
350// The callback that is invoked by v8 whenever the JavaScript 'load'
351// function is called. Loads, compiles and executes its argument
352// JavaScript file.
353Handle<Value> InterpreterV8::FuncInclude(const Arguments& args)
354{
355 for (int i=0; i<args.Length(); i++)
356 {
357 const HandleScope handle_scope;
358
359 const String::Utf8Value file(args[i]);
360 if (*file == NULL)
361 return ThrowException(String::New(("Error loading file '"+string(*file)+"'").c_str()));
362
363 if (!ExecuteFile(*file))
364 return ThrowException(String::New(("Execution of '"+string(*file)+"' failed").c_str()));
365 }
366 return Undefined();
367}
368
369Handle<Value> InterpreterV8::FuncVersion(const Arguments&)
370{
371 return String::New(V8::GetVersion());
372}
373
374// ==========================================================================
375// Database
376// ==========================================================================
377
378Handle<Value> InterpreterV8::FuncDbClose(const Arguments &args)
379{
380 HandleScope handle_scope;
381
382 void *ptr = Handle<External>::Cast(args.This()->GetInternalField(0))->Value();
383 if (!ptr)
384 return handle_scope.Close(Boolean::New(false));
385
386#ifdef HAVE_SQL
387 Database *db = reinterpret_cast<Database*>(ptr);
388 auto it = find(fDatabases.begin(), fDatabases.end(), db);
389 fDatabases.erase(it);
390 delete db;
391#endif
392
393 args.This()->SetInternalField(0, External::New(0));
394
395 return handle_scope.Close(Boolean::New(true));
396}
397Handle<Value> InterpreterV8::FuncDbQuery(const Arguments &args)
398{
399 if (args.Length()==0)
400 return ThrowException(String::New("Arguments expected."));
401
402 HandleScope handle_scope;
403
404 void *ptr = Handle<External>::Cast(args.This()->GetInternalField(0))->Value();
405 if (!ptr)
406 return Undefined();
407
408 string query;
409 for (int i=0; i<args.Length(); i++)
410 query += string(" ") + *String::Utf8Value(args[i]);
411 query.erase(0, 1);
412
413#ifdef HAVE_SQL
414 try
415 {
416 Database *db = reinterpret_cast<Database*>(ptr);
417
418 const mysqlpp::StoreQueryResult res = db->query(query).store();
419
420 Handle<Array> ret = Array::New();
421 ret->Set(String::New("table"), String::New(res.table()), ReadOnly);
422 ret->Set(String::New("query"), String::New(query.c_str()), ReadOnly);
423
424 Handle<Array> cols = Array::New();
425
426 int irow=0;
427 for (vector<mysqlpp::Row>::const_iterator it=res.begin(); it<res.end(); it++)
428 {
429 Handle<Array> row = Array::New();
430
431 const mysqlpp::FieldNames *list = it->field_list().list;
432
433 for (size_t i=0; i<it->size(); i++)
434 {
435 const Handle<Value> name = String::New((*list)[i].c_str());
436 if (irow==0)
437 cols->Set(i, name);
438
439 if ((*it)[i].is_null())
440 {
441 row->Set(name, Undefined(), ReadOnly);
442 continue;
443 }
444
445 const string sql_type = (*it)[i].type().sql_name();
446
447 const bool uns = sql_type.find("UNSIGNED")==string::npos;
448
449 if (sql_type.find("BIGINT")!=string::npos)
450 {
451 if (uns)
452 {
453 const uint64_t val = (uint64_t)(*it)[i];
454 if (val>UINT32_MAX)
455 row->Set(name, Number::New(val), ReadOnly);
456 else
457 row->Set(name, Integer::NewFromUnsigned(val), ReadOnly);
458 }
459 else
460 {
461 const int64_t val = (int64_t)(*it)[i];
462 if (val<INT32_MIN || val>INT32_MAX)
463 row->Set(name, Number::New(val), ReadOnly);
464 else
465 row->Set(name, Integer::NewFromUnsigned(val), ReadOnly);
466 }
467 continue;
468 }
469
470 // 32 bit
471 if (sql_type.find("INT")!=string::npos)
472 {
473 if (uns)
474 row->Set(name, Integer::NewFromUnsigned((uint32_t)(*it)[i]), ReadOnly);
475 else
476 row->Set(name, Integer::New((int32_t)(*it)[i]), ReadOnly);
477 }
478
479 if (sql_type.find("BOOL")!=string::npos )
480 {
481 row->Set(name, Boolean::New((bool)(*it)[i]), ReadOnly);
482 continue;
483 }
484
485 if (sql_type.find("FLOAT")!=string::npos)
486 {
487 ostringstream val;
488 val << setprecision(7) << (float)(*it)[i];
489 row->Set(name, Number::New(stod(val.str())), ReadOnly);
490 continue;
491
492 }
493 if (sql_type.find("DOUBLE")!=string::npos)
494 {
495 row->Set(name, Number::New((double)(*it)[i]), ReadOnly);
496 continue;
497 }
498
499 if (sql_type.find("CHAR")!=string::npos ||
500 sql_type.find("TEXT")!=string::npos)
501 {
502 row->Set(name, String::New((const char*)(*it)[i]), ReadOnly);
503 continue;
504 }
505
506 time_t date = 0;
507 if (sql_type.find("TIMESTAMP")!=string::npos)
508 date = mysqlpp::Time((*it)[i]);
509
510 if (sql_type.find("DATETIME")!=string::npos)
511 date = mysqlpp::DateTime((*it)[i]);
512
513 if (sql_type.find(" DATE ")!=string::npos)
514 date = mysqlpp::Date((*it)[i]);
515
516 if (date>0)
517 {
518 // It is important to catch the exception thrown
519 // by Date::New in case of thread termination!
520 TryCatch exception;
521 Local<Value> val = Date::New(date*1000);
522 if (exception.HasCaught())
523 return exception.ReThrow();
524 //if (V8::IsExecutionTerminating())
525 // return Undefined();
526
527 row->Set(name, val, ReadOnly);
528 }
529 }
530
531 ret->Set(irow++, row);
532 }
533
534 if (irow>0)
535 ret->Set(String::New("cols"), cols, ReadOnly);
536
537 return handle_scope.Close(ret);
538 }
539 catch (const exception &e)
540 {
541 return ThrowException(String::New(e.what()));
542 }
543#endif
544}
545
546Handle<Value> InterpreterV8::FuncDatabase(const Arguments &args)
547{
548 if (args.Length()!=1)
549 return ThrowException(String::New("Number of arguments must be 1."));
550
551 if (!args[0]->IsString())
552 return ThrowException(String::New("Argument 1 not a string."));
553
554 HandleScope handle_scope;
555
556#ifdef HAVE_SQL
557 try
558 {
559 Database *db = new Database(*String::Utf8Value(args[0]));
560 fDatabases.push_back(db);
561
562 Handle<ObjectTemplate> tem = ObjectTemplate::New();
563 tem->Set(String::New("user"), String::New(db->user.c_str()), ReadOnly);
564 tem->Set(String::New("server"), String::New(db->server.c_str()), ReadOnly);
565 tem->Set(String::New("database"), String::New(db->db.c_str()), ReadOnly);
566 tem->Set(String::New("port"), db->port==0?Undefined():Integer::NewFromUnsigned(db->port), ReadOnly);
567 tem->Set(String::New("query"), FunctionTemplate::New(WrapDbQuery), ReadOnly);
568 tem->Set(String::New("close"), FunctionTemplate::New(WrapDbClose), ReadOnly);
569 tem->SetInternalFieldCount(1);
570
571 Handle<Object> obj = tem->NewInstance();
572 obj->SetInternalField(0, External::New(db));
573
574 return handle_scope.Close(obj);
575 }
576 catch (const exception &e)
577 {
578 return ThrowException(String::New(e.what()));
579 }
580#endif
581}
582
583// ==========================================================================
584// Services
585// ==========================================================================
586
587Handle<Value> InterpreterV8::Convert(char type, const char* &ptr)
588{
589 // Dim values are always unsigned per (FACT++) definition
590 switch (type)
591 {
592 case 'F':
593 {
594 // Remove the "imprecision" effect coming from casting a float to
595 // a double and then showing it with double precision
596 ostringstream val;
597 val << setprecision(7) << *reinterpret_cast<const float*>(ptr);
598 Handle<Value> v=Number::New(stod(val.str()));
599 ptr+=4;
600 return v;
601 }
602 case 'D': { Handle<Value> v=Number::New(*reinterpret_cast<const double*>(ptr)); ptr+=8; return v; }
603 case 'I':
604 case 'L': { Handle<Value> v=Integer::NewFromUnsigned(*reinterpret_cast<const uint32_t*>(ptr)); ptr += 4; return v; }
605 case 'X':
606 {
607 const uint64_t val = *reinterpret_cast<const uint64_t*>(ptr);
608 ptr += 8;
609 if (val>UINT32_MAX)
610 return Number::New(val);
611 return Integer::NewFromUnsigned(val);
612 }
613 case 'S': { Handle<Value> v=Integer::NewFromUnsigned(*reinterpret_cast<const uint16_t*>(ptr)); ptr += 2; return v; }
614 case 'C': { Handle<Value> v=Integer::NewFromUnsigned((uint16_t)*reinterpret_cast<const uint8_t*>(ptr)); ptr += 1; return v; }
615 case ':': { Handle<Value> v=String::New(ptr); return v; }
616 }
617 return Undefined();
618}
619
620Handle<Value> InterpreterV8::FuncClose(const Arguments &args)
621{
622 HandleScope handle_scope;
623
624 //const void *ptr = Local<External>::Cast(args.Holder()->GetInternalField(0))->Value();
625
626 const String::Utf8Value str(args.Holder()->Get(String::New("name")));
627
628 const auto it = fReverseMap.find(*str);
629 if (it!=fReverseMap.end())
630 {
631 it->second.Dispose();
632 fReverseMap.erase(it);
633 }
634
635 args.Holder()->Set(String::New("isOpen"), Boolean::New(false), ReadOnly);
636
637 return handle_scope.Close(Boolean::New(JsUnsubscribe(*str)));
638}
639
640Handle<Value> InterpreterV8::ConvertEvent(const EventImp *evt, uint64_t counter, const char *str)
641{
642 Local<Value> date;
643
644 // It is important to catch the exception thrown
645 // by Date::New in case of thread termination!
646 {
647 TryCatch exception;
648 date = Date::New(evt->GetJavaDate());
649 if (exception.HasCaught())
650 return exception.ReThrow();
651 }
652
653 const vector<Description> vec = JsDescription(str);
654
655 Handle<Array> ret = Array::New();
656 ret->Set(String::New("name"), String::New(str), ReadOnly);
657 ret->Set(String::New("format"), String::New(evt->GetFormat().c_str()), ReadOnly);
658 ret->Set(String::New("named"), Boolean::New(vec.size()>0), ReadOnly);
659 ret->Set(String::New("qos"), Integer::New(evt->GetQoS()), ReadOnly);
660 ret->Set(String::New("size"), Integer::New(evt->GetSize()), ReadOnly);
661 ret->Set(String::New("counter"), Integer::New(counter), ReadOnly);
662 ret->Set(String::New("time"), date, ReadOnly);
663
664 // If no event was received (usually a disconnection event in
665 // the context of FACT++), no data is returned
666 if (evt->IsEmpty())
667 return ret;
668
669 // If valid data was received, but the size was zero, then
670 // null is returned as data
671 if (evt->GetSize()==0 || evt->GetFormat().empty())
672 {
673 ret->Set(String::New("data"), Null(), ReadOnly);
674 return ret;
675 }
676
677 typedef boost::char_separator<char> separator;
678 const boost::tokenizer<separator> tokenizer(evt->GetFormat(), separator(";:"));
679
680 const vector<string> tok(tokenizer.begin(), tokenizer.end());
681
682 Handle<Array> obj = tok.size()>1 ? Array::New() : ret;
683
684 const char *ptr = evt->GetText();
685 const char *end = evt->GetText()+evt->GetSize();
686
687 try
688 {
689 size_t pos = 1;
690 for (auto it=tok.begin(); it!=tok.end() && ptr<end; it++, pos++)
691 {
692 char type = (*it)[0];
693 it++;
694
695 if (it==tok.end() && type=='C')
696 type = ':';
697
698 if (it==tok.end() && type!=':')
699 return Exception::Error(String::New(("Format string invalid '"+evt->GetFormat()+"'").c_str()));
700
701 string name = pos<vec.size() ? vec[pos].name : "";
702 if (tok.size()==1)
703 name = "data";
704
705 const uint32_t cnt = it==tok.end() ? 1 : stoi(it->c_str());
706
707 if (cnt==1)
708 {
709 const Handle<Value> v = Convert(type, ptr);
710 if (tok.size()>1)
711 obj->Set(pos-1, v);
712 if (!name.empty())
713 obj->Set(String::New(name.c_str()), v);
714 }
715 else
716 {
717 Handle<Array> a = Array::New(cnt);
718 for (uint32_t i=0; i<cnt; i++)
719 a->Set(i, Convert(type, ptr));
720 if (tok.size()>1)
721 obj->Set(pos-1, a);
722 if (!name.empty())
723 obj->Set(String::New(name.c_str()), a);
724 }
725
726 if (it==tok.end())
727 break;
728 }
729
730 if (tok.size()>1)
731 ret->Set(String::New("data"), obj, ReadOnly);
732
733 return ret;
734 }
735 catch (...)
736 {
737 return Exception::Error(String::New(("Format string conversion '"+evt->GetFormat()+"' failed.").c_str()));
738 }
739}
740/*
741Handle<Value> InterpreterV8::FuncGetData(const Arguments &args)
742{
743 HandleScope handle_scope;
744
745 const String::Utf8Value str(args.Holder()->Get(String::New("name")));
746
747 const pair<uint64_t, EventImp *> p = JsGetEvent(*str);
748
749 const EventImp *evt = p.second;
750 if (!evt)
751 return Undefined();
752
753 //if (counter==cnt)
754 // return info.Holder();//Holder()->Get(String::New("data"));
755
756 Handle<Value> ret = ConvertEvent(evt, p.first, *str);
757 return ret->IsNativeError() ? ThrowException(ret) : handle_scope.Close(ret);
758}
759*/
760Handle<Value> InterpreterV8::FuncGetData(const Arguments &args)
761{
762 if (args.Length()>1)
763 return ThrowException(String::New("Number of arguments must not be greatr than 1."));
764
765 if (args.Length()==1 && !args[0]->IsInt32() && !args[0]->IsNull())
766 return ThrowException(String::New("Argument 1 not an int32."));
767
768 // Using a Javascript function has the advantage that it is fully
769 // interruptable without the need of C++ code
770 const bool null = args.Length()==1 && args[0]->IsNull();
771 const int32_t timeout = args.Length()==1 ? args[0]->Int32Value() : 0;
772
773 HandleScope handle_scope;
774
775 const Handle<Script> sleep = Script::Compile(String::New("dim.sleep();"));
776
777 const Handle<String> data = String::New("data");
778 const Handle<String> named = String::New("named");
779
780 const String::Utf8Value name(args.Holder()->Get(String::New("name")));
781
782 TryCatch exception;
783
784 Time t;
785 while (!exception.HasCaught())
786 {
787 const pair<uint64_t, EventImp *> p = JsGetEvent(*name);
788
789 const EventImp *evt = p.second;
790 if (evt)
791 {
792 const Handle<Value> val = ConvertEvent(evt, p.first, *name);
793 if (val->IsNativeError())
794 return ThrowException(val);
795
796 // Protect against the return of an exception
797 if (!val.IsEmpty() && val->IsObject())
798 {
799 const Handle<Object> obj = val->ToObject();
800 if (obj->Has(data) && obj->Get(named)->ToBoolean()->Value())
801 return handle_scope.Close(val);
802 }
803 }
804
805 if (args.Length()==0)
806 break;
807
808 if (!null && Time()-t>=boost::posix_time::milliseconds(abs(timeout)))
809 break;
810
811 // We cannot sleep directly because we have to give control back to
812 // JavaScript ever now and then. This also allows us to catch
813 // exceptions, either from the preemption or ConvertEvent
814 sleep->Run();
815 }
816
817 if (exception.HasCaught())
818 return exception.ReThrow();
819
820 if (timeout>=0)
821 return Undefined();
822
823 const string str = "Waiting for a valid event of "+string(*name)+" timed out.";
824 return ThrowException(String::New(str.c_str()));
825}
826
827
828// This is a callback from the RemoteControl piping event handling
829// to the java script ---> in test phase!
830void InterpreterV8::JsHandleEvent(const EventImp &evt, uint64_t cnt, const string &service)
831{
832 if (fThreadId<0)
833 return;
834
835 Locker locker;
836
837 const auto it = fReverseMap.find(service);
838 if (it==fReverseMap.end())
839 return;
840
841 const HandleScope handle_scope;
842
843 Handle<Object> obj = it->second;
844 if (obj.IsEmpty())
845 return;
846
847 const Handle<String> onchange = String::New("onchange");
848 if (!obj->Has(onchange))
849 return;
850
851 const Handle<Value> val = obj->Get(onchange);
852 if (!val->IsFunction())
853 return;
854
855 // -------------------------------------------------------------------
856 // We are not in a context... we need to get into one for Array::New
857
858 Persistent<Context> context = Context::New();
859 if (context.IsEmpty())
860 return;
861
862 const Context::Scope scope(context);
863
864 // -------------------------------------------------------------------
865
866 TryCatch exception;
867
868 Handle<Value> ret = ConvertEvent(&evt, cnt, service.c_str());
869 if (ret->IsArray())
870 {
871 Handle<Array> data = Handle<Array>::Cast(ret);
872 Handle<Value> args[] = { data };
873
874 Handle<Function>::Cast(val)->Call(obj, 1, args);
875 }
876
877 if (exception.HasCaught())
878 ReportException(&exception);
879
880 if (ret->IsNativeError())
881 JsException(service+".onchange callback - "+*String::Utf8Value(ret));
882
883 context.Dispose();
884
885 if (ret->IsUndefined() || ret->IsNativeError() || exception.HasCaught())
886 V8::TerminateExecution(fThreadId);
887}
888
889Handle<Value> InterpreterV8::OnChangeSet(Local<String> prop, Local< Value > value, const AccessorInfo &)
890{
891 const HandleScope handle_scope;
892
893 // Returns the value if the setter intercepts the request. Otherwise, returns an empty handle.
894 const string server = *String::Utf8Value(prop);
895 auto it = fStateCallbacks.find(server);
896
897 if (it!=fStateCallbacks.end())
898 {
899 it->second.Dispose();
900 fStateCallbacks.erase(it);
901 }
902
903 if (value->IsFunction())
904 fStateCallbacks[server] = Persistent<Value>::New(value);
905
906 return Handle<Value>();
907}
908
909
910void InterpreterV8::JsHandleState(const std::string &server, const State &state)
911{
912 if (fThreadId<0)
913 return;
914
915 Locker locker;
916
917 auto it = fStateCallbacks.find(server);
918 if (it==fStateCallbacks.end())
919 {
920 it = fStateCallbacks.find("*");
921 if (it==fStateCallbacks.end())
922 return;
923 }
924
925 const HandleScope handle_scope;
926
927 if (it->second.IsEmpty() || !it->second->IsFunction())
928 return;
929
930 // -------------------------------------------------------------------
931 // We are not in a context... we need to get into one for Array::New
932
933 Persistent<Context> context = Context::New();
934 if (context.IsEmpty())
935 return;
936
937 const Context::Scope scope(context);
938
939 // -------------------------------------------------------------------
940
941 TryCatch exception;
942
943 // It is important to catch the exception thrown
944 // by Date::New in case of thread termination!
945 Local<Value> date = Date::New(state.time.JavaDate());
946
947 if (!exception.HasCaught())
948 {
949 Handle<ObjectTemplate> obj = ObjectTemplate::New();
950 obj->Set(String::New("index"), state.index<=-256?Undefined():Integer::New(state.index), ReadOnly);
951 obj->Set(String::New("name"), state.index<=-256?Undefined():String::New(state.name.c_str()), ReadOnly);
952 obj->Set(String::New("comment"), state.index<=-256?Undefined():String::New(state.comment.c_str()), ReadOnly);
953 obj->Set(String::New("server"), String::New(server.c_str()), ReadOnly);
954 if (state.index>-256)
955 obj->Set(String::New("time"), date);
956
957 Handle<Value> args[] = { obj->NewInstance() };
958
959 Handle<Function> fun = Handle<Function>::Cast(it->second);
960 fun->Call(fun, 1, args);
961 }
962
963 if (exception.HasCaught())
964 ReportException(&exception);
965
966 context.Dispose();
967
968 if (exception.HasCaught())
969 V8::TerminateExecution(fThreadId);
970}
971
972/*
973void Cleanup( Persistent<Value> object, void *parameter )
974{
975 cout << "======================> RemoveMyObj()" << endl;
976}*/
977
978Handle<Value> InterpreterV8::FuncSubscribe(const Arguments &args)
979{
980 if (args.Length()!=1)
981 return ThrowException(String::New("Number of arguments must be exactly 1."));
982
983 if (!args[0]->IsString())
984 return ThrowException(String::New("Argument 1 must be a string."));
985
986 //if (!args.IsConstructCall())
987 // return ThrowException(String::New("Must be used as constructor."));
988
989 HandleScope handle_scope;
990
991 const String::Utf8Value str(args[0]);
992
993 const auto it = fReverseMap.find(*str);
994 if (it!=fReverseMap.end())
995 return handle_scope.Close(it->second);
996
997 void *ptr = JsSubscribe(*str);
998 if (ptr==0)
999 return ThrowException(String::New(("Subscription to '"+string(*str)+"' already exists.").c_str()));
1000
1001 Handle<ObjectTemplate> tem = ObjectTemplate::New();
1002 tem->Set(String::New("get"), FunctionTemplate::New(WrapGetData), ReadOnly);
1003 tem->Set(String::New("close"), FunctionTemplate::New(WrapClose), ReadOnly);
1004 tem->Set(String::New("name"), String::New(*str), ReadOnly);
1005 tem->Set(String::New("isOpen"), Boolean::New(true));
1006 tem->SetInternalFieldCount(1);
1007 //tem->Set(String::New("toString"), String::New(("[object Dim "+string(*str)+"]").c_str()), ReadOnly);
1008
1009 Handle<Object> obj = tem->NewInstance();
1010 obj->SetInternalField(0, External::New(ptr));
1011
1012 fReverseMap[*str] = Persistent<Object>::New(obj);
1013
1014 return handle_scope.Close(obj);
1015
1016 // Persistent<Object> p = Persistent<Object>::New(obj->NewInstance());
1017 // obj.MakeWeak((void*)1, Cleanup);
1018 // return obj;
1019}
1020
1021// ==========================================================================
1022// Astrometry
1023// ==========================================================================
1024#ifdef HAVE_NOVA
1025
1026double InterpreterV8::GetDataMember(const Arguments &args, const char *name)
1027{
1028 return args.This()->Get(String::New(name))->NumberValue();
1029}
1030
1031Handle<Value> InterpreterV8::LocalToString(const Arguments &/*args*/)
1032{
1033 return String::New("[object Local]");
1034 /*
1035 HandleScope handle_scope;
1036
1037 const Handle<Object> This = args.This();
1038
1039 Handle<String> zd = This->Get(String::New("zd"))->ToString();
1040 Handle<String> az = This->Get(String::New("az"))->ToString();
1041
1042 return String::New("TEST");
1043 */
1044}
1045
1046Handle<Value> InterpreterV8::SkyToString(const Arguments &/*args*/)
1047{
1048 return String::New("[object Sky]");
1049}
1050
1051Handle<Value> InterpreterV8::MoonToString(const Arguments &/*args*/)
1052{
1053 return String::New("[object Moon]");
1054}
1055
1056Handle<Value> InterpreterV8::ConstructLocal(double zd, double az, Handle<Value> time)
1057{
1058 Handle<ObjectTemplate> loc = ObjectTemplate::New();
1059
1060 loc->Set(String::New("zd"), Number::New(zd), ReadOnly);
1061 loc->Set(String::New("az"), Number::New(az), ReadOnly);
1062 loc->Set(String::New("toSky"), FunctionTemplate::New(LocalToSky), ReadOnly);
1063 loc->Set(String::New("toString"), FunctionTemplate::New(LocalToString), ReadOnly);
1064 if (!time.IsEmpty())
1065 loc->Set(String::New("time"), time);
1066
1067 return loc->NewInstance();
1068}
1069
1070Handle<Value> InterpreterV8::ConstructSky(double ra, double dec, Handle<Value> time, bool ismoon)
1071{
1072 Handle<ObjectTemplate> sky = ObjectTemplate::New();
1073
1074 sky->Set(String::New("ra"), Number::New(ra), ReadOnly);
1075 sky->Set(String::New("dec"), Number::New(dec), ReadOnly);
1076 sky->Set(String::New("toLocal"), FunctionTemplate::New(ismoon?MoonToLocal :SkyToLocal), ReadOnly);
1077 sky->Set(String::New("toString"), FunctionTemplate::New(ismoon?MoonToString:SkyToString), ReadOnly);
1078 if (!time.IsEmpty())
1079 sky->Set(String::New("time"), time);
1080
1081 return sky->NewInstance();
1082}
1083
1084Handle<Value> InterpreterV8::LocalDist(const Arguments &args)
1085{
1086 HandleScope handle_scope;
1087
1088 if (args.Length()!=2)
1089 return ThrowException(String::New("dist must not be called with two arguments."));
1090
1091 if (!args[0]->IsObject() || !args[1]->IsObject())
1092 return ThrowException(String::New("at least one argument not an object."));
1093
1094 Handle<Object> obj[2] =
1095 {
1096 Handle<Object>::Cast(args[0]),
1097 Handle<Object>::Cast(args[1])
1098 };
1099
1100 const Handle<String> s_zd = String::New("zd");
1101 const Handle<String> s_az = String::New("az");
1102
1103 const double zd0 = obj[0]->Get(s_zd)->NumberValue() * M_PI/180;
1104 const double az0 = obj[0]->Get(s_az)->NumberValue() * M_PI/180;
1105 const double zd1 = obj[1]->Get(s_zd)->NumberValue() * M_PI/180;
1106 const double az1 = obj[1]->Get(s_az)->NumberValue() * M_PI/180;
1107
1108 if (!finite(zd0) || !finite(zd1) || !finite(az0) || !finite(az1))
1109 return ThrowException(String::New("some values not valid or not finite."));
1110
1111 /*
1112 const double x0 = sin(zd0) * cos(az0); // az0 -= az0
1113 const double y0 = sin(zd0) * sin(az0); // az0 -= az0
1114 const double z0 = cos(zd0);
1115
1116 const double x1 = sin(zd1) * cos(az1); // az1 -= az0
1117 const double y1 = sin(zd1) * sin(az1); // az1 -= az0
1118 const double z1 = cos(zd1);
1119
1120 const double res = acos(x0*x1 + y0*y1 + z0*z1) * 180/M_PI;
1121 */
1122
1123 // cos(az1-az0) = cos(az1)*cos(az0) + sin(az1)*sin(az0)
1124
1125 const double x = sin(zd0) * sin(zd1) * cos(az1-az0);
1126 const double y = cos(zd0) * cos(zd1);
1127
1128 const double res = acos(x + y) * 180/M_PI;
1129
1130 return handle_scope.Close(Number::New(res));
1131}
1132
1133Handle<Value> InterpreterV8::MoonDisk(const Arguments &args)
1134{
1135 HandleScope handle_scope;
1136
1137 if (args.Length()>1)
1138 return ThrowException(String::New("disk must not be called with more than one argument."));
1139
1140 const uint64_t v = uint64_t(args[0]->NumberValue());
1141 const Time utc = args.Length()==0 ? Time() : Time(v/1000, v%1000);
1142
1143 return handle_scope.Close(Number::New(ln_get_lunar_disk(utc.JD())));
1144}
1145
1146Handle<Value> InterpreterV8::LocalToSky(const Arguments &args)
1147{
1148 HandleScope handle_scope;
1149
1150 if (args.Length()>1)
1151 return ThrowException(String::New("toSky must not be called with more than one argument."));
1152
1153 ln_hrz_posn hrz;
1154 hrz.alt = 90-GetDataMember(args, "zd");
1155 hrz.az = GetDataMember(args, "az");
1156
1157 if (!finite(hrz.alt) || !finite(hrz.az))
1158 return ThrowException(String::New("zd and az must be finite."));
1159
1160 // It is important to catch the exception thrown
1161 // by Date::New in case of thread termination!
1162 TryCatch exception;
1163
1164 const Local<Value> date =
1165 args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
1166 if (exception.HasCaught())
1167 return exception.ReThrow();
1168
1169 const uint64_t v = uint64_t(args[0]->NumberValue());
1170 const Time utc(v/1000, v%1000);
1171
1172 ln_lnlat_posn obs;
1173 obs.lng = -(17.+53./60+26.525/3600);
1174 obs.lat = 28.+45./60+42.462/3600;
1175
1176 ln_equ_posn equ;
1177 ln_get_equ_from_hrz(&hrz, &obs, utc.JD(), &equ);
1178
1179 return handle_scope.Close(ConstructSky(equ.ra/15, equ.dec, date));
1180}
1181
1182Handle<Value> InterpreterV8::SkyToLocal(const Arguments &args)
1183{
1184 HandleScope handle_scope;
1185
1186 if (args.Length()>1)
1187 return ThrowException(String::New("toLocal must not be called with more than one argument."));
1188
1189 ln_equ_posn equ;
1190 equ.ra = GetDataMember(args, "ra")*15;
1191 equ.dec = GetDataMember(args, "dec");
1192
1193 if (!finite(equ.ra) || !finite(equ.dec))
1194 return ThrowException(String::New("Ra and dec must be finite."));
1195
1196 // It is important to catch the exception thrown
1197 // by Date::New in case of thread termination!
1198 TryCatch exception;
1199
1200 const Local<Value> date =
1201 args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
1202 if (exception.HasCaught())
1203 return exception.ReThrow();
1204
1205 const uint64_t v = uint64_t(args[0]->NumberValue());
1206 const Time utc(v/1000, v%1000);
1207
1208 ln_lnlat_posn obs;
1209 obs.lng = -(17.+53./60+26.525/3600);
1210 obs.lat = 28.+45./60+42.462/3600;
1211
1212 ln_hrz_posn hrz;
1213 ln_get_hrz_from_equ(&equ, &obs, utc.JD(), &hrz);
1214
1215 return handle_scope.Close(ConstructLocal(90-hrz.alt, hrz.az, date));
1216}
1217
1218Handle<Value> InterpreterV8::MoonToLocal(const Arguments &args)
1219{
1220 HandleScope handle_scope;
1221
1222 if (args.Length()>0)
1223 return ThrowException(String::New("toLocal must not be called with arguments."));
1224
1225 ln_equ_posn equ;
1226 equ.ra = GetDataMember(args, "ra")*15;
1227 equ.dec = GetDataMember(args, "dec");
1228
1229 if (!finite(equ.ra) || !finite(equ.dec))
1230 return ThrowException(String::New("ra and dec must be finite."));
1231
1232 // It is important to catch the exception thrown
1233 // by Date::New in case of thread termination!
1234 TryCatch exception;
1235
1236 const Local<Value> date =
1237 args.Length()==0 ? Date::New(Time().JavaDate()) : args.This()->Get(String::New("time"));
1238 if (exception.HasCaught())
1239 return exception.ReThrow();
1240
1241 const uint64_t v = uint64_t(args[0]->NumberValue());
1242 const Time utc(v/1000, v%1000);
1243
1244 ln_lnlat_posn obs;
1245 obs.lng = -(17.+53./60+26.525/3600);
1246 obs.lat = 28.+45./60+42.462/3600;
1247
1248 ln_hrz_posn hrz;
1249 ln_get_hrz_from_equ(&equ, &obs, utc.JD(), &hrz);
1250
1251 return handle_scope.Close(ConstructLocal(90-hrz.alt, hrz.az, date));
1252}
1253
1254Handle<Value> InterpreterV8::ConstructorMoon(const Arguments &args)
1255{
1256 HandleScope handle_scope;
1257
1258 if (args.Length()>1)
1259 return ThrowException(String::New("Moon constructor must not be called with more than one argument."));
1260
1261 // It is important to catch the exception thrown
1262 // by Date::New in case of thread termination!
1263 TryCatch exception;
1264
1265 const Local<Value> date =
1266 args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
1267 if (exception.HasCaught())
1268 return exception.ReThrow();
1269
1270 const uint64_t v = uint64_t(args[0]->NumberValue());
1271 const Time utc(v/1000, v%1000);
1272
1273 ln_equ_posn equ;
1274 ln_get_lunar_equ_coords_prec(utc.JD(), &equ, 0.01);
1275
1276 return handle_scope.Close(ConstructSky(equ.ra/15, equ.dec, date, true));
1277}
1278
1279Handle<Value> InterpreterV8::ConstructorSky(const Arguments &args)
1280{
1281 HandleScope handle_scope;
1282
1283 if (args.Length()!=2)
1284 return ThrowException(String::New("Sky constructor takes two arguments."));
1285
1286 const double ra = args[0]->NumberValue();
1287 const double dec = args[1]->NumberValue();
1288
1289 if (!finite(ra) || !finite(dec))
1290 return ThrowException(String::New("Both arguments to Sky must be valid numbers."));
1291
1292 return handle_scope.Close(ConstructSky(ra, dec));
1293}
1294
1295Handle<Value> InterpreterV8::ConstructorLocal(const Arguments &args)
1296{
1297 HandleScope handle_scope;
1298
1299 if (args.Length()!=2)
1300 return ThrowException(String::New("Local constructor takes two arguments."));
1301
1302 const double zd = args[0]->NumberValue();
1303 const double az = args[1]->NumberValue();
1304
1305 if (!finite(zd) || !finite(az))
1306 return ThrowException(String::New("Both arguments to Local must be valid numbers."));
1307
1308 return handle_scope.Close(ConstructLocal(zd, az));
1309}
1310#endif
1311
1312// ==========================================================================
1313// Process control
1314// ==========================================================================
1315
1316bool InterpreterV8::ReportException(TryCatch* try_catch)
1317{
1318 if (!try_catch->CanContinue())
1319 return false;
1320
1321 const HandleScope handle_scope;
1322
1323 const String::Utf8Value exception(try_catch->Exception());
1324
1325 if (*exception && string(*exception)=="exit")
1326 return true;
1327 if (*exception && string(*exception)=="null")
1328 return false;
1329
1330 const Handle<Message> message = try_catch->Message();
1331 if (message.IsEmpty())
1332 return false;
1333
1334 // Print (filename):(line number): (message).
1335 const String::Utf8Value filename(message->GetScriptResourceName());
1336
1337 ostringstream out;
1338
1339 if (*filename)
1340 out << *filename << ": ";
1341 out << "l." << message->GetLineNumber();
1342 if (*exception)
1343 out << ": " << *exception;
1344
1345 JsException(out.str());
1346
1347 // Print line of source code.
1348 const String::Utf8Value sourceline(message->GetSourceLine());
1349 if (*sourceline)
1350 JsException(*sourceline);
1351
1352 // Print wavy underline (GetUnderline is deprecated).
1353 const int start = message->GetStartColumn();
1354 const int end = message->GetEndColumn();
1355
1356 out.str("");
1357 if (start>0)
1358 out << setfill(' ') << setw(start) << ' ';
1359 out << setfill('^') << setw(end-start) << '^';
1360
1361 JsException(out.str());
1362
1363 String::Utf8Value stack_trace(try_catch->StackTrace());
1364 if (stack_trace.length()<=0)
1365 return false;
1366
1367 //if (*stack_trace)
1368 // JsException(string("\n")+*stack_trace);
1369
1370 return false;
1371}
1372
1373// Executes a string within the current v8 context.
1374bool InterpreterV8::ExecuteStringNT(const Handle<String> &code, const Handle<Value> &file)
1375{
1376 if (code.IsEmpty())
1377 return true;
1378
1379 const HandleScope handle_scope;
1380
1381 const Handle<Script> script = Script::Compile(code, file);
1382 if (script.IsEmpty())
1383 return false;
1384
1385 JsSetState(3);
1386
1387 const Handle<Value> result = script->Run();
1388 if (result.IsEmpty())
1389 return false;
1390
1391 // If all went well and the result wasn't undefined then print
1392 // the returned value.
1393 if (!result->IsUndefined())
1394 JsResult(*String::Utf8Value(result));
1395
1396 return true;
1397}
1398
1399bool InterpreterV8::ExecuteCode(const Handle<String> &code, const Handle<Value> &file)
1400{
1401 TryCatch exception;
1402
1403 const bool rc = ExecuteStringNT(code, file);
1404
1405 // Check if this is a termination exception
1406 //if (!exception.CanContinue())
1407 // return false;
1408
1409 if (exception.HasCaught())
1410 return ReportException(&exception);
1411
1412 return rc;
1413}
1414
1415bool InterpreterV8::ExecuteCode(const string &code, const string &file)
1416{
1417 return ExecuteCode(String::New(code.c_str(), code.size()),
1418 String::New(file.c_str()));
1419}
1420
1421bool InterpreterV8::ExecuteFile(const string &name)
1422{
1423 ifstream fin(name.c_str());
1424 if (!fin)
1425 {
1426 JsException("Error - Could not open file '"+name+"'");
1427 return false;
1428 }
1429
1430 string buffer;
1431 if (!getline(fin, buffer, '\0'))
1432 return true;
1433
1434 if (fin.fail())
1435 {
1436 JsException("Error - reading file.");
1437 return false;
1438 }
1439
1440 return ExecuteCode(buffer, name);
1441}
1442
1443// ==========================================================================
1444// CORE
1445// ==========================================================================
1446
1447bool InterpreterV8::JsRun(const string &filename, const map<string, string> &map)
1448{
1449 Locker locker;
1450 fThreadId = V8::GetCurrentThreadId();
1451
1452 JsPrint(string("JavaScript Engine V8 ")+V8::GetVersion());
1453
1454 JsLoad(filename);
1455
1456 HandleScope handle_scope;
1457
1458 // Create a template for the global object.
1459 Handle<ObjectTemplate> dim = ObjectTemplate::New();
1460 dim->Set(String::New("print"), FunctionTemplate::New(WrapPrint), ReadOnly);
1461 dim->Set(String::New("alarm"), FunctionTemplate::New(WrapAlarm), ReadOnly);
1462 dim->Set(String::New("out"), FunctionTemplate::New(WrapOut), ReadOnly);
1463 dim->Set(String::New("wait"), FunctionTemplate::New(WrapWait), ReadOnly);
1464 dim->Set(String::New("send"), FunctionTemplate::New(WrapSend), ReadOnly);
1465 dim->Set(String::New("state"), FunctionTemplate::New(WrapState), ReadOnly);
1466 dim->Set(String::New("newState"), FunctionTemplate::New(WrapNewState), ReadOnly);
1467 dim->Set(String::New("setState"), FunctionTemplate::New(WrapSetState), ReadOnly);
1468 dim->Set(String::New("sleep"), FunctionTemplate::New(WrapSleep), ReadOnly);
1469 dim->Set(String::New("subscribe"), FunctionTemplate::New(WrapSubscribe), ReadOnly);
1470 dim->Set(String::New("database"), FunctionTemplate::New(WrapDatabase), ReadOnly);
1471
1472 Handle<ObjectTemplate> onchange = ObjectTemplate::New();
1473 onchange->SetNamedPropertyHandler(OnChangeGet, WrapOnChangeSet);
1474 dim->Set(v8::String::New("onchange"), onchange);
1475
1476 Handle<ObjectTemplate> global = ObjectTemplate::New();
1477 global->Set(String::New("dim"), dim, ReadOnly);
1478 global->Set(String::New("include"), FunctionTemplate::New(WrapInclude), ReadOnly);
1479 global->Set(String::New("exit"), FunctionTemplate::New(WrapExit), ReadOnly);
1480 global->Set(String::New("version"), FunctionTemplate::New(InterpreterV8::FuncVersion), ReadOnly);
1481
1482#ifdef HAVE_NOVA
1483 Handle<FunctionTemplate> sky = FunctionTemplate::New(ConstructorSky);
1484 global->Set(String::New("Sky"), sky, ReadOnly);
1485
1486 Handle<FunctionTemplate> loc = FunctionTemplate::New(ConstructorLocal);
1487 loc->Set(String::New("dist"), FunctionTemplate::New(LocalDist), ReadOnly);
1488 global->Set(String::New("Local"), loc, ReadOnly);
1489
1490 Handle<FunctionTemplate> moon = FunctionTemplate::New(ConstructorMoon);
1491 moon->Set(String::New("disk"), FunctionTemplate::New(MoonDisk), ReadOnly);
1492 global->Set(String::New("Moon"), moon, ReadOnly);
1493#endif
1494
1495 // Persistent
1496 Persistent<Context> context = Context::New(NULL, global);
1497 if (context.IsEmpty())
1498 {
1499 //printf("Error creating context\n");
1500 return false;
1501 }
1502
1503 Context::Scope scope(context);
1504
1505 Handle<Array> args = Array::New(map.size());
1506 for (auto it=map.begin(); it!=map.end(); it++)
1507 args->Set(String::New(it->first.c_str()), String::New(it->second.c_str()));
1508 context->Global()->Set(String::New("$"), args, ReadOnly);
1509 context->Global()->Set(String::New("arg"), args, ReadOnly);
1510
1511 JsStart(filename);
1512
1513 //context->Enter();
1514 Locker::StartPreemption(10);
1515 const bool rc = ExecuteFile(filename);
1516
1517 // -----
1518 // This is how an exit handler could look like, but there is no way to interrupt it
1519 // -----
1520 // Handle<Object> obj = Handle<Object>::Cast(context->Global()->Get(String::New("dim")));
1521 // if (!obj.IsEmpty())
1522 // {
1523 // Handle<Value> onexit = obj->Get(String::New("onexit"));
1524 // if (!onexit->IsUndefined())
1525 // Handle<Function>::Cast(onexit)->NewInstance(0, NULL); // argc, argv
1526 // // Handle<Object> result = Handle<Function>::Cast(onexit)->NewInstance(0, NULL); // argc, argv
1527 // }
1528
1529 Locker::StopPreemption();
1530 //context->Exit();
1531
1532 for (auto it=fStateCallbacks.begin(); it!=fStateCallbacks.end(); it++)
1533 it->second.Dispose();
1534 fStateCallbacks.clear();
1535
1536 for (auto it=fReverseMap.begin(); it!=fReverseMap.end(); it++)
1537 it->second.Dispose();
1538 fReverseMap.clear();
1539
1540 context.Dispose();
1541
1542#ifdef HAVE_SQL
1543 for (auto it=fDatabases.begin(); it!=fDatabases.end(); it++)
1544 delete *it;
1545 fDatabases.clear();
1546#endif
1547
1548 JsEnd(filename);
1549
1550 return rc;
1551}
1552
1553void InterpreterV8::JsStop()
1554{
1555 Locker locker;
1556
1557 //cout << "Terminate " << fThreadId << endl;
1558 if (This->fThreadId>=0)
1559 V8::TerminateExecution(This->fThreadId);
1560 //cout << "Terminate " << fThreadId << endl;
1561
1562 //Unlocker unlocker;
1563}
1564
1565#endif
1566
1567
1568
1569
1570
Note: See TracBrowser for help on using the repository browser.