make it work

This commit is contained in:
Ari Lazier 2015-10-22 16:49:32 -07:00
parent 92a9113ef6
commit c3c9cee0ee
3 changed files with 93 additions and 90 deletions

View File

@ -82,10 +82,14 @@ JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor, bool cre
_bridge = bridge; _bridge = bridge;
static GCDWebServer *s_webServer; static GCDWebServer *s_webServer;
static realm_js::RPCServer *rpcServer;
if (s_webServer) { if (s_webServer) {
[s_webServer stop]; [s_webServer stop];
[s_webServer removeAllHandlers]; [s_webServer removeAllHandlers];
s_webServer = nil; s_webServer = nil;
delete rpcServer;
} }
// The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context. // The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context.
@ -94,17 +98,16 @@ JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor, bool cre
if ([executor isMemberOfClass:NSClassFromString(@"RCTWebSocketExecutor")]) { if ([executor isMemberOfClass:NSClassFromString(@"RCTWebSocketExecutor")]) {
[GCDWebServer setLogLevel:3]; [GCDWebServer setLogLevel:3];
GCDWebServer *webServer = [[GCDWebServer alloc] init]; GCDWebServer *webServer = [[GCDWebServer alloc] init];
__block realm_js::RPCServer rpcServer; rpcServer = new realm_js::RPCServer();
// Add a handler to respond to POST requests on any URL // Add a handler to respond to POST requests on any URL
[webServer addDefaultHandlerForMethod:@"POST" [webServer addDefaultHandlerForMethod:@"POST"
requestClass:[GCDWebServerDataRequest class] requestClass:[GCDWebServerDataRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
GCDWebServerResponse *response; GCDWebServerResponse *response;
try { try {
realm_js::json args = realm_js::json::parse([[(GCDWebServerDataRequest *)request text] UTF8String]); realm_js::json args = realm_js::json::parse([[(GCDWebServerDataRequest *)request text] UTF8String]);
std::string response_text = rpcServer.perform_request(request.path.UTF8String, args).dump(); std::string response_text = rpcServer->perform_request(request.path.UTF8String, args).dump();
response = [[GCDWebServerDataResponse alloc] initWithData:[NSData dataWithBytes:response_text.c_str() length:response_text.length()] contentType:@"application/json"]; response = [[GCDWebServerDataResponse alloc] initWithData:[NSData dataWithBytes:response_text.c_str() length:response_text.length()] contentType:@"application/json"];
} }
catch(std::exception &ex) { catch(std::exception &ex) {

View File

@ -35,7 +35,7 @@ class RPCServer {
public: public:
RPCServer(); RPCServer();
~RPCServer(); ~RPCServer();
json perform_request(std::string name, const json args); json perform_request(std::string name, json &args);
private: private:
JSGlobalContextRef _context; JSGlobalContextRef _context;

View File

@ -48,7 +48,7 @@ RPCServer::RPCServer() {
setIncludesNativeCallStack(_context, false); setIncludesNativeCallStack(_context, false);
} }
_requests["/create_session"] = [=](const json dict) { _requests["/create_session"] = [this](const json dict) {
[RealmJS initializeContext:_context]; [RealmJS initializeContext:_context];
JSStringRef realm_string = RJSStringForString("Realm"); JSStringRef realm_string = RJSStringForString("Realm");
@ -56,9 +56,9 @@ RPCServer::RPCServer() {
JSStringRelease(realm_string); JSStringRelease(realm_string);
_sessionID = store_object(realm_constructor); _sessionID = store_object(realm_constructor);
return json({"result", _sessionID}); return (json){{"result", _sessionID}};
}; };
_requests["/create_realm"] = [=](const json dict) { _requests["/create_realm"] = [this](const json dict) {
JSObjectRef realm_constructor = _sessionID ? _objects[_sessionID] : NULL; JSObjectRef realm_constructor = _sessionID ? _objects[_sessionID] : NULL;
if (!realm_constructor) { if (!realm_constructor) {
throw std::runtime_error("Realm constructor not found!"); throw std::runtime_error("Realm constructor not found!");
@ -76,28 +76,28 @@ RPCServer::RPCServer() {
JSObjectRef realmObject = JSObjectCallAsConstructor(_context, realm_constructor, arg_count, arg_values, &exception); JSObjectRef realmObject = JSObjectCallAsConstructor(_context, realm_constructor, arg_count, arg_values, &exception);
if (exception) { if (exception) {
return (json){"error", RJSStringForValue(_context, exception)}; return (json){{"error", RJSStringForValue(_context, exception)}};
} }
RPCObjectID realmId = store_object(realmObject); RPCObjectID realmId = store_object(realmObject);
return (json){"result", realmId}; return (json){{"result", realmId}};
}; };
_requests["/begin_transaction"] = [=](const json dict) { _requests["/begin_transaction"] = [this](const json dict) {
RPCObjectID realmId = dict["realmId"].get<RPCObjectID>(); RPCObjectID realmId = dict["realmId"].get<RPCObjectID>();
RJSGetInternal<realm::SharedRealm *>(_objects[realmId])->get()->begin_transaction(); RJSGetInternal<realm::SharedRealm *>(_objects[realmId])->get()->begin_transaction();
return nil; return json::object();
}; };
_requests["/cancel_transaction"] = [=](const json dict) { _requests["/cancel_transaction"] = [this](const json dict) {
RPCObjectID realmId = dict["realmId"].get<RPCObjectID>(); RPCObjectID realmId = dict["realmId"].get<RPCObjectID>();
RJSGetInternal<realm::SharedRealm *>(_objects[realmId])->get()->cancel_transaction(); RJSGetInternal<realm::SharedRealm *>(_objects[realmId])->get()->cancel_transaction();
return nil; return json::object();
}; };
_requests["/commit_transaction"] = [=](const json dict) { _requests["/commit_transaction"] = [this](const json dict) {
RPCObjectID realmId = dict["realmId"].get<RPCObjectID>(); RPCObjectID realmId = dict["realmId"].get<RPCObjectID>();
RJSGetInternal<realm::SharedRealm *>(_objects[realmId])->get()->commit_transaction(); RJSGetInternal<realm::SharedRealm *>(_objects[realmId])->get()->commit_transaction();
return nil; return json::object();
}; };
_requests["/call_method"] = [=](const json dict) { _requests["/call_method"] = [this](const json dict) {
JSObjectRef object = _objects[dict["id"].get<RPCObjectID>()]; JSObjectRef object = _objects[dict["id"].get<RPCObjectID>()];
JSStringRef methodString = RJSStringForString(dict["name"].get<std::string>()); JSStringRef methodString = RJSStringForString(dict["name"].get<std::string>());
JSObjectRef function = RJSValidatedObjectProperty(_context, object, methodString); JSObjectRef function = RJSValidatedObjectProperty(_context, object, methodString);
@ -114,11 +114,11 @@ RPCServer::RPCServer() {
JSValueRef result = JSObjectCallAsFunction(_context, function, object, argCount, argValues, &exception); JSValueRef result = JSObjectCallAsFunction(_context, function, object, argCount, argValues, &exception);
if (exception) { if (exception) {
return (json){"error", RJSStringForValue(_context, exception)}; return (json){{"error", RJSStringForValue(_context, exception)}};
} }
return (json){"result", serialize_json_value(result)}; return (json){{"result", serialize_json_value(result)}};
}; };
_requests["/get_property"] = [=](const json dict) { _requests["/get_property"] = [this](const json dict) {
RPCObjectID oid = dict["id"].get<RPCObjectID>(); RPCObjectID oid = dict["id"].get<RPCObjectID>();
json name = dict["name"]; json name = dict["name"];
JSValueRef value = NULL; JSValueRef value = NULL;
@ -134,11 +134,11 @@ RPCServer::RPCServer() {
} }
if (exception) { if (exception) {
return (json){"error", RJSStringForValue(_context, exception)}; return (json){{"error", RJSStringForValue(_context, exception)}};
} }
return (json){"result", serialize_json_value(value)}; return (json){{"result", serialize_json_value(value)}};
}; };
_requests["/set_property"] = [=](const json dict) { _requests["/set_property"] = [this](const json dict) {
RPCObjectID oid = dict["id"].get<RPCObjectID>(); RPCObjectID oid = dict["id"].get<RPCObjectID>();
json name = dict["name"]; json name = dict["name"];
JSValueRef value = deserialize_json_value(dict["value"]); JSValueRef value = deserialize_json_value(dict["value"]);
@ -154,17 +154,17 @@ RPCServer::RPCServer() {
} }
if (exception) { if (exception) {
return json({"error", RJSStringForValue(_context, exception)}); return (json){{"error", RJSStringForValue(_context, exception)}};
} }
return json({}); return json::object();
}; };
_requests["/dispose_object"] = [=](const json dict) { _requests["/dispose_object"] = [this](const json dict) {
RPCObjectID oid = dict["id"].get<RPCObjectID>(); RPCObjectID oid = dict["id"].get<RPCObjectID>();
JSValueUnprotect(_context, _objects[oid]); JSValueUnprotect(_context, _objects[oid]);
_objects.erase(oid); _objects.erase(oid);
return nil; return json::object();
}; };
_requests["/clear_test_state"] = [=](const json dict) { _requests["/clear_test_state"] = [this](const json dict) {
for (auto object : _objects) { for (auto object : _objects) {
// The session ID points to the Realm constructor object, which should remain. // The session ID points to the Realm constructor object, which should remain.
if (object.first == _sessionID) { if (object.first == _sessionID) {
@ -176,7 +176,7 @@ RPCServer::RPCServer() {
} }
JSGarbageCollect(_context); JSGarbageCollect(_context);
[RealmJS clearTestState]; [RealmJS clearTestState];
return nil; return json::object();
}; };
} }
@ -188,25 +188,26 @@ RPCServer::~RPCServer() {
JSGlobalContextRelease(_context); JSGlobalContextRelease(_context);
} }
json RPCServer::perform_request(std::string name, const json args) { json RPCServer::perform_request(std::string name, json &args) {
// perform all realm ops on the main thread // perform all realm ops on the main thread
__block json response;
dispatch_sync(dispatch_get_main_queue(), ^{
try {
RPCRequest action = _requests[name]; RPCRequest action = _requests[name];
assert(action); assert(action);
__block json response; if (name == "/create_session" || _sessionID == args["sessionId"].get<RPCObjectID>()) {
dispatch_sync(dispatch_get_main_queue(), ^{
if (_sessionID != args["sessionId"].get<RPCObjectID>()) {
response = {"error", "Invalid session ID"};
return;
}
try {
response = action(args); response = action(args);
assert(response.is_object());
}
else {
response = {{"error", "Invalid session ID"}};
}
} catch (std::exception &exception) { } catch (std::exception &exception) {
response = {"error", (std::string)"exception thrown: " + exception.what()}; response = {{"error", (std::string)"exception thrown: " + exception.what()}};
} }
}); });
return response ?: json(); return response;
} }
RPCObjectID RPCServer::store_object(JSObjectRef object) { RPCObjectID RPCServer::store_object(JSObjectRef object) {
@ -220,15 +221,15 @@ RPCObjectID RPCServer::store_object(JSObjectRef object) {
json RPCServer::serialize_json_value(JSValueRef value) { json RPCServer::serialize_json_value(JSValueRef value) {
switch (JSValueGetType(_context, value)) { switch (JSValueGetType(_context, value)) {
case kJSTypeUndefined: case kJSTypeUndefined:
return {}; return json::object();
case kJSTypeNull: case kJSTypeNull:
return {"value", json(nullptr)}; return {{"value", json(nullptr)}};
case kJSTypeBoolean: case kJSTypeBoolean:
return {"value", JSValueToBoolean(_context, value)}; return {{"value", JSValueToBoolean(_context, value)}};
case kJSTypeNumber: case kJSTypeNumber:
return {"value", JSValueToNumber(_context, value, NULL)}; return {{"value", JSValueToNumber(_context, value, NULL)}};
case kJSTypeString: case kJSTypeString:
return {"value", RJSStringForValue(_context, value).c_str()}; return {{"value", RJSStringForValue(_context, value).c_str()}};
case kJSTypeObject: case kJSTypeObject:
break; break;
} }
@ -238,33 +239,33 @@ json RPCServer::serialize_json_value(JSValueRef value) {
if (JSValueIsObjectOfClass(_context, value, RJSObjectClass())) { if (JSValueIsObjectOfClass(_context, value, RJSObjectClass())) {
realm::Object *object = RJSGetInternal<realm::Object *>(jsObject); realm::Object *object = RJSGetInternal<realm::Object *>(jsObject);
return { return {
"type", RJSTypeGet(realm::PropertyTypeObject).c_str(), {"type", RJSTypeGet(realm::PropertyTypeObject).c_str()},
"id", store_object(jsObject), {"id", store_object(jsObject)},
"schema", serialize_object_schema(object->object_schema) {"schema", serialize_object_schema(object->object_schema)}
}; };
} }
else if (JSValueIsObjectOfClass(_context, value, RJSListClass())) { else if (JSValueIsObjectOfClass(_context, value, RJSListClass())) {
realm::List *list = RJSGetInternal<realm::List *>(jsObject); realm::List *list = RJSGetInternal<realm::List *>(jsObject);
return { return {
"type", RJSTypeGet(realm::PropertyTypeArray), {"type", RJSTypeGet(realm::PropertyTypeArray)},
"id", store_object(jsObject), {"id", store_object(jsObject)},
"size", list->link_view->size(), {"size", list->link_view->size()},
"schema", serialize_object_schema(list->object_schema) {"schema", serialize_object_schema(list->object_schema)}
}; };
} }
else if (JSValueIsObjectOfClass(_context, value, RJSResultsClass())) { else if (JSValueIsObjectOfClass(_context, value, RJSResultsClass())) {
realm::Results *results = RJSGetInternal<realm::Results *>(jsObject); realm::Results *results = RJSGetInternal<realm::Results *>(jsObject);
return { return {
"type", RealmObjectTypesResults, {"type", RealmObjectTypesResults},
"id", store_object(jsObject), {"id", store_object(jsObject)},
"size", results->size(), {"size", results->size()},
"schema", serialize_object_schema(results->object_schema) {"schema", serialize_object_schema(results->object_schema)}
}; };
} }
else if (JSValueIsObjectOfClass(_context, value, RJSNotificationClass())) { else if (JSValueIsObjectOfClass(_context, value, RJSNotificationClass())) {
return { return {
"type", RealmObjectTypesNotification, {"type", RealmObjectTypesNotification},
"id", store_object(jsObject), {"id", store_object(jsObject)},
}; };
} }
else if (RJSIsValueArray(_context, value)) { else if (RJSIsValueArray(_context, value)) {
@ -273,43 +274,44 @@ json RPCServer::serialize_json_value(JSValueRef value) {
for (unsigned int i = 0; i < length; i++) { for (unsigned int i = 0; i < length; i++) {
array.push_back(serialize_json_value(JSObjectGetPropertyAtIndex(_context, jsObject, i, NULL))); array.push_back(serialize_json_value(JSObjectGetPropertyAtIndex(_context, jsObject, i, NULL)));
} }
return {"value", array}; return {{"value", array}};
} }
else if (RJSIsValueDate(_context, value)) { else if (RJSIsValueDate(_context, value)) {
return { return {
"type", RJSTypeGet(realm::PropertyTypeDate), {"type", RJSTypeGet(realm::PropertyTypeDate)},
"value", RJSValidatedValueToNumber(_context, value), {"value", RJSValidatedValueToNumber(_context, value)},
}; };
} }
assert(0); assert(0);
} }
json RPCServer::serialize_object_schema(realm::ObjectSchema &objectSchema) { json RPCServer::serialize_object_schema(realm::ObjectSchema &objectSchema) {
json properties({}); json properties = json::array();
for (realm::Property prop : objectSchema.properties) { for (realm::Property prop : objectSchema.properties) {
properties.push_back({ properties.push_back({
"name", prop.name, {"name", prop.name},
"type", RJSTypeGet(prop.type), {"type", RJSTypeGet(prop.type)},
}); });
} }
return { return {
"name", objectSchema.name, {"name", objectSchema.name},
"properties", properties, {"properties", properties},
}; };
} }
JSValueRef RPCServer::deserialize_json_value(const json dict) JSValueRef RPCServer::deserialize_json_value(const json dict)
{ {
RPCObjectID oid = dict["id"].get<long>(); json oid = dict["id"];
if (oid) { if (oid.is_number()) {
return _objects[oid]; return _objects[oid.get<RPCObjectID>()];
} }
std::string type = dict["type"].get<std::string>();
json value = dict["value"]; json value = dict["value"];
json type = dict["type"];
if (type == RealmObjectTypesFunction) { if (type.is_string()) {
std::string type_string = type.get<std::string>();
if (type_string == RealmObjectTypesFunction) {
// FIXME: Make this actually call the function by its id once we need it to. // FIXME: Make this actually call the function by its id once we need it to.
JSStringRef jsBody = JSStringCreateWithUTF8CString(""); JSStringRef jsBody = JSStringCreateWithUTF8CString("");
JSObjectRef jsFunction = JSObjectMakeFunction(_context, NULL, 0, NULL, jsBody, NULL, 1, NULL); JSObjectRef jsFunction = JSObjectMakeFunction(_context, NULL, 0, NULL, jsBody, NULL, 1, NULL);
@ -317,7 +319,7 @@ JSValueRef RPCServer::deserialize_json_value(const json dict)
return jsFunction; return jsFunction;
} }
else if (type == RJSTypeGet(realm::PropertyTypeDate)) { else if (type_string == RJSTypeGet(realm::PropertyTypeDate)) {
JSValueRef exception = NULL; JSValueRef exception = NULL;
JSValueRef time = JSValueMakeNumber(_context, value.get<double>()); JSValueRef time = JSValueMakeNumber(_context, value.get<double>());
JSObjectRef date = JSObjectMakeDate(_context, 1, &time, &exception); JSObjectRef date = JSObjectMakeDate(_context, 1, &time, &exception);
@ -327,11 +329,9 @@ JSValueRef RPCServer::deserialize_json_value(const json dict)
} }
return date; return date;
} }
if (!value) {
return JSValueMakeUndefined(_context);
} }
else if (value.is_null()) {
if (value.is_null()) {
return JSValueMakeNull(_context); return JSValueMakeNull(_context);
} }
else if (value.is_boolean()) { else if (value.is_boolean()) {