RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* bid_request_js.cc 00002 Jeremy Barnes, 6 April 2011 00003 Copyright (c) 2011 Datacratic. All rights reserved. 00004 00005 Bid Request. 00006 */ 00007 00008 00009 #include "bid_request_js.h" 00010 #include "soa/js/js_wrapped.h" 00011 #include "jml/utils/smart_ptr_utils.h" 00012 #include "soa/types/js/id_js.h" 00013 #include "soa/types/js/url_js.h" 00014 #include "currency_js.h" 00015 #include <boost/make_shared.hpp> 00016 #include <boost/algorithm/string/trim.hpp> 00017 #include "rtbkit/openrtb/openrtb_parsing.h" 00018 00019 00020 using namespace std; 00021 using namespace v8; 00022 using namespace node; 00023 00024 namespace Datacratic { 00025 00026 struct JSConverters { 00027 std::function<void (void *, const JS::JSValue &)> fromJs; 00028 std::function<v8::Handle<v8::Value> (const void *, std::shared_ptr<void>)> toJs; 00029 }; 00030 00031 namespace JS { 00032 00033 00034 const char * const bidRequestModule = "bid_request"; 00035 //so we can do require("standalone_demo") 00036 00037 void to_js(JS::JSValue & value, const Format & f) 00038 { 00039 value = JS::toJS(f.print()); 00040 } 00041 00042 00043 /*****************************************************************************/ 00044 /* SEGMENT LIST JS */ 00045 /*****************************************************************************/ 00046 00047 const char * SegmentListName = "SegmentList"; 00048 00049 struct SegmentListJS 00050 : public JSWrapped2<SegmentList, SegmentListJS, SegmentListName, 00051 bidRequestModule> { 00052 00053 SegmentListJS(v8::Handle<v8::Object> This, 00054 const std::shared_ptr<SegmentList> & list 00055 = std::shared_ptr<SegmentList>()) 00056 { 00057 HandleScope scope; 00058 wrap(This, list); 00059 } 00060 00061 static Handle<v8::Value> 00062 New(const Arguments & args) 00063 { 00064 try { 00065 if (args.Length() == 0) { 00066 new SegmentListJS(args.This(), 00067 std::make_shared<SegmentList>()); 00068 return args.This(); 00069 } 00070 else { 00071 if (SegmentListJS::tmpl->HasInstance(args[0])) { 00072 throw ML::Exception("segment list from segment list"); 00073 //new SegmentListJS(args.This(), 00074 // std::make_shared<SegmentList> 00075 // (*SegmentListJS::fromJS(args[0]))); 00076 return args.This(); 00077 } 00078 00079 Json::Value valInJson = JS::fromJS(args[0]); 00080 new SegmentListJS(args.This(), 00081 std::make_shared<SegmentList> 00082 (SegmentList::createFromJson(valInJson))); 00083 return args.This(); 00084 } 00085 } HANDLE_JS_EXCEPTIONS; 00086 } 00087 00088 static void 00089 Initialize() 00090 { 00091 Persistent<FunctionTemplate> t = Register(New); 00092 NODE_SET_PROTOTYPE_METHOD(t, "forEach", forEach); 00093 NODE_SET_PROTOTYPE_METHOD(t, "add", add); 00094 NODE_SET_PROTOTYPE_METHOD(t, "toArray", toArray); 00095 NODE_SET_PROTOTYPE_METHOD(t, "toString", toString); 00096 NODE_SET_PROTOTYPE_METHOD(t, "inspect", toString); 00097 00098 registerMemberFn(&SegmentList::toJson, "toJSON"); 00099 00100 t->InstanceTemplate() 00101 ->SetAccessor(String::NewSymbol("length"), lengthGetter, 00102 0, v8::Handle<v8::Value>(), DEFAULT, 00103 PropertyAttribute(ReadOnly | DontEnum | DontDelete)); 00104 00105 t->InstanceTemplate() 00106 ->SetIndexedPropertyHandler(getIndexed, setIndexed, queryIndexed, 00107 deleteIndexed, listIndexed); 00108 } 00109 00110 static v8::Handle<v8::Value> 00111 add(const Arguments & args) 00112 { 00113 try { 00114 auto segs = getShared(args.This()); 00115 segs->add(getArg<string>(args, 0, "segment")); 00116 segs->sort(); 00117 return args.This(); 00118 } HANDLE_JS_EXCEPTIONS; 00119 } 00120 00121 static v8::Handle<v8::Value> 00122 forEach(const Arguments & args) 00123 { 00124 HandleScope scope; 00125 try { 00126 auto segs = getShared(args.This()); 00127 00128 v8::Local<v8::Function> fn = getArg(args, 0, "iterFunction"); 00129 00130 for (unsigned index = 0; index < segs->size(); ++index) { 00131 HandleScope scope; 00132 JSValue value; 00133 00134 if (index < segs->ints.size()) 00135 value = JS::toJS(segs->ints[index]); 00136 else if (index - segs->ints.size() < segs->strings.size()) 00137 value = JS::toJS(segs->strings[index - segs->ints.size()]); 00138 else throw ML::Exception("logic error in forEach"); 00139 00140 // Argument 1: value 00141 // Argument 2: index number 00142 int argc = 2; 00143 v8::Handle<v8::Value> argv[argc]; 00144 00145 argv[0] = value; 00146 argv[1] = v8::Uint32::New(index); 00147 00148 v8::Handle<v8::Value> result 00149 = fn->Call(args.This(), argc, argv); 00150 00151 // Exception? 00152 if (result.IsEmpty()) 00153 return scope.Close(result); 00154 00155 if (index == segs->size() - 1 && !result->IsUndefined()) 00156 return scope.Close(result); 00157 } 00158 00159 return v8::Undefined(); 00160 } HANDLE_JS_EXCEPTIONS; 00161 } 00162 00163 static v8::Handle<v8::Value> 00164 getIndexed(uint32_t index, const v8::AccessorInfo & info) 00165 { 00166 try { 00167 auto segs = getShared(info.This()); 00168 00169 if (index < segs->ints.size()) 00170 return JS::toJS(segs->ints[index]); 00171 else if (index - segs->ints.size() < segs->strings.size()) 00172 return JS::toJS(segs->strings[index - segs->ints.size()]); 00173 else return v8::Undefined(); 00174 } HANDLE_JS_EXCEPTIONS; 00175 } 00176 00177 static v8::Handle<v8::Value> 00178 setIndexed(uint32_t index, 00179 v8::Local<v8::Value> value, 00180 const v8::AccessorInfo & info) 00181 { 00182 try { 00183 throw ML::Exception("can't modify segments argument"); 00184 } HANDLE_JS_EXCEPTIONS; 00185 } 00186 00187 static v8::Handle<v8::Integer> 00188 queryIndexed(uint32_t index, 00189 const v8::AccessorInfo & info) 00190 { 00191 auto segs = getShared(info.This()); 00192 int sz = segs->size(); 00193 00194 if (index <= sz) 00195 return v8::Integer::New(ReadOnly | DontDelete); 00196 00197 return NULL_HANDLE; 00198 } 00199 00200 static v8::Handle<v8::Array> 00201 listIndexed(const v8::AccessorInfo & info) 00202 { 00203 v8::HandleScope scope; 00204 auto segs = getShared(info.This()); 00205 int sz = segs->size(); 00206 00207 v8::Handle<v8::Array> result(v8::Array::New(sz)); 00208 00209 for (unsigned i = 0; i < sz; ++i) { 00210 result->Set(v8::Uint32::New(i), 00211 v8::Uint32::New(i)); 00212 } 00213 00214 return scope.Close(result); 00215 } 00216 00217 static v8::Handle<v8::Boolean> 00218 deleteIndexed(uint32_t index, 00219 const v8::AccessorInfo & info) 00220 { 00221 return NULL_HANDLE; 00222 } 00223 00224 static v8::Handle<v8::Value> 00225 toArray(const v8::Arguments & args) 00226 { 00227 try { 00228 v8::HandleScope scope; 00229 auto segs = getShared(args.This()); 00230 int sz = segs->size(); 00231 00232 v8::Handle<v8::Array> result(v8::Array::New(sz)); 00233 00234 for (unsigned i = 0; i < segs->ints.size(); ++i) { 00235 result->Set(v8::Uint32::New(i), 00236 v8::Uint32::New(segs->ints[i])); 00237 } 00238 for (unsigned i = 0; i < segs->strings.size(); ++i) { 00239 result->Set(v8::Uint32::New(i + segs->ints.size()), 00240 JS::toJS(segs->strings[i])); 00241 } 00242 00243 return scope.Close(result); 00244 } HANDLE_JS_EXCEPTIONS; 00245 } 00246 00247 static v8::Handle<v8::Value> 00248 toString(const v8::Arguments & args) 00249 { 00250 try { 00251 auto segs = getShared(args.This()); 00252 return JS::toJS(boost::trim_copy(segs->toJson().toString())); 00253 } HANDLE_JS_EXCEPTIONS; 00254 } 00255 00256 static v8::Handle<v8::Value> 00257 lengthGetter(v8::Local<v8::String> property, 00258 const AccessorInfo & info) 00259 { 00260 try { 00261 return v8::Integer::New(getShared(info.This())->size()); 00262 } HANDLE_JS_EXCEPTIONS; 00263 } 00264 }; 00265 00266 std::shared_ptr<SegmentList> 00267 from_js(const JSValue & value, std::shared_ptr<SegmentList> *) 00268 { 00269 if (SegmentListJS::tmpl->HasInstance(value)) 00270 return SegmentListJS::fromJS(value); 00271 00272 vector<string> values; 00273 JS::from_js(value, &values); 00274 return std::make_shared<SegmentList>(values); 00275 } 00276 00277 SegmentList * 00278 from_js(const JSValue & value, SegmentList **) 00279 { 00280 return SegmentListJS::fromJS(value).get(); 00281 } 00282 00283 std::shared_ptr<SegmentList> 00284 from_js_ref(const JSValue & value, std::shared_ptr<SegmentList> *) 00285 { 00286 return SegmentListJS::fromJS(value); 00287 } 00288 00289 void to_js(JS::JSValue & value, const std::shared_ptr<SegmentList> & br) 00290 { 00291 value = SegmentListJS::toJS(br); 00292 } 00293 00294 SegmentList 00295 from_js(const JSValue & value, SegmentList *) 00296 { 00297 if (SegmentListJS::tmpl->HasInstance(value)) 00298 return *SegmentListJS::fromJS(value); 00299 Json::Value valInJson = JS::fromJS(value); 00300 SegmentList result = SegmentList::createFromJson(valInJson); 00301 return result; 00302 } 00303 00304 void to_js(JS::JSValue & value, const UserIds & uids) 00305 { 00306 to_js(value, static_cast<const std::map<std::string, Id> &>(uids)); 00307 } 00308 00309 UserIds 00310 from_js(const JSValue & value, UserIds *) 00311 { 00312 UserIds result; 00313 static_cast<std::map<std::string, Id> &>(result) 00314 = from_js(value, (std::map<std::string, Id> *)0); 00315 return result; 00316 } 00317 00318 00319 /*****************************************************************************/ 00320 /* SEGMENTS BY SOURCE JS */ 00321 /*****************************************************************************/ 00322 00323 const char * SegmentsBySourceName = "SegmentsBySource"; 00324 00325 struct SegmentsBySourceJS 00326 : public JSWrapped2<SegmentsBySource, SegmentsBySourceJS, 00327 SegmentsBySourceName, 00328 bidRequestModule> { 00329 00330 SegmentsBySourceJS(v8::Handle<v8::Object> This, 00331 const std::shared_ptr<SegmentsBySource> & list 00332 = std::shared_ptr<SegmentsBySource>()) 00333 { 00334 HandleScope scope; 00335 wrap(This, list); 00336 } 00337 00338 static Handle<v8::Value> 00339 New(const Arguments & args) 00340 { 00341 try { 00342 new SegmentsBySourceJS(args.This(), 00343 std::make_shared<SegmentsBySource>()); 00344 return args.This(); 00345 } HANDLE_JS_EXCEPTIONS; 00346 } 00347 00348 static void 00349 Initialize() 00350 { 00351 Persistent<FunctionTemplate> t = Register(New); 00352 00353 t->InstanceTemplate() 00354 ->SetNamedPropertyHandler(getNamed, setNamed, queryNamed, 00355 deleteNamed, listNamed); 00356 00357 } 00358 00359 static v8::Handle<v8::Value> 00360 getNamed(v8::Local<v8::String> property, 00361 const v8::AccessorInfo & info) 00362 { 00363 HandleScope scope; 00364 try { 00365 Local<v8::Value> object_prop 00366 = info.This()->GetRealNamedProperty(property); 00367 if (!object_prop.IsEmpty()) 00368 return scope.Close(object_prop); 00369 00370 // Is it a column name? 00371 string name = cstr(property); 00372 00373 SegmentsBySource * segs = getShared(info.This()); 00374 00375 if (!segs->count(name)) 00376 return NULL_HANDLE; 00377 00378 return scope.Close(JS::toJS(segs->find(name)->second)); 00379 } HANDLE_JS_EXCEPTIONS; 00380 } 00381 00382 static v8::Handle<v8::Value> 00383 setNamed(v8::Local<v8::String> property, 00384 v8::Local<v8::Value> value, 00385 const v8::AccessorInfo & info) 00386 { 00387 try { 00388 if (info.This()->HasRealNamedProperty(property)) { 00389 if (info.This()->Set(property, value)) 00390 return value; 00391 } 00392 00393 // Is it a column name? 00394 string name = cstr(property); 00395 SegmentsBySource * segs = getShared(info.This()); 00396 00397 // Is the value sensible? 00398 if (value->IsNull() || value->IsUndefined()) { 00399 throw ML::Exception("can't set named to undefined"); 00400 } 00401 00402 std::shared_ptr<SegmentList> segs2 00403 = from_js(value, &segs2); 00404 00405 if (!segs2) 00406 throw ML::Exception("can't set to null segments"); 00407 00408 (*segs)[name] = segs2; 00409 00410 return v8::Undefined(); 00411 } HANDLE_JS_EXCEPTIONS; 00412 } 00413 00414 static v8::Handle<v8::Integer> 00415 queryNamed(v8::Local<v8::String> property, 00416 const v8::AccessorInfo & info) 00417 { 00418 if (property.IsEmpty() || property->IsNull() 00419 || property->IsUndefined()) 00420 throw ML::Exception("queryNamed: invalid property"); 00421 00422 string name = cstr(property); 00423 00424 SegmentsBySource * segs = getShared(info.This()); 00425 00426 if (segs->count(name)) 00427 return v8::Integer::New(DontDelete); 00428 00429 return NULL_HANDLE; 00430 } 00431 00432 static v8::Handle<v8::Boolean> 00433 deleteNamed(v8::Local<v8::String> property, 00434 const v8::AccessorInfo & info) 00435 00436 { 00437 if (property.IsEmpty() || property->IsNull() 00438 || property->IsUndefined()) 00439 throw ML::Exception("queryNamed: invalid property"); 00440 00441 string name = cstr(property); 00442 00443 SegmentsBySource * segs = getShared(info.This()); 00444 00445 return v8::Boolean::New(segs->erase(name)); 00446 } 00447 00448 static v8::Handle<v8::Array> 00449 listNamed(const v8::AccessorInfo & info) 00450 { 00451 //cerr << "listNamed" << endl; 00452 HandleScope scope; 00453 try { 00454 SegmentsBySource * segs = getShared(info.This()); 00455 00456 int n = segs->size(); 00457 00458 v8::Handle<v8::Array> result = v8::Array::New(n); 00459 00460 //cerr << "listNamed: " << ncol << " columns" << endl; 00461 00462 unsigned i = 0; 00463 for (auto it = segs->begin(), end = segs->end(); 00464 it != end; ++it,++i) { 00465 v8::Local<Integer> key = v8::Integer::New(i); 00466 v8::Handle<Value> val = JS::toJS(it->first); 00467 result->Set(key, val); 00468 } 00469 00470 return scope.Close(result); 00471 } catch (...) { 00472 cerr << "got exception in listNamed" << endl; 00473 return NULL_HANDLE; 00474 } 00475 } 00476 }; 00477 00478 00479 /*****************************************************************************/ 00480 /* USER IDS JS */ 00481 /*****************************************************************************/ 00482 00483 const char * UserIdsName = "UserIds"; 00484 00485 struct UserIdsJS 00486 : public JSWrapped2<UserIds, UserIdsJS, 00487 UserIdsName, 00488 bidRequestModule> { 00489 00490 UserIdsJS(v8::Handle<v8::Object> This, 00491 const std::shared_ptr<UserIds> & list 00492 = std::shared_ptr<UserIds>()) 00493 { 00494 HandleScope scope; 00495 wrap(This, list); 00496 } 00497 00498 static Handle<v8::Value> 00499 New(const Arguments & args) 00500 { 00501 try { 00502 new UserIdsJS(args.This(), 00503 std::make_shared<UserIds>()); 00504 return args.This(); 00505 } HANDLE_JS_EXCEPTIONS; 00506 } 00507 00508 static void 00509 Initialize() 00510 { 00511 Persistent<FunctionTemplate> t = Register(New); 00512 00513 t->InstanceTemplate() 00514 ->SetNamedPropertyHandler(getNamed, setNamed, queryNamed, 00515 deleteNamed, listNamed); 00516 } 00517 00518 static v8::Handle<v8::Value> 00519 getNamed(v8::Local<v8::String> property, 00520 const v8::AccessorInfo & info) 00521 { 00522 HandleScope scope; 00523 try { 00524 Local<v8::Value> object_prop 00525 = info.This()->GetRealNamedProperty(property); 00526 if (!object_prop.IsEmpty()) 00527 return scope.Close(object_prop); 00528 00529 // Is it a column name? 00530 string name = cstr(property); 00531 00532 UserIds * ids = getShared(info.This()); 00533 00534 if (!ids->count(name)) 00535 return NULL_HANDLE; 00536 00537 return scope.Close(JS::toJS(ids->find(name)->second)); 00538 } HANDLE_JS_EXCEPTIONS; 00539 } 00540 00541 static v8::Handle<v8::Value> 00542 setNamed(v8::Local<v8::String> property, 00543 v8::Local<v8::Value> value, 00544 const v8::AccessorInfo & info) 00545 { 00546 try { 00547 if (info.This()->HasRealNamedProperty(property)) { 00548 if (info.This()->Set(property, value)) 00549 return value; 00550 } 00551 00552 // Is it a column name? 00553 string name = cstr(property); 00554 UserIds * ids = getShared(info.This()); 00555 00556 // Is the value sensible? 00557 if (value->IsNull() || value->IsUndefined()) { 00558 throw ML::Exception("can't set named to undefined"); 00559 } 00560 00561 Id id = from_js(value, &id); 00562 00563 if (!id) 00564 throw ML::Exception("can't set to null ID"); 00565 00566 ids->set(id, name); 00567 00568 return v8::Undefined(); 00569 } HANDLE_JS_EXCEPTIONS; 00570 } 00571 00572 static v8::Handle<v8::Integer> 00573 queryNamed(v8::Local<v8::String> property, 00574 const v8::AccessorInfo & info) 00575 { 00576 if (property.IsEmpty() || property->IsNull() 00577 || property->IsUndefined()) 00578 throw ML::Exception("queryNamed: invalid property"); 00579 00580 string name = cstr(property); 00581 00582 UserIds * ids = getShared(info.This()); 00583 00584 if (ids->count(name)) 00585 return v8::Integer::New(DontDelete); 00586 00587 return NULL_HANDLE; 00588 } 00589 00590 static v8::Handle<v8::Boolean> 00591 deleteNamed(v8::Local<v8::String> property, 00592 const v8::AccessorInfo & info) 00593 00594 { 00595 if (property.IsEmpty() || property->IsNull() 00596 || property->IsUndefined()) 00597 throw ML::Exception("queryNamed: invalid property"); 00598 00599 string name = cstr(property); 00600 00601 UserIds * ids = getShared(info.This()); 00602 00603 return v8::Boolean::New(ids->erase(name)); 00604 } 00605 00606 static v8::Handle<v8::Array> 00607 listNamed(const v8::AccessorInfo & info) 00608 { 00609 //cerr << "listNamed" << endl; 00610 HandleScope scope; 00611 try { 00612 UserIds * ids = getShared(info.This()); 00613 00614 int n = ids->size(); 00615 00616 v8::Handle<v8::Array> result = v8::Array::New(n); 00617 00618 //cerr << "listNamed: " << ncol << " columns" << endl; 00619 00620 unsigned i = 0; 00621 for (auto it = ids->begin(), end = ids->end(); 00622 it != end; ++it,++i) { 00623 v8::Local<Integer> key = v8::Integer::New(i); 00624 v8::Handle<Value> val = JS::toJS(it->first); 00625 result->Set(key, val); 00626 } 00627 00628 return scope.Close(result); 00629 } catch (...) { 00630 cerr << "got exception in listNamed" << endl; 00631 return NULL_HANDLE; 00632 } 00633 } 00634 }; 00635 00636 00637 /*****************************************************************************/ 00638 /* LOCATION JS */ 00639 /*****************************************************************************/ 00640 00641 const char * LocationName = "Location"; 00642 00643 struct LocationJS 00644 : public JSWrapped2<Location, LocationJS, 00645 LocationName, 00646 bidRequestModule> { 00647 00648 LocationJS(v8::Handle<v8::Object> This, 00649 const std::shared_ptr<Location> & list 00650 = std::shared_ptr<Location>()) 00651 { 00652 HandleScope scope; 00653 wrap(This, list); 00654 } 00655 00656 static Handle<v8::Value> 00657 New(const Arguments & args) 00658 { 00659 try { 00660 new LocationJS(args.This(), 00661 std::make_shared<Location>()); 00662 return args.This(); 00663 } HANDLE_JS_EXCEPTIONS; 00664 } 00665 00666 static void 00667 Initialize() 00668 { 00669 Persistent<FunctionTemplate> t = Register(New); 00670 registerRWProperty(&Location::countryCode, "countryCode"); 00671 registerRWProperty(&Location::regionCode, "regionCode"); 00672 registerRWProperty(&Location::cityName, "cityName"); 00673 registerRWProperty(&Location::dma, "dma"); 00674 registerRWProperty(&Location::timezoneOffsetMinutes, 00675 "timezoneOffsetMinutes"); 00676 registerMemberFn(&Location::toJson, "toJSON"); 00677 registerMemberFn(&Location::fullLocationString, 00678 "fullLocationString"); 00679 } 00680 }; 00681 00682 // To/from JS goes via JSON for the moment... 00683 template<typename Obj, typename Base> 00684 struct PropertyAccessViaJson { 00685 static v8::Handle<v8::Value> 00686 getter(v8::Local<v8::String> property, 00687 const v8::AccessorInfo & info) 00688 { 00689 try { 00690 const ValueDescription * vd 00691 = reinterpret_cast<const ValueDescription *> 00692 (v8::External::Unwrap(info.Data())); 00693 Obj * o = Base::getShared(info.This()); 00694 const StructureDescriptionBase::FieldDescription & fd 00695 = vd->getField(cstr(property)); 00696 StructuredJsonPrintingContext context; 00697 fd.description->printJson(addOffset(o, fd.offset), context); 00698 return JS::toJS(context.output); 00699 } HANDLE_JS_EXCEPTIONS; 00700 } 00701 00702 static void 00703 setter(v8::Local<v8::String> property, 00704 v8::Local<v8::Value> value, 00705 const v8::AccessorInfo & info) 00706 { 00707 try { 00708 const ValueDescription * vd 00709 = reinterpret_cast<const ValueDescription *> 00710 (v8::External::Unwrap(info.Data())); 00711 Obj * o = Base::getShared(info.This()); 00712 const StructureDescriptionBase::FieldDescription & fd 00713 = vd->getField(cstr(property)); 00714 Json::Value val = JS::fromJS(JSValue(value)); 00715 StructuredJsonParsingContext context(val); 00716 fd.description->parseJson(addOffset(o, fd.offset), context); 00717 } HANDLE_JS_EXCEPTIONS_SETTER; 00718 } 00719 }; 00720 00721 #if 0 00722 struct WrappedStructureJS: public JS::JSWrapped { 00723 const ValueDescription * desc; 00724 }; 00725 #endif 00726 00727 void 00728 setFromJs(void * field, 00729 const JSValue & value, 00730 const ValueDescription & desc); 00731 00732 v8::Handle<v8::Value> 00733 getFromJs(const void * field, 00734 const ValueDescription & desc, 00735 const std::shared_ptr<void> & owner); 00736 00737 struct WrappedArrayJS: public JSWrappedBase { 00738 const ValueDescription * desc; 00739 void * value; // value being read 00740 00741 static v8::Persistent<v8::FunctionTemplate> tmpl; 00742 00743 WrappedArrayJS(v8::Handle<v8::Object> This, 00744 void * value = 0, 00745 std::shared_ptr<void> owner = nullptr) 00746 { 00747 wrap(This, 64 /* bytes */, typeid(*this)); 00748 this->value = value; 00749 this->owner_ = owner; 00750 } 00751 00752 static Handle<v8::Value> 00753 New(const Arguments & args) 00754 { 00755 try { 00756 new WrappedArrayJS(args.This(), nullptr); 00757 return args.This(); 00758 } HANDLE_JS_EXCEPTIONS; 00759 } 00760 00761 static void Initialize() 00762 { 00763 tmpl = RegisterBase("WrappedArrayJS", "bonus", New); 00764 00765 tmpl->InstanceTemplate() 00766 ->SetIndexedPropertyHandler(getIndexed, setIndexed, queryIndexed, 00767 deleteIndexed, listIndexed); 00768 00769 tmpl->InstanceTemplate() 00770 ->SetAccessor(String::NewSymbol("length"), lengthGetter, 00771 0, v8::Handle<v8::Value>(), DEFAULT, 00772 PropertyAttribute(ReadOnly | DontEnum | DontDelete)); 00773 } 00774 00775 static WrappedArrayJS * getWrapper(const v8::Handle<v8::Object> & object) 00776 { 00777 return unwrap<WrappedArrayJS>(object); 00778 } 00779 00780 static v8::Handle<v8::Value> 00781 lengthGetter(v8::Local<v8::String> property, 00782 const AccessorInfo & info) 00783 { 00784 try { 00785 WrappedArrayJS * wrapper = getWrapper(info.This()); 00786 size_t size = wrapper->desc->getArrayLength(wrapper->value); 00787 return JS::toJS(size); 00788 } HANDLE_JS_EXCEPTIONS; 00789 } 00790 00791 static v8::Handle<v8::Value> 00792 getIndexed(uint32_t index, const v8::AccessorInfo & info) 00793 { 00794 v8::HandleScope scope; 00795 try { 00796 WrappedArrayJS * wrapper = getWrapper(info.This()); 00797 size_t size = wrapper->desc->getArrayLength(wrapper->value); 00798 00799 if (index >= size) 00800 return v8::Undefined(); 00801 00802 void * element = wrapper->desc->getArrayElement(wrapper->value, index); 00803 00804 return scope.Close(getFromJs(element, wrapper->desc->contained(), 00805 wrapper->owner_)); 00806 } HANDLE_JS_EXCEPTIONS; 00807 } 00808 00809 static v8::Handle<v8::Value> 00810 setIndexed(uint32_t index, 00811 v8::Local<v8::Value> value, 00812 const v8::AccessorInfo & info) 00813 { 00814 try { 00815 throw ML::Exception("setIndexed not done yet"); 00816 } HANDLE_JS_EXCEPTIONS; 00817 } 00818 00819 static v8::Handle<v8::Integer> 00820 queryIndexed(uint32_t index, 00821 const v8::AccessorInfo & info) 00822 { 00823 WrappedArrayJS * wrapper = getWrapper(info.This()); 00824 size_t size = wrapper->desc->getArrayLength(wrapper->value); 00825 00826 if (index < size) 00827 return v8::Integer::New(v8::ReadOnly | v8::DontDelete); 00828 00829 return NULL_HANDLE; 00830 } 00831 00832 static v8::Handle<v8::Boolean> 00833 deleteIndexed(uint32_t index, 00834 const v8::AccessorInfo & info) 00835 { 00836 return NULL_HANDLE; 00837 } 00838 00839 static v8::Handle<v8::Array> 00840 listIndexed(const v8::AccessorInfo & info) 00841 { 00842 v8::HandleScope scope; 00843 00844 WrappedArrayJS * wrapper = getWrapper(info.This()); 00845 size_t sz = wrapper->desc->getArrayLength(wrapper->value); 00846 00847 v8::Handle<v8::Array> result(v8::Array::New(sz)); 00848 00849 for (unsigned i = 0; i < sz; ++i) { 00850 result->Set(v8::Uint32::New(i), 00851 v8::Uint32::New(i)); 00852 } 00853 00854 return scope.Close(result); 00855 } 00856 }; 00857 00858 v8::Persistent<v8::FunctionTemplate> 00859 WrappedArrayJS:: 00860 tmpl; 00861 00862 // Wrap an array of values where elements are got or set in their entirity 00863 struct WrappedValueArrayJS: public JSWrappedBase { 00864 const ValueDescription * desc; 00865 }; 00866 00867 // Wrap an array of fundamental types that can be directly mapped by the 00868 // Javascript runtime 00869 struct WrappedFundamentalValueArrayJS: public JSWrappedBase { 00870 const ValueDescription * desc; 00871 }; 00872 00873 struct WrappedStructureJS: public JSWrappedBase { 00874 const ValueDescription * desc; 00875 void * value; // value being read 00876 00877 static v8::Persistent<v8::FunctionTemplate> tmpl; 00878 00879 WrappedStructureJS(v8::Handle<v8::Object> This, 00880 void * value = 0, 00881 std::shared_ptr<void> owner = nullptr) 00882 { 00883 wrap(This, 64 /* bytes */, typeid(*this)); 00884 this->value = value; 00885 this->owner_ = owner; 00886 } 00887 00888 static Handle<v8::Value> 00889 New(const Arguments & args) 00890 { 00891 try { 00892 new WrappedStructureJS(args.This(), nullptr); 00893 return args.This(); 00894 } HANDLE_JS_EXCEPTIONS; 00895 } 00896 00897 static void Initialize() 00898 { 00899 tmpl = RegisterBase("WrappedStructureJS", "bonus", New); 00900 00901 tmpl->InstanceTemplate() 00902 ->SetNamedPropertyHandler(getNamed, setNamed, queryNamed, 00903 deleteNamed, listNamed); 00904 } 00905 00906 static WrappedStructureJS * getWrapper(const v8::Handle<v8::Object> & object) 00907 { 00908 return unwrap<WrappedStructureJS>(object); 00909 } 00910 00911 static v8::Handle<v8::Value> 00912 getNamed(v8::Local<v8::String> property, 00913 const v8::AccessorInfo & info) 00914 { 00915 try { 00916 string name = cstr(property); 00917 00918 WrappedStructureJS * wrapper = getWrapper(info.This()); 00919 const ValueDescription::FieldDescription * fd 00920 = wrapper->desc->hasField(wrapper->value, name); 00921 00922 if (!fd) 00923 return NULL_HANDLE; 00924 00925 return getFromJs(addOffset(wrapper->value, fd->offset), 00926 *fd->description, 00927 wrapper->owner_); 00928 00929 } HANDLE_JS_EXCEPTIONS; 00930 } 00931 00932 static v8::Handle<v8::Value> 00933 setNamed(v8::Local<v8::String> property, 00934 v8::Local<v8::Value> value, 00935 const v8::AccessorInfo & info) 00936 { 00937 try { 00938 string name = cstr(property); 00939 00940 WrappedStructureJS * wrapper = getWrapper(info.This()); 00941 const ValueDescription::FieldDescription & fd 00942 = wrapper->desc->getField(name); 00943 00944 setFromJs(addOffset(wrapper->value, fd.offset), value, 00945 *fd.description); 00946 00947 return v8::Undefined(); 00948 } HANDLE_JS_EXCEPTIONS; 00949 } 00950 00951 static v8::Handle<v8::Integer> 00952 queryNamed(v8::Local<v8::String> property, 00953 const v8::AccessorInfo & info) 00954 { 00955 string name = cstr(property); 00956 WrappedStructureJS * wrapper = getWrapper(info.This()); 00957 if (!wrapper->desc->hasField(wrapper->value, name)) 00958 return NULL_HANDLE; 00959 00960 return v8::Integer::New(DontDelete); 00961 } 00962 00963 static v8::Handle<v8::Boolean> 00964 deleteNamed(v8::Local<v8::String> property, 00965 const v8::AccessorInfo & info) 00966 00967 { 00968 return v8::False(); 00969 } 00970 00971 static v8::Handle<v8::Array> 00972 listNamed(const v8::AccessorInfo & info) 00973 { 00974 try { 00975 HandleScope scope; 00976 WrappedStructureJS * wrapper = getWrapper(info.This()); 00977 int numFields = wrapper->desc->getFieldCount(wrapper->value); 00978 00979 int i = 0; 00980 v8::Handle<v8::Array> result = v8::Array::New(numFields); 00981 00982 auto onField = [&] (const ValueDescription::FieldDescription & fd) 00983 { 00984 result->Set(v8::Uint32::New(i++), JS::toJS(fd.fieldName)); 00985 }; 00986 00987 wrapper->desc->forEachField(wrapper->value, onField); 00988 00989 return scope.Close(result); 00990 } catch (const std::exception & exc) { 00991 cerr << "got exception in listNamed" << endl; 00992 cerr << exc.what() << endl; 00993 cerr << cstr(info.This()) << endl; 00994 //backtrace(); 00995 return NULL_HANDLE; 00996 } 00997 } 00998 00999 }; 01000 01001 v8::Persistent<v8::FunctionTemplate> 01002 WrappedStructureJS:: 01003 tmpl; 01004 01005 namespace { 01006 01007 struct Init { 01008 Init() 01009 { 01010 registry.introduce("WrappedArrayJS", "bonus", WrappedArrayJS::Initialize); 01011 registry.introduce("WrappedStructureJS", "bonus", WrappedStructureJS::Initialize); 01012 } 01013 } init; 01014 01015 } // file scope 01016 01017 void 01018 initJsConverters(const ValueDescription & desc) 01019 { 01020 if (desc.jsConverters || desc.jsConvertersInitialized) 01021 return; 01022 01023 std::unique_ptr<JSConverters> converters 01024 (new JSConverters); 01025 01026 // Take a pointer so we bind over the pointer and copy it, not the 01027 // description 01028 auto descPtr = &desc; 01029 01030 //cerr << "***** desc.kind = " << desc.kind << " for " 01031 // << desc.typeName << endl; 01032 01033 // Is it a structure? 01034 if (desc.kind == ValueKind::STRUCTURE) { 01035 //cerr << "got structure " << desc.typeName << endl; 01036 01037 // Return structure-based converters 01038 converters->fromJs = [=] (void * field, const JSValue & val) 01039 { 01040 // Is it an object of the correct type? 01041 01042 if (!val->IsObject()) { 01043 throw ML::Exception("attempt to create structure from non-object " 01044 + cstr(val)); 01045 } 01046 #if 0 01047 if (WrappedStructureJS::tmpl->HasInstance(val)) { 01048 // Copy element by element 01049 } 01050 #endif 01051 01052 // Firstly, clear all of the fields to their default value 01053 descPtr->setDefault(field); 01054 01055 v8::HandleScope scope; 01056 auto objPtr = v8::Object::Cast(*val); 01057 01058 v8::Local<v8::Array> properties = objPtr->GetOwnPropertyNames(); 01059 01060 for (int i = 0; i < properties->Length(); ++i) { 01061 auto keyVal = properties->Get(i); 01062 string fieldName = cstr(keyVal); 01063 v8::Local<v8::Value> fieldVal = objPtr->Get(keyVal); 01064 01065 auto * fd = descPtr->hasField(field, fieldName); 01066 if (!fd) { 01067 Json::Value val = JS::fromJS(fieldVal); 01068 // TODO: some kind of on-unknown-field function 01069 01070 cerr << "got unknown JS field " << fieldName << " = " 01071 << val.toString() << endl; 01072 01073 continue; 01074 } 01075 01076 setFromJs(addOffset(field, fd->offset), fieldVal, 01077 *fd->description); 01078 } 01079 }; 01080 01081 converters->toJs = [=] (const void * field, std::shared_ptr<void> owner) 01082 { 01083 //cerr << "to JS structure for " << descPtr->typeName << endl; 01084 01085 // Wrap it in a wrapped array object 01086 v8::Local<v8::Object> result 01087 = WrappedStructureJS::tmpl->GetFunction()->NewInstance(); 01088 auto wrapper = WrappedStructureJS::getWrapper(result); 01089 wrapper->value = (void *)field; 01090 wrapper->desc = descPtr; 01091 wrapper->owner_ = owner; 01092 01093 return result; 01094 }; 01095 } 01096 01097 // Is it an array? 01098 if (desc.kind == ValueKind::ARRAY) { 01099 //cerr << "got array " << desc.typeName << endl; 01100 01101 const ValueDescription * innerDesc = &descPtr->contained(); 01102 01103 // Convert each element of the array 01104 converters->fromJs = [=] (void * field, const JSValue & val) 01105 { 01106 //cerr << "from JS array" << endl; 01107 01108 // Convert the entire lot in the JS into our type 01109 if (val->IsNull()) { 01110 descPtr->setArrayLength(field, 0); 01111 return; 01112 } 01113 01114 // Is it an object of the correct type? 01115 if (val->IsObject()) { 01116 if (WrappedArrayJS::tmpl->HasInstance(val)) { 01117 //cerr << "Is a wrapped array" << endl; 01118 auto wrapper = WrappedArrayJS::getWrapper(val); 01119 01120 // Same type?; do a direct copy 01121 if (wrapper->desc->type == descPtr->type) { 01122 descPtr->copyValue(wrapper->value, field); 01123 return; 01124 } 01125 01126 // Otherwise, copy element by element 01127 size_t len = wrapper->desc->getArrayLength(wrapper->value); 01128 01129 descPtr->setArrayLength(field, len); 01130 01131 auto & valContained = wrapper->desc->contained(); 01132 01133 // Same inner type? 01134 if (innerDesc->type == valContained.type) { 01135 for (unsigned i = 0; i < len; ++i) { 01136 innerDesc->copyValue(wrapper->desc->getArrayElement(wrapper->value, i), 01137 descPtr->getArrayElement(field, i)); 01138 } 01139 return; 01140 } 01141 01142 for (unsigned i = 0; i < len; ++i) { 01143 for (unsigned i = 0; i < len; ++i) { 01144 innerDesc->convertAndCopy 01145 (wrapper->desc->getArrayElement(wrapper->value, i), 01146 *wrapper->desc, 01147 descPtr->getArrayElement(field, i)); 01148 } 01149 } 01150 01151 return; 01152 01153 cerr << "descPtr = " << descPtr 01154 << "wrapper->desc = " << wrapper->desc << endl; 01155 cerr << "descPtr = " << descPtr->typeName 01156 << "wrapper->desc = " << wrapper->desc->typeName << endl; 01157 cerr << "field = " << field << " wrapper->value = " 01158 << wrapper->value << endl; 01159 01160 // Copy element by element 01161 } 01162 } 01163 01164 if(!val->IsArray()) { 01165 throw ML::Exception("invalid JSValue for array extraction"); 01166 } 01167 01168 auto arrPtr = v8::Array::Cast(*val); 01169 01170 descPtr->setArrayLength(field, arrPtr->Length()); 01171 01172 for(int i=0; i<arrPtr->Length(); ++i) { 01173 auto val = arrPtr->Get(i); 01174 setFromJs(descPtr->getArrayElement(field, i), val, *innerDesc); 01175 } 01176 }; 01177 01178 converters->toJs = [=] (const void * field, const std::shared_ptr<void> & owner) 01179 { 01180 //cerr << "to JS array for " << descPtr->typeName << endl; 01181 01182 // Wrap it in a wrapped array object 01183 v8::Local<v8::Object> result 01184 = WrappedArrayJS::tmpl->GetFunction()->NewInstance(); 01185 auto wrapper = WrappedArrayJS::getWrapper(result); 01186 wrapper->value = (void *)field; 01187 wrapper->desc = descPtr; 01188 wrapper->owner_ = owner; 01189 01190 return result; 01191 }; 01192 } 01193 01194 // Is it optional? 01195 if (desc.kind == ValueKind::OPTIONAL) { 01196 //cerr << "got optional " << desc.typeName << endl; 01197 01198 const ValueDescription * innerDesc = &descPtr->contained(); 01199 01200 //cerr << "innerDesc = " << innerDesc << endl; 01201 01202 // Return optional converters 01203 converters->fromJs = [=] (void * field, const JSValue & value) 01204 { 01205 //cerr << "optional value = " << cstr(value) << endl; 01206 // If the value is null, then we remove the optional value 01207 if (value->IsNull() || value->IsUndefined()) { 01208 descPtr->setDefault(field); 01209 return; 01210 } 01211 01212 //cerr << "*** setting inner value" << endl; 01213 01214 // Otherwise we get the inner value and set it 01215 setFromJs(descPtr->optionalMakeValue(field), 01216 value, 01217 *innerDesc); 01218 }; 01219 01220 converters->toJs = [=] (const void * field, std::shared_ptr<void> owner) 01221 -> v8::Handle<v8::Value> 01222 { 01223 // If the value is missing, we return null 01224 if (descPtr->isDefault(field)) 01225 return v8::Null(); 01226 01227 // Otherwise we return the inner value 01228 return getFromJs(descPtr->optionalGetValue(field), 01229 *innerDesc, 01230 owner); 01231 }; 01232 } 01233 01234 // Does it have any parent classes? 01235 01236 // Is it an arithmetic type? 01237 01238 // Default goes through JSON 01239 if (!converters->fromJs) { 01240 converters->fromJs = [=] (void * field, const JSValue & value) 01241 { 01242 Json::Value val = JS::fromJS(value); 01243 StructuredJsonParsingContext context(val); 01244 descPtr->parseJson(field, context); 01245 }; 01246 } 01247 01248 if (!converters->toJs) { 01249 converters->toJs = [=] (const void * field, std::shared_ptr<void>) 01250 { 01251 StructuredJsonPrintingContext context; 01252 descPtr->printJson(field, context); 01253 return JS::toJS(context.output); 01254 }; 01255 } 01256 01257 desc.jsConverters = converters.release(); 01258 desc.jsConvertersInitialized = true; 01259 } 01260 01261 void 01262 setFromJs(void * field, 01263 const JSValue & value, 01264 const ValueDescription & desc) 01265 { 01266 if (!desc.jsConvertersInitialized) { 01267 initJsConverters(desc); 01268 } 01269 01270 desc.jsConverters->fromJs(field, value); 01271 } 01272 01273 v8::Handle<v8::Value> 01274 getFromJs(const void * field, 01275 const ValueDescription & desc, 01276 const std::shared_ptr<void> & owner) 01277 { 01278 if (!desc.jsConvertersInitialized) { 01279 initJsConverters(desc); 01280 } 01281 01282 return desc.jsConverters->toJs(field, owner); 01283 } 01284 01285 01286 template<typename Obj, typename Base> 01287 struct PropertyAccessViaDescription { 01288 static v8::Handle<v8::Value> 01289 getter(v8::Local<v8::String> property, 01290 const v8::AccessorInfo & info) 01291 { 01292 try { 01293 const ValueDescription * vd 01294 = reinterpret_cast<const ValueDescription *> 01295 (v8::External::Unwrap(info.Data())); 01296 auto p = Base::getSharedPtr(info.This()); 01297 Obj * o = p.get(); 01298 const StructureDescriptionBase::FieldDescription & fd 01299 = vd->getField(cstr(property)); 01300 return getFromJs(addOffset(o, fd.offset), *fd.description, p); 01301 } HANDLE_JS_EXCEPTIONS; 01302 } 01303 01304 static void 01305 setter(v8::Local<v8::String> property, 01306 v8::Local<v8::Value> value, 01307 const v8::AccessorInfo & info) 01308 { 01309 try { 01310 const ValueDescription * vd 01311 = reinterpret_cast<const ValueDescription *> 01312 (v8::External::Unwrap(info.Data())); 01313 Obj * o = Base::getShared(info.This()); 01314 const StructureDescriptionBase::FieldDescription & fd 01315 = vd->getField(cstr(property)); 01316 setFromJs(addOffset(o, fd.offset), value, *fd.description); 01317 } HANDLE_JS_EXCEPTIONS_SETTER; 01318 } 01319 }; 01320 01321 template<typename Wrapper, typename T> 01322 void registerFieldFromDescription(const StructureDescription<T> & desc, 01323 const std::string & fieldName) 01324 { 01325 Wrapper::tmpl->InstanceTemplate() 01326 ->SetAccessor(v8::String::NewSymbol(fieldName.c_str()), 01327 PropertyAccessViaDescription<T, Wrapper>::getter, 01328 PropertyAccessViaDescription<T, Wrapper>::setter, 01329 v8::External::Wrap((void *)&desc), 01330 v8::DEFAULT, 01331 v8::PropertyAttribute(v8::DontDelete)); 01332 } 01333 01334 /*****************************************************************************/ 01335 /* AD SPOT JS */ 01336 /*****************************************************************************/ 01337 01338 extern const char * AdSpotName; 01339 const char * AdSpotName = "AdSpot"; 01340 01341 struct AdSpotJS 01342 : public JSWrapped2<AdSpot, AdSpotJS, AdSpotName, 01343 bidRequestModule> { 01344 01345 AdSpotJS(v8::Handle<v8::Object> This, 01346 const std::shared_ptr<AdSpot> & as 01347 = std::shared_ptr<AdSpot>()) 01348 { 01349 HandleScope scope; 01350 wrap(This, as); 01351 } 01352 01353 static Handle<v8::Value> 01354 New(const Arguments & args) 01355 { 01356 try { 01357 new AdSpotJS(args.This(), ML::make_std_sp(new AdSpot())); 01358 return args.This(); 01359 } HANDLE_JS_EXCEPTIONS; 01360 } 01361 01362 static void 01363 Initialize() 01364 { 01365 Persistent<FunctionTemplate> t = Register(New); 01366 01367 static DefaultDescription<AdSpot> desc; 01368 01369 for (auto & f: desc.fields) { 01370 const char * name = f.first; 01371 registerFieldFromDescription<JSWrapped2>(desc, name); 01372 } 01373 01374 registerRWProperty(&AdSpot::id, "id", 01375 v8::DontDelete); 01376 registerRWProperty(&AdSpot::reservePrice, "reservePrice", 01377 v8::DontDelete); 01378 registerROProperty(&AdSpot::formats, "formats", 01379 v8::ReadOnly | v8::DontDelete); 01380 01381 #if 0 01382 t->InstanceTemplate() 01383 ->SetAccessor(String::NewSymbol("width"), widthsGetter, 01384 0, v8::Handle<v8::Value>(), DEFAULT, 01385 PropertyAttribute(ReadOnly | DontDelete)); 01386 t->InstanceTemplate() 01387 ->SetAccessor(String::NewSymbol("height"), heightsGetter, 01388 0, v8::Handle<v8::Value>(), DEFAULT, 01389 PropertyAttribute(ReadOnly | DontDelete)); 01390 #endif 01391 } 01392 01393 #if 0 01394 static v8::Handle<v8::Value> 01395 widthsGetter(v8::Local<v8::String> property, 01396 const v8::AccessorInfo & info) 01397 { 01398 try { 01399 const auto & f = getShared(info.This())->formats; 01400 vector<int> v2; 01401 for (unsigned i = 0; i < f.size(); ++i) 01402 v2.push_back(f[i].width); 01403 return JS::toJS(v2); 01404 } HANDLE_JS_EXCEPTIONS; 01405 } 01406 01407 static v8::Handle<v8::Value> 01408 heightsGetter(v8::Local<v8::String> property, 01409 const v8::AccessorInfo & info) 01410 { 01411 try { 01412 const auto & f = getShared(info.This())->formats; 01413 vector<int> v2; 01414 for (unsigned i = 0; i < f.size(); ++i) 01415 v2.push_back(f[i].height); 01416 return JS::toJS(v2); 01417 } HANDLE_JS_EXCEPTIONS; 01418 } 01419 #endif 01420 01421 }; 01422 01423 void to_js(JS::JSValue & value, const std::shared_ptr<AdSpot> & as) 01424 { 01425 value = AdSpotJS::toJS(as); 01426 } 01427 01428 void to_js(JS::JSValue & value, const AdSpot & as) 01429 { 01430 to_js(value, ML::make_std_sp(new AdSpot(as))); 01431 } 01432 01433 std::shared_ptr<AdSpot> 01434 from_js(const JSValue & value, std::shared_ptr<AdSpot> *) 01435 { 01436 return AdSpotJS::fromJS(value); 01437 } 01438 01439 AdSpot 01440 from_js(const JSValue & value, AdSpot *) 01441 { 01442 return *AdSpotJS::fromJS(value).get(); 01443 } 01444 01445 01446 /*****************************************************************************/ 01447 /* BID REQUEST JS */ 01448 /*****************************************************************************/ 01449 01450 const char * BidRequestName = "BidRequest"; 01451 01452 struct BidRequestJS 01453 : public JSWrapped2<BidRequest, BidRequestJS, BidRequestName, 01454 bidRequestModule> { 01455 01456 BidRequestJS(v8::Handle<v8::Object> This, 01457 const std::shared_ptr<BidRequest> & bid 01458 = std::shared_ptr<BidRequest>()) 01459 { 01460 HandleScope scope; 01461 wrap(This, bid); 01462 } 01463 01464 static Handle<v8::Value> 01465 New(const Arguments & args) 01466 { 01467 try { 01468 if (args.Length() > 0) { 01469 if (BidRequestJS::tmpl->HasInstance(args[0])) { 01470 //cerr << "copy existing" << endl; 01471 // Copy an existing bid request 01472 std::shared_ptr<BidRequest> oldBr 01473 = JS::fromJS(args[0]); 01474 auto br = std::make_shared<BidRequest>(); 01475 *br = *oldBr; 01476 new BidRequestJS(args.This(), br); 01477 01478 } 01479 else if (args[0]->IsString()) { 01480 // Parse from a string 01481 //cerr << "parse string" << endl; 01482 Utf8String request = getArg<Utf8String>(args, 0, "request"); 01483 string source = getArg<string>(args, 1, "datacratic", "source"); 01484 new BidRequestJS(args.This(), 01485 ML::make_std_sp(BidRequest::parse(source, request))); 01486 } 01487 else if (args[0]->IsObject()) { 01488 //cerr << "parse object" << endl; 01489 // Parse from an object by going through JSON 01490 Json::Value json = JS::fromJS(args[0]); 01491 //cerr << "JSON = " << json << endl; 01492 auto br = std::make_shared<BidRequest>(); 01493 *br = BidRequest::createFromJson(json); 01494 new BidRequestJS(args.This(), br); 01495 } 01496 else throw ML::Exception("Cannot convert " + cstr(args[0]) 01497 + " to BidRequest"); 01498 } else { 01499 new BidRequestJS(args.This(), ML::make_std_sp(new BidRequest())); 01500 } 01501 return args.This(); 01502 } HANDLE_JS_EXCEPTIONS; 01503 } 01504 01505 static void 01506 Initialize() 01507 { 01508 Persistent<FunctionTemplate> t = Register(New); 01509 01510 registerRWProperty(&BidRequest::auctionId, "id", v8::DontDelete); 01511 registerRWProperty(&BidRequest::timestamp, "timestamp", v8::DontDelete); 01512 registerRWProperty(&BidRequest::isTest, "isTest", v8::DontDelete); 01513 registerRWProperty(&BidRequest::url, "url", v8::DontDelete); 01514 registerRWProperty(&BidRequest::meta, "meta", v8::DontDelete); 01515 registerRWProperty(&BidRequest::ipAddress, "ipAddress", v8::DontDelete); 01516 registerRWProperty(&BidRequest::userAgent, "userAgent", v8::DontDelete); 01517 registerRWProperty(&BidRequest::language, "language", v8::DontDelete); 01518 registerRWProperty(&BidRequest::protocolVersion, 01519 "protocolVersion", v8::DontDelete); 01520 registerRWProperty(&BidRequest::exchange, "exchange", v8::DontDelete); 01521 registerRWProperty(&BidRequest::provider, "provider", v8::DontDelete); 01522 01523 static DefaultDescription<BidRequest> desc; 01524 01526 registerFieldFromDescription<BidRequestJS>(desc, "spots"); 01527 registerFieldFromDescription<BidRequestJS>(desc, "imp"); 01528 01529 01530 //registerRWProperty(&BidRequest::imp, "imp", v8::DontDelete); 01531 01532 //registerRWProperty(&BidRequest::winSurcharge, "winSurchage", 01533 // v8::DontDelete); 01534 01535 // TODO: these should go... 01536 //registerRWProperty(&BidRequest::creative, "creative", v8::DontDelete); 01537 registerMemberFn(&BidRequest::toJson, "toJSON"); 01538 01539 NODE_SET_PROTOTYPE_METHOD(t, "getSegmentsFromSource", 01540 getSegmentsFromSource); 01541 01542 t->InstanceTemplate() 01543 ->SetAccessor(String::NewSymbol("segments"), segmentsGetter, 01544 segmentsSetter, v8::Handle<v8::Value>(), DEFAULT, 01545 PropertyAttribute(DontDelete)); 01546 01547 t->InstanceTemplate() 01548 ->SetAccessor(String::NewSymbol("restrictions"), restrictionsGetter, 01549 restrictionsSetter, v8::Handle<v8::Value>(), DEFAULT, 01550 PropertyAttribute(DontDelete)); 01551 01552 t->InstanceTemplate() 01553 ->SetAccessor(String::NewSymbol("userIds"), userIdsGetter, 01554 userIdsSetter, v8::Handle<v8::Value>(), DEFAULT, 01555 PropertyAttribute(DontDelete)); 01556 01557 t->InstanceTemplate() 01558 ->SetAccessor(String::NewSymbol("location"), locationGetter, 01559 locationSetter, v8::Handle<v8::Value>(), DEFAULT, 01560 PropertyAttribute(DontDelete)); 01561 } 01562 01563 static Handle<v8::Value> 01564 getSegmentsFromSource(const Arguments & args) 01565 { 01566 try { 01567 string segmentProvider = getArg(args, 0, "segmentProvider"); 01568 auto sh = getShared(args.This()); 01569 auto it = sh->segments.find(segmentProvider); 01570 if (it == sh->segments.end()) 01571 return v8::Null(); 01572 return JS::toJS(it->second); 01573 } HANDLE_JS_EXCEPTIONS; 01574 } 01575 01576 static v8::Handle<v8::Value> 01577 segmentsGetter(v8::Local<v8::String> property, 01578 const v8::AccessorInfo & info) 01579 { 01580 try { 01581 v8::Handle<v8::Value> segs 01582 = SegmentsBySourceJS::toJS 01583 (ML::make_unowned_std_sp(getShared(info.This())->segments)); 01584 SegmentsBySourceJS * wrapper 01585 = SegmentsBySourceJS::getWrapper(segs); 01586 wrapper->owner_ = getSharedPtr(info.This()); 01587 return segs; 01588 } HANDLE_JS_EXCEPTIONS; 01589 } 01590 01591 static void 01592 segmentsSetter(v8::Local<v8::String> property, 01593 v8::Local<v8::Value> value, 01594 const v8::AccessorInfo & info) 01595 { 01596 try { 01597 if (SegmentsBySourceJS::tmpl->HasInstance(value)) { 01598 getShared(info.This())->segments 01599 = *SegmentsBySourceJS::getShared(value); 01600 return; 01601 } 01602 if (value->IsObject()) { 01603 map<std::string, std::shared_ptr<SegmentList> > segs; 01604 segs = from_js(JSValue(value), &segs); 01605 getShared(info.This())->segments = SegmentsBySource(segs); 01606 return; 01607 } 01608 throw ML::Exception("can't convert " + cstr(value) 01609 + " into segment list"); 01610 } HANDLE_JS_EXCEPTIONS_SETTER; 01611 } 01612 01613 static v8::Handle<v8::Value> 01614 restrictionsGetter(v8::Local<v8::String> property, 01615 const v8::AccessorInfo & info) 01616 { 01617 try { 01618 v8::Handle<v8::Value> segs 01619 = SegmentsBySourceJS::toJS 01620 (ML::make_unowned_std_sp(getShared(info.This())->restrictions)); 01621 SegmentsBySourceJS * wrapper 01622 = SegmentsBySourceJS::getWrapper(segs); 01623 wrapper->owner_ = getSharedPtr(info.This()); 01624 return segs; 01625 } HANDLE_JS_EXCEPTIONS; 01626 } 01627 01628 static void 01629 restrictionsSetter(v8::Local<v8::String> property, 01630 v8::Local<v8::Value> value, 01631 const v8::AccessorInfo & info) 01632 { 01633 try { 01634 if (SegmentsBySourceJS::tmpl->HasInstance(value)) { 01635 getShared(info.This())->restrictions 01636 = *SegmentsBySourceJS::getShared(value); 01637 return; 01638 } 01639 if (value->IsObject()) { 01640 map<std::string, std::shared_ptr<SegmentList> > segs; 01641 segs = from_js(JSValue(value), &segs); 01642 getShared(info.This())->restrictions = SegmentsBySource(segs); 01643 return; 01644 } 01645 throw ML::Exception("can't convert " + cstr(value) 01646 + " into segment list"); 01647 } HANDLE_JS_EXCEPTIONS_SETTER; 01648 } 01649 01650 static v8::Handle<v8::Value> 01651 userIdsGetter(v8::Local<v8::String> property, 01652 const v8::AccessorInfo & info) 01653 { 01654 try { 01655 auto owner = getSharedPtr(info.This()); 01656 return UserIdsJS::toJS(owner->userIds, owner); 01657 } HANDLE_JS_EXCEPTIONS; 01658 } 01659 01660 static void 01661 userIdsSetter(v8::Local<v8::String> property, 01662 v8::Local<v8::Value> value, 01663 const v8::AccessorInfo & info) 01664 { 01665 try { 01666 if (UserIdsJS::tmpl->HasInstance(value)) { 01667 getShared(info.This())->userIds 01668 = *UserIdsJS::getShared(value); 01669 return; 01670 } 01671 if (value->IsObject()) { 01672 map<std::string, Id> ids; 01673 ids = from_js(JSValue(value), &ids); 01674 auto & uids = getShared(info.This())->userIds; 01675 for (auto it = ids.begin(), end = ids.end(); 01676 it != end; ++it) 01677 uids.add(it->second, it->first); 01678 return; 01679 } 01680 throw ML::Exception("can't convert " + cstr(value) 01681 + " into segment list"); 01682 } HANDLE_JS_EXCEPTIONS_SETTER; 01683 } 01684 01685 static v8::Handle<v8::Value> 01686 locationGetter(v8::Local<v8::String> property, 01687 const v8::AccessorInfo & info) 01688 { 01689 try { 01690 auto owner = getSharedPtr(info.This()); 01691 return LocationJS::toJS(owner->location, owner); 01692 } HANDLE_JS_EXCEPTIONS; 01693 } 01694 01695 static void 01696 locationSetter(v8::Local<v8::String> property, 01697 v8::Local<v8::Value> value, 01698 const v8::AccessorInfo & info) 01699 { 01700 try { 01701 if (LocationJS::tmpl->HasInstance(value)) { 01702 getShared(info.This())->location 01703 = *LocationJS::getShared(value); 01704 return; 01705 } 01706 if (value->IsObject()) { 01707 Json::Value json = JS::fromJS(value); 01708 getShared(info.This())->location 01709 = Location::createFromJson(json); 01710 return; 01711 } 01712 throw ML::Exception("can't convert " + cstr(value) 01713 + " into location info"); 01714 } HANDLE_JS_EXCEPTIONS_SETTER; 01715 } 01716 01717 }; 01718 01719 std::shared_ptr<BidRequest> 01720 from_js(const JSValue & value, std::shared_ptr<BidRequest> *) 01721 { 01722 return BidRequestJS::fromJS(value); 01723 } 01724 01725 BidRequest * 01726 from_js(const JSValue & value, BidRequest **) 01727 { 01728 return BidRequestJS::fromJS(value).get(); 01729 } 01730 01731 std::shared_ptr<BidRequest> 01732 from_js_ref(const JSValue & value, std::shared_ptr<BidRequest> *) 01733 { 01734 return BidRequestJS::fromJS(value); 01735 } 01736 01737 void to_js(JS::JSValue & value, const std::shared_ptr<BidRequest> & br) 01738 { 01739 value = BidRequestJS::toJS(br); 01740 } 01741 01742 01743 std::shared_ptr<BidRequest> 01744 getBidRequestSharedPointer(const JS::JSValue & value) 01745 { 01746 if(BidRequestJS::tmpl->HasInstance(value)) 01747 { 01748 std::shared_ptr<BidRequest> br = BidRequestJS::getSharedPtr(value); 01749 return br; 01750 } 01751 std::shared_ptr<BidRequest> br; 01752 return br; 01753 } 01754 01755 01756 extern "C" void 01757 init(Handle<v8::Object> target) 01758 { 01759 Datacratic::JS::registry.init(target, bidRequestModule); 01760 } 01761 01762 } // namespace JS 01763 } // namespace Datacratic