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), value: Object.freeze(propTypes),
}, },
defaultPath: { defaultPath: {
get: rpc.getDefaultPath, get: util.getterForProperty('defaultPath'),
set: rpc.setDefaultPath, set: util.setterForProperty('defaultPath'),
}, },
clearTestState: { clearTestState: {
value: rpc.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; module.exports = Realm;

View File

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

View File

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