Generalize getting/setting properties through RPC
This commit is contained in:
parent
4c0cc578d5
commit
1b7653206a
20
lib/lists.js
20
lib/lists.js
|
@ -1,7 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
let keys = require('./keys');
|
||||
let rpc = require('./rpc');
|
||||
let types = require('./types');
|
||||
let util = require('./util');
|
||||
|
||||
|
@ -20,21 +18,5 @@ util.createMethods(List.prototype, types.LIST, [
|
|||
], true);
|
||||
|
||||
function create(realmId, info) {
|
||||
return util.createList(List.prototype, realmId, info, getterForLength, getterForIndex, setterForIndex);
|
||||
}
|
||||
|
||||
function getterForLength() {
|
||||
return rpc.getListSize(this[keys.realm], this[keys.id]);
|
||||
}
|
||||
|
||||
function getterForIndex(index) {
|
||||
return function() {
|
||||
return rpc.getListItem(this[keys.realm], this[keys.id], index);
|
||||
};
|
||||
}
|
||||
|
||||
function setterForIndex(index) {
|
||||
return function(value) {
|
||||
rpc.setListItem(this[keys.realm], this[keys.id], index, value);
|
||||
};
|
||||
return util.createList(List.prototype, realmId, info, true);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
let keys = require('./keys');
|
||||
let rpc = require('./rpc');
|
||||
let util = require('./util');
|
||||
|
||||
let registeredConstructors = {};
|
||||
|
||||
|
@ -24,8 +24,8 @@ function create(realmId, info) {
|
|||
let name = prop.name;
|
||||
|
||||
props[name] = {
|
||||
get: getterForProperty(name),
|
||||
set: setterForProperty(name),
|
||||
get: util.getterForProperty(name),
|
||||
set: util.setterForProperty(name),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -37,15 +37,3 @@ function create(realmId, info) {
|
|||
function registerConstructors(realmId, constructors) {
|
||||
registeredConstructors[realmId] = constructors;
|
||||
}
|
||||
|
||||
function getterForProperty(name) {
|
||||
return function() {
|
||||
return rpc.getObjectProperty(this[keys.realm], this[keys.id], name);
|
||||
};
|
||||
}
|
||||
|
||||
function setterForProperty(name) {
|
||||
return function(value) {
|
||||
rpc.setObjectProperty(this[keys.realm], this[keys.id], name, value);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
let internal = require('./internal-types');
|
||||
let keys = require('./keys');
|
||||
let rpc = require('./rpc');
|
||||
let util = require('./util');
|
||||
|
||||
module.exports = {
|
||||
|
@ -16,15 +14,5 @@ util.createMethods(Results.prototype, internal.RESULTS, [
|
|||
]);
|
||||
|
||||
function create(realmId, info) {
|
||||
return util.createList(Results.prototype, realmId, info, getterForLength, getterForIndex);
|
||||
}
|
||||
|
||||
function getterForLength() {
|
||||
return rpc.getResultsSize(this[keys.realm], this[keys.id]);
|
||||
}
|
||||
|
||||
function getterForIndex(index) {
|
||||
return function() {
|
||||
return rpc.getResultsItem(this[keys.realm], this[keys.id], index);
|
||||
};
|
||||
return util.createList(Results.prototype, realmId, info);
|
||||
}
|
||||
|
|
40
lib/rpc.js
40
lib/rpc.js
|
@ -21,17 +21,8 @@ module.exports = {
|
|||
|
||||
createRealm,
|
||||
callMethod,
|
||||
|
||||
getObjectProperty,
|
||||
setObjectProperty,
|
||||
|
||||
getListItem,
|
||||
setListItem,
|
||||
getListSize,
|
||||
|
||||
getResultsItem,
|
||||
getResultsSize,
|
||||
|
||||
getProperty,
|
||||
setProperty,
|
||||
beginTransaction,
|
||||
cancelTransaction,
|
||||
commitTransaction,
|
||||
|
@ -60,39 +51,16 @@ function callMethod(realmId, id, type, name, args) {
|
|||
return deserialize(realmId, result);
|
||||
}
|
||||
|
||||
function getObjectProperty(realmId, id, name) {
|
||||
function getProperty(realmId, id, name) {
|
||||
let result = sendRequest('get_property', {realmId, id, name});
|
||||
return deserialize(realmId, result);
|
||||
}
|
||||
|
||||
function setObjectProperty(realmId, id, name, value) {
|
||||
function setProperty(realmId, id, name, value) {
|
||||
value = serialize(realmId, value);
|
||||
sendRequest('set_property', {realmId, id, name, value});
|
||||
}
|
||||
|
||||
function getListItem(realmId, id, index) {
|
||||
let result = sendRequest('get_list_item', {realmId, id, index});
|
||||
return deserialize(realmId, result);
|
||||
}
|
||||
|
||||
function setListItem(realmId, id, index, value) {
|
||||
value = serialize(realmId, value);
|
||||
sendRequest('set_list_item', {realmId, id, index, value});
|
||||
}
|
||||
|
||||
function getListSize(realmId, id) {
|
||||
return sendRequest('get_list_size', {realmId, id});
|
||||
}
|
||||
|
||||
function getResultsItem(realmId, id, index) {
|
||||
let result = sendRequest('get_results_item', {realmId, id, index});
|
||||
return deserialize(realmId, result);
|
||||
}
|
||||
|
||||
function getResultsSize(realmId, id) {
|
||||
return sendRequest('get_results_size', {realmId, id});
|
||||
}
|
||||
|
||||
function beginTransaction(realmId) {
|
||||
sendRequest('begin_transaction', {realmId});
|
||||
}
|
||||
|
|
22
lib/util.js
22
lib/util.js
|
@ -6,13 +6,15 @@ let rpc = require('./rpc');
|
|||
module.exports = {
|
||||
createList,
|
||||
createMethods,
|
||||
getterForProperty,
|
||||
setterForProperty,
|
||||
};
|
||||
|
||||
function createList(prototype, realmId, info, getterForLength, getterForIndex, setterForIndex) {
|
||||
function createList(prototype, realmId, info, mutable) {
|
||||
let list = Object.create(prototype);
|
||||
let size = 0;
|
||||
|
||||
Object.defineProperty(list, 'length', {get: getterForLength});
|
||||
Object.defineProperty(list, 'length', {get: getterForProperty('length')});
|
||||
|
||||
list[keys.resize] = function(length) {
|
||||
if (length == null) {
|
||||
|
@ -27,8 +29,8 @@ function createList(prototype, realmId, info, getterForLength, getterForIndex, s
|
|||
|
||||
for (let i = size; i < length; i++) {
|
||||
props[i] = {
|
||||
get: getterForIndex(i),
|
||||
set: setterForIndex && setterForIndex(i),
|
||||
get: getterForProperty(i),
|
||||
set: mutable ? setterForProperty(i) : undefined,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
};
|
||||
|
@ -82,3 +84,15 @@ function createMethods(prototype, type, methodNames, resize) {
|
|||
|
||||
Object.defineProperties(prototype, props);
|
||||
}
|
||||
|
||||
function getterForProperty(name) {
|
||||
return function() {
|
||||
return rpc.getProperty(this[keys.realm], this[keys.id], name);
|
||||
};
|
||||
}
|
||||
|
||||
function setterForProperty(name) {
|
||||
return function(value) {
|
||||
rpc.setProperty(this[keys.realm], this[keys.id], name, value);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,6 +23,3 @@
|
|||
extern const JSStaticFunction RJSListFuncs[];
|
||||
JSClassRef RJSListClass();
|
||||
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list);
|
||||
|
||||
JSValueRef ListGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException);
|
||||
bool ListSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException);
|
|
@ -24,7 +24,3 @@ namespace realm {
|
|||
|
||||
JSClassRef RJSObjectClass();
|
||||
JSObjectRef RJSObjectCreate(JSContextRef ctx, realm::Object object);
|
||||
|
||||
JSValueRef ObjectGetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* exception);
|
||||
bool ObjectSetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef value, JSValueRef* exception);
|
||||
|
||||
|
|
|
@ -27,6 +27,3 @@ extern const JSStaticFunction RJSResultsFuncs[];
|
|||
JSClassRef RJSResultsClass();
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className);
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query);
|
||||
|
||||
JSValueRef ResultsGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException);
|
||||
|
||||
|
|
111
src/RealmRPC.mm
111
src/RealmRPC.mm
|
@ -19,6 +19,7 @@
|
|||
#import "RealmRPC.h"
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "RealmJS.h"
|
||||
|
@ -68,6 +69,13 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
|
|||
if (self) {
|
||||
_context = JSGlobalContextCreate(NULL);
|
||||
|
||||
// JavaScriptCore crashes when trying to walk up the native stack to print the stacktrace.
|
||||
// FIXME: Avoid having to do this!
|
||||
static void (*setIncludesNativeCallStack)(JSGlobalContextRef, bool) = (void (*)(JSGlobalContextRef, bool))dlsym(RTLD_DEFAULT, "JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions");
|
||||
if (setIncludesNativeCallStack) {
|
||||
setIncludesNativeCallStack(_context, false);
|
||||
}
|
||||
|
||||
id _self = self;
|
||||
__weak __typeof__(self) self = _self;
|
||||
|
||||
|
@ -112,28 +120,44 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
|
|||
objectId:[dict[@"id"] unsignedLongValue]];
|
||||
};
|
||||
_requests["/get_property"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
|
||||
id name = dict[@"name"];
|
||||
JSValueRef value = NULL;
|
||||
JSValueRef exception = NULL;
|
||||
NSString *name = dict[@"name"];
|
||||
JSStringRef propString = RJSStringForString(name.UTF8String);
|
||||
RPCObjectID objectId = [dict[@"id"] unsignedLongValue];
|
||||
JSValueRef propertyValue = ObjectGetProperty(_context, _objects[objectId], propString, &exception);
|
||||
|
||||
if ([name isKindOfClass:[NSNumber class]]) {
|
||||
value = JSObjectGetPropertyAtIndex(_context, _objects[oid], [name unsignedIntValue], &exception);
|
||||
}
|
||||
else {
|
||||
JSStringRef propString = RJSStringForString([name UTF8String]);
|
||||
value = JSObjectGetProperty(_context, _objects[oid], propString, &exception);
|
||||
JSStringRelease(propString);
|
||||
}
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||
}
|
||||
return @{@"result": [self resultForJSValue:propertyValue]};
|
||||
return @{@"result": [self resultForJSValue:value]};
|
||||
};
|
||||
_requests["/set_property"] = [=](NSDictionary *dict) {
|
||||
JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]);
|
||||
RPCObjectID objectId = [dict[@"id"] unsignedLongValue];
|
||||
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
|
||||
id name = dict[@"name"];
|
||||
JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]];
|
||||
JSValueRef exception = NULL;
|
||||
|
||||
ObjectSetProperty(_context, _objects[objectId], propString, value, &exception);
|
||||
if ([name isKindOfClass:[NSNumber class]]) {
|
||||
JSObjectSetPropertyAtIndex(_context, _objects[oid], [name unsignedIntValue], value, &exception);
|
||||
}
|
||||
else {
|
||||
JSStringRef propString = RJSStringForString([name UTF8String]);
|
||||
JSObjectSetProperty(_context, _objects[oid], propString, value, 0, &exception);
|
||||
JSStringRelease(propString);
|
||||
}
|
||||
|
||||
return exception ? @{@"error": @(RJSStringForValue(_context, exception).c_str())} : @{};
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||
}
|
||||
return @{};
|
||||
};
|
||||
_requests["/dispose_object"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
|
||||
|
@ -141,75 +165,6 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
|
|||
_objects.erase(oid);
|
||||
return nil;
|
||||
};
|
||||
_requests["/get_results_size"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID resultsId = [dict[@"id"] unsignedLongValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
||||
JSValueRef lengthValue = ResultsGetProperty(_context, _objects[resultsId], lengthPropertyName, &exception);
|
||||
size_t length = JSValueToNumber(_context, lengthValue, &exception);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||
}
|
||||
return @{@"result": @(length)};
|
||||
};
|
||||
_requests["/get_results_item"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID resultsId = [dict[@"id"] unsignedLongValue];
|
||||
long index = [dict[@"index"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
|
||||
JSValueRef objectValue = ResultsGetProperty(_context, _objects[resultsId], indexPropertyName, &exception);
|
||||
JSStringRelease(indexPropertyName);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||
}
|
||||
return @{@"result": [self resultForJSValue:objectValue]};
|
||||
};
|
||||
_requests["/get_list_size"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID listId = [dict[@"id"] unsignedLongValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
||||
JSValueRef lengthValue = ListGetProperty(_context, _objects[listId], lengthPropertyName, &exception);
|
||||
size_t length = JSValueToNumber(_context, lengthValue, &exception);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||
}
|
||||
return @{@"result": @(length)};
|
||||
};
|
||||
_requests["/get_list_item"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID listId = [dict[@"id"] unsignedLongValue];
|
||||
long index = [dict[@"index"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
|
||||
JSValueRef objectValue = ListGetProperty(_context, _objects[listId], indexPropertyName, &exception);
|
||||
JSStringRelease(indexPropertyName);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||
}
|
||||
return @{@"result": [self resultForJSValue:objectValue]};
|
||||
};
|
||||
_requests["/set_list_item"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID listId = [dict[@"id"] unsignedLongValue];
|
||||
long index = [dict[@"index"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
|
||||
JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]];
|
||||
ListSetProperty(_context, _objects[listId], indexPropertyName, value, &exception);
|
||||
JSStringRelease(indexPropertyName);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||
}
|
||||
return @{};
|
||||
};
|
||||
_requests["/clear_test_state"] = [=](NSDictionary *dict) {
|
||||
for (auto object : _objects) {
|
||||
JSValueUnprotect(_context, object.second);
|
||||
|
|
Loading…
Reference in New Issue