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';
|
'use strict';
|
||||||
|
|
||||||
let keys = require('./keys');
|
|
||||||
let rpc = require('./rpc');
|
|
||||||
let types = require('./types');
|
let types = require('./types');
|
||||||
let util = require('./util');
|
let util = require('./util');
|
||||||
|
|
||||||
|
@ -20,21 +18,5 @@ util.createMethods(List.prototype, types.LIST, [
|
||||||
], true);
|
], true);
|
||||||
|
|
||||||
function create(realmId, info) {
|
function create(realmId, info) {
|
||||||
return util.createList(List.prototype, realmId, info, getterForLength, getterForIndex, setterForIndex);
|
return util.createList(List.prototype, realmId, info, true);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
let keys = require('./keys');
|
let keys = require('./keys');
|
||||||
let rpc = require('./rpc');
|
let util = require('./util');
|
||||||
|
|
||||||
let registeredConstructors = {};
|
let registeredConstructors = {};
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ function create(realmId, info) {
|
||||||
let name = prop.name;
|
let name = prop.name;
|
||||||
|
|
||||||
props[name] = {
|
props[name] = {
|
||||||
get: getterForProperty(name),
|
get: util.getterForProperty(name),
|
||||||
set: setterForProperty(name),
|
set: util.setterForProperty(name),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,15 +37,3 @@ function create(realmId, info) {
|
||||||
function registerConstructors(realmId, constructors) {
|
function registerConstructors(realmId, constructors) {
|
||||||
registeredConstructors[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';
|
'use strict';
|
||||||
|
|
||||||
let internal = require('./internal-types');
|
let internal = require('./internal-types');
|
||||||
let keys = require('./keys');
|
|
||||||
let rpc = require('./rpc');
|
|
||||||
let util = require('./util');
|
let util = require('./util');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -16,15 +14,5 @@ util.createMethods(Results.prototype, internal.RESULTS, [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function create(realmId, info) {
|
function create(realmId, info) {
|
||||||
return util.createList(Results.prototype, realmId, info, getterForLength, getterForIndex);
|
return util.createList(Results.prototype, realmId, info);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
40
lib/rpc.js
40
lib/rpc.js
|
@ -21,17 +21,8 @@ module.exports = {
|
||||||
|
|
||||||
createRealm,
|
createRealm,
|
||||||
callMethod,
|
callMethod,
|
||||||
|
getProperty,
|
||||||
getObjectProperty,
|
setProperty,
|
||||||
setObjectProperty,
|
|
||||||
|
|
||||||
getListItem,
|
|
||||||
setListItem,
|
|
||||||
getListSize,
|
|
||||||
|
|
||||||
getResultsItem,
|
|
||||||
getResultsSize,
|
|
||||||
|
|
||||||
beginTransaction,
|
beginTransaction,
|
||||||
cancelTransaction,
|
cancelTransaction,
|
||||||
commitTransaction,
|
commitTransaction,
|
||||||
|
@ -60,39 +51,16 @@ function callMethod(realmId, id, type, name, args) {
|
||||||
return deserialize(realmId, result);
|
return deserialize(realmId, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObjectProperty(realmId, id, name) {
|
function getProperty(realmId, id, name) {
|
||||||
let result = sendRequest('get_property', {realmId, id, name});
|
let result = sendRequest('get_property', {realmId, id, name});
|
||||||
return deserialize(realmId, result);
|
return deserialize(realmId, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setObjectProperty(realmId, id, name, value) {
|
function setProperty(realmId, id, name, value) {
|
||||||
value = serialize(realmId, value);
|
value = serialize(realmId, value);
|
||||||
sendRequest('set_property', {realmId, id, name, 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) {
|
function beginTransaction(realmId) {
|
||||||
sendRequest('begin_transaction', {realmId});
|
sendRequest('begin_transaction', {realmId});
|
||||||
}
|
}
|
||||||
|
|
22
lib/util.js
22
lib/util.js
|
@ -6,13 +6,15 @@ let rpc = require('./rpc');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createList,
|
createList,
|
||||||
createMethods,
|
createMethods,
|
||||||
|
getterForProperty,
|
||||||
|
setterForProperty,
|
||||||
};
|
};
|
||||||
|
|
||||||
function createList(prototype, realmId, info, getterForLength, getterForIndex, setterForIndex) {
|
function createList(prototype, realmId, info, mutable) {
|
||||||
let list = Object.create(prototype);
|
let list = Object.create(prototype);
|
||||||
let size = 0;
|
let size = 0;
|
||||||
|
|
||||||
Object.defineProperty(list, 'length', {get: getterForLength});
|
Object.defineProperty(list, 'length', {get: getterForProperty('length')});
|
||||||
|
|
||||||
list[keys.resize] = function(length) {
|
list[keys.resize] = function(length) {
|
||||||
if (length == null) {
|
if (length == null) {
|
||||||
|
@ -27,8 +29,8 @@ function createList(prototype, realmId, info, getterForLength, getterForIndex, s
|
||||||
|
|
||||||
for (let i = size; i < length; i++) {
|
for (let i = size; i < length; i++) {
|
||||||
props[i] = {
|
props[i] = {
|
||||||
get: getterForIndex(i),
|
get: getterForProperty(i),
|
||||||
set: setterForIndex && setterForIndex(i),
|
set: mutable ? setterForProperty(i) : undefined,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
};
|
};
|
||||||
|
@ -82,3 +84,15 @@ function createMethods(prototype, type, methodNames, resize) {
|
||||||
|
|
||||||
Object.defineProperties(prototype, props);
|
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[];
|
extern const JSStaticFunction RJSListFuncs[];
|
||||||
JSClassRef RJSListClass();
|
JSClassRef RJSListClass();
|
||||||
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list);
|
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();
|
JSClassRef RJSObjectClass();
|
||||||
JSObjectRef RJSObjectCreate(JSContextRef ctx, realm::Object object);
|
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();
|
JSClassRef RJSResultsClass();
|
||||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className);
|
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className);
|
||||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query);
|
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query);
|
||||||
|
|
||||||
JSValueRef ResultsGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException);
|
|
||||||
|
|
||||||
|
|
115
src/RealmRPC.mm
115
src/RealmRPC.mm
|
@ -19,6 +19,7 @@
|
||||||
#import "RealmRPC.h"
|
#import "RealmRPC.h"
|
||||||
#import <JavaScriptCore/JavaScriptCore.h>
|
#import <JavaScriptCore/JavaScriptCore.h>
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "RealmJS.h"
|
#include "RealmJS.h"
|
||||||
|
@ -68,6 +69,13 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
|
||||||
if (self) {
|
if (self) {
|
||||||
_context = JSGlobalContextCreate(NULL);
|
_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;
|
id _self = self;
|
||||||
__weak __typeof__(self) self = _self;
|
__weak __typeof__(self) self = _self;
|
||||||
|
|
||||||
|
@ -112,28 +120,44 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
|
||||||
objectId:[dict[@"id"] unsignedLongValue]];
|
objectId:[dict[@"id"] unsignedLongValue]];
|
||||||
};
|
};
|
||||||
_requests["/get_property"] = [=](NSDictionary *dict) {
|
_requests["/get_property"] = [=](NSDictionary *dict) {
|
||||||
|
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
|
||||||
|
id name = dict[@"name"];
|
||||||
|
JSValueRef value = NULL;
|
||||||
JSValueRef exception = NULL;
|
JSValueRef exception = NULL;
|
||||||
NSString *name = dict[@"name"];
|
|
||||||
JSStringRef propString = RJSStringForString(name.UTF8String);
|
if ([name isKindOfClass:[NSNumber class]]) {
|
||||||
RPCObjectID objectId = [dict[@"id"] unsignedLongValue];
|
value = JSObjectGetPropertyAtIndex(_context, _objects[oid], [name unsignedIntValue], &exception);
|
||||||
JSValueRef propertyValue = ObjectGetProperty(_context, _objects[objectId], propString, &exception);
|
}
|
||||||
JSStringRelease(propString);
|
else {
|
||||||
|
JSStringRef propString = RJSStringForString([name UTF8String]);
|
||||||
|
value = JSObjectGetProperty(_context, _objects[oid], propString, &exception);
|
||||||
|
JSStringRelease(propString);
|
||||||
|
}
|
||||||
|
|
||||||
if (exception) {
|
if (exception) {
|
||||||
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
|
||||||
}
|
}
|
||||||
return @{@"result": [self resultForJSValue:propertyValue]};
|
return @{@"result": [self resultForJSValue:value]};
|
||||||
};
|
};
|
||||||
_requests["/set_property"] = [=](NSDictionary *dict) {
|
_requests["/set_property"] = [=](NSDictionary *dict) {
|
||||||
JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]);
|
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
|
||||||
RPCObjectID objectId = [dict[@"id"] unsignedLongValue];
|
id name = dict[@"name"];
|
||||||
JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]];
|
JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]];
|
||||||
JSValueRef exception = NULL;
|
JSValueRef exception = NULL;
|
||||||
|
|
||||||
ObjectSetProperty(_context, _objects[objectId], propString, value, &exception);
|
if ([name isKindOfClass:[NSNumber class]]) {
|
||||||
JSStringRelease(propString);
|
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) {
|
_requests["/dispose_object"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
|
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
|
||||||
|
@ -141,75 +165,6 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
|
||||||
_objects.erase(oid);
|
_objects.erase(oid);
|
||||||
return nil;
|
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) {
|
_requests["/clear_test_state"] = [=](NSDictionary *dict) {
|
||||||
for (auto object : _objects) {
|
for (auto object : _objects) {
|
||||||
JSValueUnprotect(_context, object.second);
|
JSValueUnprotect(_context, object.second);
|
||||||
|
|
Loading…
Reference in New Issue