mirror of
https://github.com/status-im/realm-js.git
synced 2025-02-22 11:18:15 +00:00
move rpc server to RealmJS
This commit is contained in:
parent
dbc43726f5
commit
1991d9df95
@ -1,348 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 Realm Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#import "RealmRPC.h"
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "RealmJS.h"
|
||||
#include "RJSObject.hpp"
|
||||
#include "RJSResults.hpp"
|
||||
#include "RJSArray.hpp"
|
||||
#include "RJSRealm.hpp"
|
||||
#include "RJSUtil.hpp"
|
||||
|
||||
#include "object_accessor.hpp"
|
||||
#include "shared_realm.hpp"
|
||||
#include "results.hpp"
|
||||
|
||||
using RPCObjectID = long;
|
||||
using RPCRequest = std::function<NSDictionary *(NSDictionary *dictionary)>;
|
||||
static std::map<std::string, RPCRequest> s_requests;
|
||||
static std::map<RPCObjectID, JSObjectRef> s_objects;
|
||||
|
||||
static JSGlobalContextRef s_context;
|
||||
|
||||
@implementation RJSRPCServer
|
||||
|
||||
+ (void)start {
|
||||
[GCDWebServer setLogLevel:3];
|
||||
|
||||
// Create server
|
||||
GCDWebServer* webServer = [[GCDWebServer alloc] init];
|
||||
s_context = JSGlobalContextCreate(NULL);
|
||||
|
||||
s_requests["/create_realm"] = [=](NSDictionary *dict) {
|
||||
JSValueRef value = [[JSValue valueWithObject:dict
|
||||
inContext:[JSContext contextWithJSGlobalContextRef:s_context]] JSValueRef];
|
||||
RPCObjectID realmId = [self storeObject:RealmConstructor(s_context, NULL, 1, &value, NULL)];
|
||||
return @{@"result": @(realmId)};
|
||||
};
|
||||
s_requests["/begin_transaction"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->begin_transaction();
|
||||
return @{};
|
||||
};
|
||||
s_requests["/cancel_transaction"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->cancel_transaction();
|
||||
return @{};
|
||||
};
|
||||
s_requests["/commit_transaction"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->commit_transaction();
|
||||
return @{};
|
||||
};
|
||||
s_requests["/call_realm_method"] = [=](NSDictionary *dict) {
|
||||
NSString *name = dict[@"name"];
|
||||
return [self performObjectMethod:name.UTF8String
|
||||
classMethods:RJSRealmFuncs
|
||||
args:dict[@"arguments"]
|
||||
objectId:[dict[@"realmId"] longValue]];
|
||||
};
|
||||
s_requests["/dispose_realm"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
JSValueUnprotect(s_context, s_objects[realmId]);
|
||||
s_objects.erase(realmId);
|
||||
return @{};
|
||||
};
|
||||
s_requests["/get_property"] = [=](NSDictionary *dict) {
|
||||
JSValueRef exception = NULL;
|
||||
NSString *name = dict[@"name"];
|
||||
JSStringRef propString = RJSStringForString(name.UTF8String);
|
||||
RPCObjectID objectId = [dict[@"objectId"] longValue];
|
||||
JSValueRef propertyValue = ObjectGetProperty(s_context, s_objects[objectId], propString, &exception);
|
||||
JSStringRelease(propString);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||
}
|
||||
return @{@"result": [self resultForJSValue:propertyValue]};
|
||||
};
|
||||
s_requests["/set_property"] = [=](NSDictionary *dict) {
|
||||
JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]);
|
||||
RPCObjectID realmId = [dict[@"objectId"] longValue];
|
||||
JSValueRef value = [self valueFromDictionary:dict[@"value"]];
|
||||
JSValueRef exception = NULL;
|
||||
|
||||
ObjectSetProperty(s_context, s_objects[realmId], propString, value, &exception);
|
||||
JSStringRelease(propString);
|
||||
|
||||
return exception ? @{@"error": @(RJSStringForValue(s_context, exception).c_str())} : @{};
|
||||
};
|
||||
s_requests["/dispose_object"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID oid = [dict[@"realmId"] longValue];
|
||||
JSValueUnprotect(s_context, s_objects[oid]);
|
||||
s_objects.erase(oid);
|
||||
return @{};
|
||||
};
|
||||
s_requests["/get_results_size"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
||||
JSValueRef lengthValue = ResultsGetProperty(s_context, s_objects[resultsId], lengthPropertyName, &exception);
|
||||
return @{@"result": @(JSValueToNumber(s_context, lengthValue, &exception))};
|
||||
};
|
||||
s_requests["/get_results_item"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
||||
long index = [dict[@"index"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
|
||||
JSValueRef objectValue = ResultsGetProperty(s_context, s_objects[resultsId], indexPropertyName, &exception);
|
||||
JSStringRelease(indexPropertyName);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||
}
|
||||
|
||||
return @{@"result": [self resultForJSValue:objectValue]};
|
||||
};
|
||||
s_requests["/get_list_size"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID listId = [dict[@"listId"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
||||
JSValueRef lengthValue = ArrayGetProperty(s_context, s_objects[listId], lengthPropertyName, &exception);
|
||||
return @{@"result": @(JSValueToNumber(s_context, lengthValue, &exception))};
|
||||
};
|
||||
s_requests["/get_list_item"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID listId = [dict[@"listId"] longValue];
|
||||
long index = [dict[@"index"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
|
||||
JSValueRef objectValue = ArrayGetProperty(s_context, s_objects[listId], indexPropertyName, &exception);
|
||||
JSStringRelease(indexPropertyName);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||
}
|
||||
|
||||
return @{@"result": [self resultForJSValue:objectValue]};
|
||||
};
|
||||
s_requests["/call_list_method"] = [=](NSDictionary *dict) {
|
||||
NSString *name = dict[@"name"];
|
||||
return [self performObjectMethod:name.UTF8String
|
||||
classMethods:RJSArrayFuncs
|
||||
args:dict[@"arguments"]
|
||||
objectId:[dict[@"listId"] longValue]];
|
||||
};
|
||||
|
||||
// Add a handler to respond to GET requests on any URL
|
||||
[webServer addDefaultHandlerForMethod:@"POST"
|
||||
requestClass:[GCDWebServerDataRequest class]
|
||||
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
|
||||
RPCRequest action = s_requests[request.path.UTF8String];
|
||||
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[(GCDWebServerDataRequest *)request data] options:0 error:nil];
|
||||
|
||||
// perform all realm ops on the main thread
|
||||
__block GCDWebServerDataResponse *response;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
response = [GCDWebServerDataResponse responseWithJSONObject:action(json)];
|
||||
});
|
||||
[response setValue:@"http://localhost:8081" forAdditionalHeader:@"Access-Control-Allow-Origin"];
|
||||
return response;
|
||||
}];
|
||||
|
||||
[webServer startWithPort:8082 bonjourName:nil];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)performObjectMethod:(const char *)name
|
||||
classMethods:(const JSStaticFunction [])methods
|
||||
args:(NSArray *)args
|
||||
objectId:(RPCObjectID)oid {
|
||||
NSUInteger count = args.count;
|
||||
JSValueRef argValues[count];
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
argValues[i] = [self valueFromDictionary:args[i]];
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
while (methods[index].name) {
|
||||
if (!strcmp(methods[index].name, name)) {
|
||||
JSValueRef ex = NULL;
|
||||
JSValueRef ret = methods[index].callAsFunction(s_context, NULL, s_objects[oid], count, argValues, &ex);
|
||||
if (ex) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, ex).c_str())};
|
||||
}
|
||||
return @{@"result": [self resultForJSValue:ret]};
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return @{@"error": @"invalid method"};
|
||||
}
|
||||
|
||||
+ (RPCObjectID)storeObject:(JSObjectRef)object {
|
||||
static RPCObjectID s_next_id = 1;
|
||||
RPCObjectID next_id = s_next_id++;
|
||||
JSValueProtect(s_context, object);
|
||||
s_objects[next_id] = object;
|
||||
return next_id;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)resultForJSValue:(JSValueRef)value {
|
||||
switch (JSValueGetType(s_context, value)) {
|
||||
case kJSTypeUndefined:
|
||||
return @{};
|
||||
case kJSTypeNull:
|
||||
return @{@"value": [NSNull null]};
|
||||
case kJSTypeBoolean:
|
||||
return @{@"value": @(JSValueToBoolean(s_context, value))};
|
||||
case kJSTypeNumber:
|
||||
return @{@"value": @(JSValueToNumber(s_context, value, NULL))};
|
||||
case kJSTypeString:
|
||||
return @{@"value": @(RJSStringForValue(s_context, value).c_str())};
|
||||
case kJSTypeObject:
|
||||
break;
|
||||
}
|
||||
|
||||
JSObjectRef jsObject = JSValueToObject(s_context, value, NULL);
|
||||
RPCObjectID oid = [self storeObject:jsObject];
|
||||
|
||||
if (JSValueIsObjectOfClass(s_context, value, RJSObjectClass())) {
|
||||
realm::Object *object = RJSGetInternal<realm::Object *>(jsObject);
|
||||
return @{
|
||||
@"type": @(RJSTypeGet(realm::PropertyTypeObject).c_str()),
|
||||
@"id": @(oid),
|
||||
@"schema": [self objectSchemaToJSONObject:object->object_schema]
|
||||
};
|
||||
}
|
||||
else if (JSValueIsObjectOfClass(s_context, value, RJSArrayClass())) {
|
||||
realm::ObjectArray *array = RJSGetInternal<realm::ObjectArray *>(jsObject);
|
||||
return @{
|
||||
@"type": @(RJSTypeGet(realm::PropertyTypeArray).c_str()),
|
||||
@"id": @(oid),
|
||||
@"size": @(array->link_view->size()),
|
||||
@"schema": [self objectSchemaToJSONObject:array->object_schema]
|
||||
};
|
||||
}
|
||||
else if (JSValueIsObjectOfClass(s_context, value, RJSResultsClass())) {
|
||||
realm::Results *results = RJSGetInternal<realm::Results *>(jsObject);
|
||||
return @{
|
||||
@"type": @"ObjectTypesRESULTS",
|
||||
@"resultsId": @(oid),
|
||||
@"size": @(results->size()),
|
||||
@"schema": [self objectSchemaToJSONObject:results->object_schema]
|
||||
};
|
||||
}
|
||||
else if (RJSIsValueArray(s_context, value)) {
|
||||
JSObjectRef jsObject = JSValueToObject(s_context, value, NULL);
|
||||
size_t length = RJSValidatedArrayLength(s_context, jsObject);
|
||||
NSMutableArray *array = [NSMutableArray new];
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
[array addObject:[self resultForJSValue:JSObjectGetPropertyAtIndex(s_context, jsObject, i, NULL)]];
|
||||
}
|
||||
return @{@"value": array};
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary *)objectSchemaToJSONObject:(realm::ObjectSchema &)objectSchema {
|
||||
NSMutableArray *properties = [[NSMutableArray alloc] init];
|
||||
|
||||
for (realm::Property prop : objectSchema.properties) {
|
||||
NSDictionary *dict = @{
|
||||
@"name": @(prop.name.c_str()),
|
||||
@"type": @(RJSTypeGet(prop.type).c_str()),
|
||||
};
|
||||
|
||||
[properties addObject:dict];
|
||||
}
|
||||
|
||||
return @{
|
||||
@"name": @(objectSchema.name.c_str()),
|
||||
@"properties": properties,
|
||||
};
|
||||
}
|
||||
|
||||
+ (JSValueRef)valueFromDictionary:(NSDictionary *)dict {
|
||||
RPCObjectID oid = [dict[@"id"] longValue];
|
||||
if (oid) {
|
||||
return s_objects[oid];
|
||||
}
|
||||
|
||||
id value = dict[@"value"];
|
||||
if (!value) {
|
||||
return JSValueMakeUndefined(s_context);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSNull class]]) {
|
||||
return JSValueMakeNull(s_context);
|
||||
}
|
||||
else if ([value isKindOfClass:[@YES class]]) {
|
||||
return JSValueMakeBoolean(s_context, [value boolValue]);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSNumber class]]) {
|
||||
return JSValueMakeNumber(s_context, [value doubleValue]);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSString class]]) {
|
||||
return RJSValueForString(s_context, std::string([value UTF8String]));
|
||||
}
|
||||
else if ([value isKindOfClass:[NSArray class]]) {
|
||||
NSUInteger count = [value count];
|
||||
JSValueRef jsValues[count];
|
||||
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
jsValues[i] = [self valueFromDictionary:value[i]];
|
||||
}
|
||||
|
||||
return JSObjectMakeArray(s_context, count, jsValues, NULL);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSDictionary class]]) {
|
||||
JSObjectRef jsObject = JSObjectMake(s_context, NULL, NULL);
|
||||
|
||||
for (NSString *key in value) {
|
||||
JSValueRef jsValue = [self valueFromDictionary:value[key]];
|
||||
JSStringRef jsKey = JSStringCreateWithCFString((__bridge CFStringRef)key);
|
||||
|
||||
JSObjectSetProperty(s_context, jsObject, jsKey, jsValue, 0, NULL);
|
||||
JSStringRelease(jsKey);
|
||||
}
|
||||
|
||||
return jsObject;
|
||||
}
|
||||
|
||||
return JSValueMakeUndefined(s_context);
|
||||
}
|
||||
|
||||
@end
|
@ -17,9 +17,8 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "Base/RCTBridgeModule.h"
|
||||
#import "RealmRPC.h"
|
||||
@import RealmJS;
|
||||
|
||||
@protocol RCTBridgeModule;
|
||||
|
||||
|
@ -20,8 +20,8 @@
|
||||
#import "RealmReactModule.h"
|
||||
#import "Base/RCTLog.h"
|
||||
#import "Base/RCTBridge.h"
|
||||
#import "RealmRPC.h"
|
||||
|
||||
@import GCDWebServers;
|
||||
@import RealmJS;
|
||||
@import JavaScriptCore;
|
||||
|
||||
@ -50,7 +50,22 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
// The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context.
|
||||
if (!contextIvar) {
|
||||
[RJSRPCServer start];
|
||||
|
||||
[GCDWebServer setLogLevel:3];
|
||||
GCDWebServer *webServer = [[GCDWebServer alloc] init];
|
||||
RJSRPCServer *rpcServer = [[RJSRPCServer alloc] init];
|
||||
|
||||
// Add a handler to respond to GET requests on any URL
|
||||
[webServer addDefaultHandlerForMethod:@"POST"
|
||||
requestClass:[GCDWebServerDataRequest class]
|
||||
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
|
||||
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[(GCDWebServerDataRequest *)request data] options:0 error:nil];
|
||||
GCDWebServerDataResponse *response = [GCDWebServerDataResponse responseWithJSONObject:[rpcServer performRequest:request.path args:json]];
|
||||
[response setValue:@"http://localhost:8081" forAdditionalHeader:@"Access-Control-Allow-Origin"];
|
||||
return response;
|
||||
}];
|
||||
|
||||
[webServer startWithPort:8082 bonjourName:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
02258FB31BC6E2D00075F13A /* RealmRPC.h in Headers */ = {isa = PBXBuildFile; fileRef = 02258FB11BC6E2D00075F13A /* RealmRPC.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
02258FB41BC6E2D00075F13A /* RealmRPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 02258FB21BC6E2D00075F13A /* RealmRPC.mm */; settings = {ASSET_TAGS = (); }; };
|
||||
02601F031BA0F0C4007C91FF /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */; };
|
||||
02601F041BA0F0C4007C91FF /* external_commit_helper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */; };
|
||||
02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F051BA0F0CD007C91FF /* index_set.cpp */; };
|
||||
@ -19,16 +21,16 @@
|
||||
0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */; };
|
||||
0270BC4E1B7CFC0D00010E03 /* RJSArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC401B7CFC0D00010E03 /* RJSArray.cpp */; };
|
||||
0270BC4F1B7CFC0D00010E03 /* RJSArray.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC411B7CFC0D00010E03 /* RJSArray.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC421B7CFC0D00010E03 /* RJSObject.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0270BC4F1B7CFC0D00010E03 /* RJSArray.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC411B7CFC0D00010E03 /* RJSArray.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC421B7CFC0D00010E03 /* RJSObject.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC511B7CFC0D00010E03 /* RJSObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC431B7CFC0D00010E03 /* RJSObject.mm */; };
|
||||
0270BC521B7CFC0D00010E03 /* RJSRealm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0270BC521B7CFC0D00010E03 /* RJSRealm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC531B7CFC0D00010E03 /* RJSRealm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC451B7CFC0D00010E03 /* RJSRealm.mm */; };
|
||||
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC461B7CFC0D00010E03 /* RJSResults.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC461B7CFC0D00010E03 /* RJSResults.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC471B7CFC0D00010E03 /* RJSResults.mm */; };
|
||||
0270BC561B7CFC0D00010E03 /* RJSSchema.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC481B7CFC0D00010E03 /* RJSSchema.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0270BC561B7CFC0D00010E03 /* RJSSchema.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC481B7CFC0D00010E03 /* RJSSchema.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC571B7CFC0D00010E03 /* RJSSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC491B7CFC0D00010E03 /* RJSSchema.mm */; };
|
||||
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC4B1B7CFC0D00010E03 /* RJSUtil.mm */; };
|
||||
0270BC671B7CFC1C00010E03 /* object_accessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC5C1B7CFC1C00010E03 /* object_accessor.cpp */; };
|
||||
0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC5D1B7CFC1C00010E03 /* object_accessor.hpp */; };
|
||||
@ -49,7 +51,6 @@
|
||||
0270BC861B7D020100010E03 /* TestObjects.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7F1B7D020100010E03 /* TestObjects.js */; };
|
||||
0270BC871B7D023200010E03 /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
|
||||
0270BCD11B7D067300010E03 /* RealmReactModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0270BCD01B7D067300010E03 /* RealmReactModule.m */; };
|
||||
027799291BC3037900C96559 /* RealmRPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 027799281BC3037900C96559 /* RealmRPC.mm */; settings = {ASSET_TAGS = (); }; };
|
||||
02A3C7971BC4318600B1A7BE /* GCDWebServers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */; };
|
||||
02B29A311B7CF86D008A7E6B /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
|
||||
02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
||||
@ -122,6 +123,8 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
02258FB11BC6E2D00075F13A /* RealmRPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmRPC.h; path = src/RealmRPC.h; sourceTree = "<group>"; };
|
||||
02258FB21BC6E2D00075F13A /* RealmRPC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmRPC.mm; path = src/RealmRPC.mm; sourceTree = "<group>"; };
|
||||
02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/apple/external_commit_helper.cpp"; sourceTree = "<group>"; };
|
||||
02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/apple/external_commit_helper.hpp"; sourceTree = "<group>"; };
|
||||
02601F051BA0F0CD007C91FF /* index_set.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = index_set.cpp; path = "src/object-store/index_set.cpp"; sourceTree = "<group>"; };
|
||||
@ -167,9 +170,7 @@
|
||||
0270BC7F1B7D020100010E03 /* TestObjects.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TestObjects.js; path = tests/TestObjects.js; sourceTree = SOURCE_ROOT; };
|
||||
0270BCCF1B7D067300010E03 /* RealmReactModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmReactModule.h; path = ReactNative/RealmReactModule.h; sourceTree = "<group>"; };
|
||||
0270BCD01B7D067300010E03 /* RealmReactModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RealmReactModule.m; path = ReactNative/RealmReactModule.m; sourceTree = "<group>"; };
|
||||
027799281BC3037900C96559 /* RealmRPC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmRPC.mm; path = ReactNative/RealmRPC.mm; sourceTree = "<group>"; };
|
||||
0277992A1BC3039100C96559 /* RealmRPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmRPC.h; path = ReactNative/RealmRPC.h; sourceTree = "<group>"; };
|
||||
02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = "vendor/GCDWebServer/GCDWebServer.xcodeproj"; sourceTree = "<group>"; };
|
||||
02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = vendor/GCDWebServer/GCDWebServer.xcodeproj; sourceTree = "<group>"; };
|
||||
02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
02B29A161B7CF7C9008A7E6B /* libRealmReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRealmReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -233,6 +234,8 @@
|
||||
02601F071BA0F0CD007C91FF /* realm_delegate.hpp */,
|
||||
0270BC3E1B7CFC0D00010E03 /* RealmJS.h */,
|
||||
0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */,
|
||||
02258FB11BC6E2D00075F13A /* RealmRPC.h */,
|
||||
02258FB21BC6E2D00075F13A /* RealmRPC.mm */,
|
||||
0270BC401B7CFC0D00010E03 /* RJSArray.cpp */,
|
||||
0270BC411B7CFC0D00010E03 /* RJSArray.hpp */,
|
||||
0270BC421B7CFC0D00010E03 /* RJSObject.hpp */,
|
||||
@ -255,8 +258,6 @@
|
||||
children = (
|
||||
0270BCCF1B7D067300010E03 /* RealmReactModule.h */,
|
||||
0270BCD01B7D067300010E03 /* RealmReactModule.m */,
|
||||
027799281BC3037900C96559 /* RealmRPC.mm */,
|
||||
0277992A1BC3039100C96559 /* RealmRPC.h */,
|
||||
);
|
||||
name = ReactNativeModule;
|
||||
sourceTree = "<group>";
|
||||
@ -328,6 +329,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */,
|
||||
02258FB31BC6E2D00075F13A /* RealmRPC.h in Headers */,
|
||||
0270BC4F1B7CFC0D00010E03 /* RJSArray.hpp in Headers */,
|
||||
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */,
|
||||
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */,
|
||||
@ -535,7 +537,6 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0270BCD11B7D067300010E03 /* RealmReactModule.m in Sources */,
|
||||
027799291BC3037900C96559 /* RealmRPC.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -550,6 +551,7 @@
|
||||
0270BC511B7CFC0D00010E03 /* RJSObject.mm in Sources */,
|
||||
0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */,
|
||||
02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */,
|
||||
02258FB41BC6E2D00075F13A /* RealmRPC.mm in Sources */,
|
||||
02601F111BA10228007C91FF /* transact_log_handler.cpp in Sources */,
|
||||
0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */,
|
||||
0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */,
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#import <RealmJS/RealmRPC.h>
|
||||
|
||||
@interface RealmJS : NSObject
|
||||
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#import <GCDWebServers/GCDWebServers.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface RJSRPCServer : NSObject
|
||||
|
||||
+ (void)start;
|
||||
- (NSDictionary *)performRequest:(NSString *)name args:(NSDictionary *)args;
|
||||
|
||||
@end
|
339
src/RealmRPC.mm
Normal file
339
src/RealmRPC.mm
Normal file
@ -0,0 +1,339 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 Realm Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#import "RealmRPC.h"
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "RealmJS.h"
|
||||
#include "RJSObject.hpp"
|
||||
#include "RJSResults.hpp"
|
||||
#include "RJSArray.hpp"
|
||||
#include "RJSRealm.hpp"
|
||||
#include "RJSUtil.hpp"
|
||||
|
||||
#include "object_accessor.hpp"
|
||||
#include "shared_realm.hpp"
|
||||
#include "results.hpp"
|
||||
|
||||
using RPCObjectID = long;
|
||||
using RPCRequest = std::function<NSDictionary *(NSDictionary *dictionary)>;
|
||||
|
||||
@implementation RJSRPCServer {
|
||||
JSGlobalContextRef s_context;
|
||||
std::map<std::string, RPCRequest> s_requests;
|
||||
std::map<RPCObjectID, JSObjectRef> s_objects;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
s_context = JSGlobalContextCreate(NULL);
|
||||
s_requests["/create_realm"] = [=](NSDictionary *dict) {
|
||||
JSValueRef value = [[JSValue valueWithObject:dict
|
||||
inContext:[JSContext contextWithJSGlobalContextRef:s_context]] JSValueRef];
|
||||
RPCObjectID realmId = [self storeObject:RealmConstructor(s_context, NULL, 1, &value, NULL)];
|
||||
return @{@"result": @(realmId)};
|
||||
};
|
||||
s_requests["/begin_transaction"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->begin_transaction();
|
||||
return @{};
|
||||
};
|
||||
s_requests["/cancel_transaction"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->cancel_transaction();
|
||||
return @{};
|
||||
};
|
||||
s_requests["/commit_transaction"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->commit_transaction();
|
||||
return @{};
|
||||
};
|
||||
s_requests["/call_realm_method"] = [=](NSDictionary *dict) {
|
||||
NSString *name = dict[@"name"];
|
||||
return [self performObjectMethod:name.UTF8String
|
||||
classMethods:RJSRealmFuncs
|
||||
args:dict[@"arguments"]
|
||||
objectId:[dict[@"realmId"] longValue]];
|
||||
};
|
||||
s_requests["/dispose_realm"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||
JSValueUnprotect(s_context, s_objects[realmId]);
|
||||
s_objects.erase(realmId);
|
||||
return @{};
|
||||
};
|
||||
s_requests["/get_property"] = [=](NSDictionary *dict) {
|
||||
JSValueRef exception = NULL;
|
||||
NSString *name = dict[@"name"];
|
||||
JSStringRef propString = RJSStringForString(name.UTF8String);
|
||||
RPCObjectID objectId = [dict[@"objectId"] longValue];
|
||||
JSValueRef propertyValue = ObjectGetProperty(s_context, s_objects[objectId], propString, &exception);
|
||||
JSStringRelease(propString);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||
}
|
||||
return @{@"result": [self resultForJSValue:propertyValue]};
|
||||
};
|
||||
s_requests["/set_property"] = [=](NSDictionary *dict) {
|
||||
JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]);
|
||||
RPCObjectID realmId = [dict[@"objectId"] longValue];
|
||||
JSValueRef value = [self valueFromDictionary:dict[@"value"]];
|
||||
JSValueRef exception = NULL;
|
||||
|
||||
ObjectSetProperty(s_context, s_objects[realmId], propString, value, &exception);
|
||||
JSStringRelease(propString);
|
||||
|
||||
return exception ? @{@"error": @(RJSStringForValue(s_context, exception).c_str())} : @{};
|
||||
};
|
||||
s_requests["/dispose_object"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID oid = [dict[@"realmId"] longValue];
|
||||
JSValueUnprotect(s_context, s_objects[oid]);
|
||||
s_objects.erase(oid);
|
||||
return @{};
|
||||
};
|
||||
s_requests["/get_results_size"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
||||
JSValueRef lengthValue = ResultsGetProperty(s_context, s_objects[resultsId], lengthPropertyName, &exception);
|
||||
return @{@"result": @(JSValueToNumber(s_context, lengthValue, &exception))};
|
||||
};
|
||||
s_requests["/get_results_item"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
||||
long index = [dict[@"index"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
|
||||
JSValueRef objectValue = ResultsGetProperty(s_context, s_objects[resultsId], indexPropertyName, &exception);
|
||||
JSStringRelease(indexPropertyName);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||
}
|
||||
|
||||
return @{@"result": [self resultForJSValue:objectValue]};
|
||||
};
|
||||
s_requests["/get_list_size"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID listId = [dict[@"listId"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
||||
JSValueRef lengthValue = ArrayGetProperty(s_context, s_objects[listId], lengthPropertyName, &exception);
|
||||
return @{@"result": @(JSValueToNumber(s_context, lengthValue, &exception))};
|
||||
};
|
||||
s_requests["/get_list_item"] = [=](NSDictionary *dict) {
|
||||
RPCObjectID listId = [dict[@"listId"] longValue];
|
||||
long index = [dict[@"index"] longValue];
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
|
||||
JSValueRef objectValue = ArrayGetProperty(s_context, s_objects[listId], indexPropertyName, &exception);
|
||||
JSStringRelease(indexPropertyName);
|
||||
|
||||
if (exception) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||
}
|
||||
|
||||
return @{@"result": [self resultForJSValue:objectValue]};
|
||||
};
|
||||
s_requests["/call_list_method"] = [=](NSDictionary *dict) {
|
||||
NSString *name = dict[@"name"];
|
||||
return [self performObjectMethod:name.UTF8String
|
||||
classMethods:RJSArrayFuncs
|
||||
args:dict[@"arguments"]
|
||||
objectId:[dict[@"listId"] longValue]];
|
||||
};
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)performRequest:(NSString *)name args:(NSDictionary *)args {
|
||||
// perform all realm ops on the main thread
|
||||
RPCRequest action = s_requests[name.UTF8String];
|
||||
__block id response;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
response = action(args);
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
- (NSDictionary *)performObjectMethod:(const char *)name
|
||||
classMethods:(const JSStaticFunction [])methods
|
||||
args:(NSArray *)args
|
||||
objectId:(RPCObjectID)oid {
|
||||
NSUInteger count = args.count;
|
||||
JSValueRef argValues[count];
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
argValues[i] = [self valueFromDictionary:args[i]];
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
while (methods[index].name) {
|
||||
if (!strcmp(methods[index].name, name)) {
|
||||
JSValueRef ex = NULL;
|
||||
JSValueRef ret = methods[index].callAsFunction(s_context, NULL, s_objects[oid], count, argValues, &ex);
|
||||
if (ex) {
|
||||
return @{@"error": @(RJSStringForValue(s_context, ex).c_str())};
|
||||
}
|
||||
return @{@"result": [self resultForJSValue:ret]};
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return @{@"error": @"invalid method"};
|
||||
}
|
||||
|
||||
- (RPCObjectID)storeObject:(JSObjectRef)object {
|
||||
static RPCObjectID s_next_id = 1;
|
||||
RPCObjectID next_id = s_next_id++;
|
||||
JSValueProtect(s_context, object);
|
||||
s_objects[next_id] = object;
|
||||
return next_id;
|
||||
}
|
||||
|
||||
- (NSDictionary *)resultForJSValue:(JSValueRef)value {
|
||||
switch (JSValueGetType(s_context, value)) {
|
||||
case kJSTypeUndefined:
|
||||
return @{};
|
||||
case kJSTypeNull:
|
||||
return @{@"value": [NSNull null]};
|
||||
case kJSTypeBoolean:
|
||||
return @{@"value": @(JSValueToBoolean(s_context, value))};
|
||||
case kJSTypeNumber:
|
||||
return @{@"value": @(JSValueToNumber(s_context, value, NULL))};
|
||||
case kJSTypeString:
|
||||
return @{@"value": @(RJSStringForValue(s_context, value).c_str())};
|
||||
case kJSTypeObject:
|
||||
break;
|
||||
}
|
||||
|
||||
JSObjectRef jsObject = JSValueToObject(s_context, value, NULL);
|
||||
RPCObjectID oid = [self storeObject:jsObject];
|
||||
|
||||
if (JSValueIsObjectOfClass(s_context, value, RJSObjectClass())) {
|
||||
realm::Object *object = RJSGetInternal<realm::Object *>(jsObject);
|
||||
return @{
|
||||
@"type": @(RJSTypeGet(realm::PropertyTypeObject).c_str()),
|
||||
@"id": @(oid),
|
||||
@"schema": [self objectSchemaToJSONObject:object->object_schema]
|
||||
};
|
||||
}
|
||||
else if (JSValueIsObjectOfClass(s_context, value, RJSArrayClass())) {
|
||||
realm::ObjectArray *array = RJSGetInternal<realm::ObjectArray *>(jsObject);
|
||||
return @{
|
||||
@"type": @(RJSTypeGet(realm::PropertyTypeArray).c_str()),
|
||||
@"id": @(oid),
|
||||
@"size": @(array->link_view->size()),
|
||||
@"schema": [self objectSchemaToJSONObject:array->object_schema]
|
||||
};
|
||||
}
|
||||
else if (JSValueIsObjectOfClass(s_context, value, RJSResultsClass())) {
|
||||
realm::Results *results = RJSGetInternal<realm::Results *>(jsObject);
|
||||
return @{
|
||||
@"type": @"ObjectTypesRESULTS",
|
||||
@"resultsId": @(oid),
|
||||
@"size": @(results->size()),
|
||||
@"schema": [self objectSchemaToJSONObject:results->object_schema]
|
||||
};
|
||||
}
|
||||
else if (RJSIsValueArray(s_context, value)) {
|
||||
JSObjectRef jsObject = JSValueToObject(s_context, value, NULL);
|
||||
size_t length = RJSValidatedArrayLength(s_context, jsObject);
|
||||
NSMutableArray *array = [NSMutableArray new];
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
[array addObject:[self resultForJSValue:JSObjectGetPropertyAtIndex(s_context, jsObject, i, NULL)]];
|
||||
}
|
||||
return @{@"value": array};
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)objectSchemaToJSONObject:(realm::ObjectSchema &)objectSchema {
|
||||
NSMutableArray *properties = [[NSMutableArray alloc] init];
|
||||
|
||||
for (realm::Property prop : objectSchema.properties) {
|
||||
NSDictionary *dict = @{
|
||||
@"name": @(prop.name.c_str()),
|
||||
@"type": @(RJSTypeGet(prop.type).c_str()),
|
||||
};
|
||||
|
||||
[properties addObject:dict];
|
||||
}
|
||||
|
||||
return @{
|
||||
@"name": @(objectSchema.name.c_str()),
|
||||
@"properties": properties,
|
||||
};
|
||||
}
|
||||
|
||||
- (JSValueRef)valueFromDictionary:(NSDictionary *)dict {
|
||||
RPCObjectID oid = [dict[@"id"] longValue];
|
||||
if (oid) {
|
||||
return s_objects[oid];
|
||||
}
|
||||
|
||||
id value = dict[@"value"];
|
||||
if (!value) {
|
||||
return JSValueMakeUndefined(s_context);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSNull class]]) {
|
||||
return JSValueMakeNull(s_context);
|
||||
}
|
||||
else if ([value isKindOfClass:[@YES class]]) {
|
||||
return JSValueMakeBoolean(s_context, [value boolValue]);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSNumber class]]) {
|
||||
return JSValueMakeNumber(s_context, [value doubleValue]);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSString class]]) {
|
||||
return RJSValueForString(s_context, std::string([value UTF8String]));
|
||||
}
|
||||
else if ([value isKindOfClass:[NSArray class]]) {
|
||||
NSUInteger count = [value count];
|
||||
JSValueRef jsValues[count];
|
||||
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
jsValues[i] = [self valueFromDictionary:value[i]];
|
||||
}
|
||||
|
||||
return JSObjectMakeArray(s_context, count, jsValues, NULL);
|
||||
}
|
||||
else if ([value isKindOfClass:[NSDictionary class]]) {
|
||||
JSObjectRef jsObject = JSObjectMake(s_context, NULL, NULL);
|
||||
|
||||
for (NSString *key in value) {
|
||||
JSValueRef jsValue = [self valueFromDictionary:value[key]];
|
||||
JSStringRef jsKey = JSStringCreateWithCFString((__bridge CFStringRef)key);
|
||||
|
||||
JSObjectSetProperty(s_context, jsObject, jsKey, jsValue, 0, NULL);
|
||||
JSStringRelease(jsKey);
|
||||
}
|
||||
|
||||
return jsObject;
|
||||
}
|
||||
|
||||
return JSValueMakeUndefined(s_context);
|
||||
}
|
||||
|
||||
@end
|
Loading…
x
Reference in New Issue
Block a user