Fix crash when reloading app during Chrome debugging

Added a session ID, that actually tracks the Realm constructor in our RPC server's JS context. This conveniently let us remove the special casing for defaultPath as well as letting us call the Realm constructor with JSObjectCallAsConstructor.

Fixes #68
This commit is contained in:
Scott Kyle 2015-10-20 15:10:22 -07:00
parent b98e89db22
commit 34b84759c8
4 changed files with 40 additions and 22 deletions

View File

@ -119,12 +119,15 @@ Object.defineProperties(Realm, {
value: Object.freeze(propTypes),
},
defaultPath: {
get: rpc.getDefaultPath,
set: rpc.setDefaultPath,
get: util.getterForProperty('defaultPath'),
set: util.setterForProperty('defaultPath'),
},
clearTestState: {
value: rpc.clearTestState,
},
});
// The session ID refers to the Realm constructor object in the RPC server.
Realm[keys.id] = rpc.createSession();
module.exports = Realm;

View File

@ -7,6 +7,7 @@ let DEVICE_HOST = 'localhost:8082';
let {keys, objectTypes, propTypes} = constants;
let typeConverters = {};
let XMLHttpRequest = window.XMLHttpRequest;
let sessionId;
// Check if XMLHttpRequest has been overridden, and get the native one if that's the case.
if (XMLHttpRequest.__proto__ != window.XMLHttpRequestEventTarget) {
@ -19,8 +20,7 @@ if (XMLHttpRequest.__proto__ != window.XMLHttpRequestEventTarget) {
module.exports = {
registerTypeConverter,
getDefaultPath,
setDefaultPath,
createSession,
createRealm,
callMethod,
getProperty,
@ -36,12 +36,9 @@ function registerTypeConverter(type, handler) {
typeConverters[type] = handler;
}
function getDefaultPath() {
return sendRequest('get_default_path');
}
function setDefaultPath(path) {
sendRequest('set_default_path', {path});
function createSession() {
sessionId = sendRequest('create_session');
return sessionId;
}
function createRealm(args) {
@ -137,7 +134,9 @@ function deserialize(realmId, info) {
}
function sendRequest(command, data) {
let body = JSON.stringify(data || {});
data = Object.assign({}, data, sessionId ? {sessionId} : null);
let body = JSON.stringify(data);
let request = new XMLHttpRequest();
let url = 'http://' + DEVICE_HOST + '/' + command;

View File

@ -31,7 +31,5 @@ JSClassRef RJSNotificationClass();
std::string RJSDefaultPath();
void RJSSetDefaultPath(std::string path);
JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException);
std::map<std::string, realm::ObjectDefaults> &RJSDefaults(realm::Realm *realm);
std::map<std::string, JSValueRef> &RJSPrototypes(realm::Realm *realm);

View File

@ -44,6 +44,7 @@ static const char * const RealmObjectTypesResults = "ObjectTypesRESULTS";
JSGlobalContextRef _context;
std::map<std::string, RPCRequest> _requests;
std::map<RPCObjectID, JSObjectRef> _objects;
RPCObjectID _sessionID;
}
- (void)dealloc {
@ -70,15 +71,22 @@ static const char * const RealmObjectTypesResults = "ObjectTypesRESULTS";
id _self = self;
__weak __typeof__(self) self = _self;
_requests["/get_default_path"] = [=](NSDictionary *dict) {
return @{@"result": @(RJSDefaultPath().c_str())};
};
_requests["/set_default_path"] = [=](NSDictionary *dict) {
NSString *path = dict[@"path"];
RJSSetDefaultPath(path.UTF8String);
return nil;
_requests["/create_session"] = [=](NSDictionary *dict) {
[RealmJS initializeContext:_context];
JSStringRef realmString = RJSStringForString("Realm");
JSObjectRef realmConstructor = RJSValidatedObjectProperty(_context, JSContextGetGlobalObject(_context), realmString);
JSStringRelease(realmString);
_sessionID = [self storeObject:realmConstructor];
return @{@"result": @(_sessionID)};
};
_requests["/create_realm"] = [=](NSDictionary *dict) {
JSObjectRef realmConstructor = _sessionID ? _objects[_sessionID] : NULL;
if (!realmConstructor) {
throw std::runtime_error("Realm constructor not found!");
}
NSArray *args = dict[@"arguments"];
NSUInteger argCount = args.count;
JSValueRef argValues[argCount];
@ -88,7 +96,7 @@ static const char * const RealmObjectTypesResults = "ObjectTypesRESULTS";
}
JSValueRef exception = NULL;
JSObjectRef realmObject = RealmConstructor(_context, NULL, argCount, argValues, &exception);
JSObjectRef realmObject = JSObjectCallAsConstructor(_context, realmConstructor, argCount, argValues, &exception);
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
@ -165,9 +173,14 @@ static const char * const RealmObjectTypesResults = "ObjectTypesRESULTS";
};
_requests["/clear_test_state"] = [=](NSDictionary *dict) {
for (auto object : _objects) {
// The session ID points to the Realm constructor object, which should remain.
if (object.first == _sessionID) {
continue;
}
JSValueUnprotect(_context, object.second);
_objects.erase(object.first);
}
_objects.clear();
JSGarbageCollect(_context);
[RealmJS clearTestState];
return nil;
@ -183,6 +196,11 @@ static const char * const RealmObjectTypesResults = "ObjectTypesRESULTS";
__block id response;
dispatch_sync(dispatch_get_main_queue(), ^{
if (_sessionID != [args[@"sessionId"] unsignedLongValue]) {
response = @{@"error": @"Invalid session ID"};
return;
}
try {
response = action(args);
} catch (std::exception &exception) {