Make RPC server return Results properly
Still doesn't handle returning property values.
This commit is contained in:
parent
141ce2cb6d
commit
e136da5117
|
@ -21,16 +21,18 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "RealmJS.h"
|
||||||
#include "RJSObject.hpp"
|
#include "RJSObject.hpp"
|
||||||
#include "RJSResults.hpp"
|
#include "RJSResults.hpp"
|
||||||
#include "RJSRealm.hpp"
|
#include "RJSRealm.hpp"
|
||||||
#include "RJSUtil.hpp"
|
#include "RJSUtil.hpp"
|
||||||
|
|
||||||
|
#include "object_accessor.hpp"
|
||||||
#include "shared_realm.hpp"
|
#include "shared_realm.hpp"
|
||||||
#include "results.hpp"
|
#include "results.hpp"
|
||||||
|
|
||||||
using RPCObjectID = long;
|
using RPCObjectID = long;
|
||||||
using RPCRequest = std::function<std::string(NSDictionary *dictionary)>;
|
using RPCRequest = std::function<NSDictionary *(NSDictionary *dictionary)>;
|
||||||
static std::map<std::string, RPCRequest> s_requests;
|
static std::map<std::string, RPCRequest> s_requests;
|
||||||
static std::map<RPCObjectID, JSObjectRef> s_objects;
|
static std::map<RPCObjectID, JSObjectRef> s_objects;
|
||||||
|
|
||||||
|
@ -49,22 +51,22 @@ static RPCObjectID s_id_counter = 0;
|
||||||
JSValueRef value = [[JSValue valueWithObject:dict
|
JSValueRef value = [[JSValue valueWithObject:dict
|
||||||
inContext:[JSContext contextWithJSGlobalContextRef:s_context]] JSValueRef];
|
inContext:[JSContext contextWithJSGlobalContextRef:s_context]] JSValueRef];
|
||||||
s_objects[realmId] = RealmConstructor(s_context, NULL, 1, &value, NULL);
|
s_objects[realmId] = RealmConstructor(s_context, NULL, 1, &value, NULL);
|
||||||
return "{\"realmId\":" + std::to_string(realmId) + "}";
|
return @{@"result": @(realmId)};
|
||||||
};
|
};
|
||||||
s_requests["/begin_transaction"] = [=](NSDictionary *dict) {
|
s_requests["/begin_transaction"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->begin_transaction();
|
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->begin_transaction();
|
||||||
return "{}";
|
return @{};
|
||||||
};
|
};
|
||||||
s_requests["/cancel_transaction"] = [=](NSDictionary *dict) {
|
s_requests["/cancel_transaction"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->cancel_transaction();
|
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->cancel_transaction();
|
||||||
return "{}";
|
return @{};
|
||||||
};
|
};
|
||||||
s_requests["/commit_transaction"] = [=](NSDictionary *dict) {
|
s_requests["/commit_transaction"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||||
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->commit_transaction();
|
RJSGetInternal<realm::SharedRealm *>(s_objects[realmId])->get()->commit_transaction();
|
||||||
return "{}";
|
return @{};
|
||||||
};
|
};
|
||||||
s_requests["/create_object"] = [=](NSDictionary *dict) {
|
s_requests["/create_object"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID newOid = s_id_counter++;
|
RPCObjectID newOid = s_id_counter++;
|
||||||
|
@ -75,21 +77,27 @@ static RPCObjectID s_id_counter = 0;
|
||||||
JSValueRef object = RealmCreateObject(s_context, NULL, s_objects[realmId], 1, &value, &exception);
|
JSValueRef object = RealmCreateObject(s_context, NULL, s_objects[realmId], 1, &value, &exception);
|
||||||
JSValueProtect(s_context, object);
|
JSValueProtect(s_context, object);
|
||||||
s_objects[newOid] = (JSObjectRef)object;
|
s_objects[newOid] = (JSObjectRef)object;
|
||||||
return std::to_string(newOid);
|
return @{@"result": @{@"type": @"PropTypesOBJECT", @"id": @(newOid)}};
|
||||||
};
|
};
|
||||||
s_requests["/dispose_realm"] = [=](NSDictionary *dict) {
|
s_requests["/dispose_realm"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||||
JSValueUnprotect(s_context, s_objects[realmId]);
|
JSValueUnprotect(s_context, s_objects[realmId]);
|
||||||
s_objects.erase(realmId);
|
s_objects.erase(realmId);
|
||||||
return "";
|
return @{};
|
||||||
};
|
};
|
||||||
s_requests["/get_property"] = [=](NSDictionary *dict) {
|
s_requests["/get_property"] = [=](NSDictionary *dict) {
|
||||||
|
JSValueRef exception = NULL;
|
||||||
JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]);
|
JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]);
|
||||||
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
RPCObjectID realmId = [dict[@"realmId"] longValue];
|
||||||
JSValueRef propertyValue = ObjectGetProperty(s_context, s_objects[realmId], propString, NULL);
|
JSValueRef propertyValue = ObjectGetProperty(s_context, s_objects[realmId], propString, &exception);
|
||||||
JSStringRelease(propString);
|
JSStringRelease(propString);
|
||||||
|
|
||||||
return RJSValidatedStringForValue(s_context, propertyValue);
|
if (exception) {
|
||||||
|
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Convert propertyValue to appropriate type!
|
||||||
|
return @{};
|
||||||
};
|
};
|
||||||
s_requests["/set_property"] = [=](NSDictionary *dict) {
|
s_requests["/set_property"] = [=](NSDictionary *dict) {
|
||||||
JSValueRef exception = NULL;
|
JSValueRef exception = NULL;
|
||||||
|
@ -100,13 +108,13 @@ static RPCObjectID s_id_counter = 0;
|
||||||
ObjectSetProperty(s_context, s_objects[realmId], propString, value, &exception);
|
ObjectSetProperty(s_context, s_objects[realmId], propString, value, &exception);
|
||||||
JSStringRelease(propString);
|
JSStringRelease(propString);
|
||||||
|
|
||||||
return exception ? "exception" : "";
|
return exception ? @{@"error": @(RJSStringForValue(s_context, exception).c_str())} : @{};
|
||||||
};
|
};
|
||||||
s_requests["/dispose_object"] = [=](NSDictionary *dict) {
|
s_requests["/dispose_object"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID oid = [dict[@"realmId"] longValue];
|
RPCObjectID oid = [dict[@"realmId"] longValue];
|
||||||
JSValueUnprotect(s_context, s_objects[oid]);
|
JSValueUnprotect(s_context, s_objects[oid]);
|
||||||
s_objects.erase(oid);
|
s_objects.erase(oid);
|
||||||
return "";
|
return @{};
|
||||||
};
|
};
|
||||||
s_requests["/get_objects"] = [=](NSDictionary *dict) {
|
s_requests["/get_objects"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID resultsId = s_id_counter++;
|
RPCObjectID resultsId = s_id_counter++;
|
||||||
|
@ -126,7 +134,7 @@ static RPCObjectID s_id_counter = 0;
|
||||||
JSValueProtect(s_context, results);
|
JSValueProtect(s_context, results);
|
||||||
s_objects[resultsId] = (JSObjectRef)results;
|
s_objects[resultsId] = (JSObjectRef)results;
|
||||||
size_t size = RJSGetInternal<realm::Results *>((JSObjectRef)results)->size();
|
size_t size = RJSGetInternal<realm::Results *>((JSObjectRef)results)->size();
|
||||||
return "{\"result\":{\"resultsId\":" + std::to_string(resultsId) + ", \"size\":" + std::to_string(size) + "}}";
|
return @{@"result": @{@"resultsId": @(resultsId), @"size": @(size)}};
|
||||||
};
|
};
|
||||||
s_requests["/get_results_size"] = [=](NSDictionary *dict) {
|
s_requests["/get_results_size"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
||||||
|
@ -134,7 +142,7 @@ static RPCObjectID s_id_counter = 0;
|
||||||
JSValueRef exception = NULL;
|
JSValueRef exception = NULL;
|
||||||
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
|
||||||
JSValueRef lengthValue = ResultsGetProperty(s_context, s_objects[resultsId], lengthPropertyName, &exception);
|
JSValueRef lengthValue = ResultsGetProperty(s_context, s_objects[resultsId], lengthPropertyName, &exception);
|
||||||
return "{\"result\":" + std::to_string(JSValueToNumber(s_context, lengthValue, &exception)) + "}";
|
return @{@"result": @(JSValueToNumber(s_context, lengthValue, &exception))};
|
||||||
};
|
};
|
||||||
s_requests["/get_results_item"] = [=](NSDictionary *dict) {
|
s_requests["/get_results_item"] = [=](NSDictionary *dict) {
|
||||||
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
RPCObjectID resultsId = [dict[@"resultsId"] longValue];
|
||||||
|
@ -145,10 +153,22 @@ static RPCObjectID s_id_counter = 0;
|
||||||
JSValueRef objectValue = ResultsGetProperty(s_context, s_objects[resultsId], indexPropertyName, &exception);
|
JSValueRef objectValue = ResultsGetProperty(s_context, s_objects[resultsId], indexPropertyName, &exception);
|
||||||
JSStringRelease(indexPropertyName);
|
JSStringRelease(indexPropertyName);
|
||||||
|
|
||||||
|
if (exception) {
|
||||||
|
return @{@"error": @(RJSStringForValue(s_context, exception).c_str())};
|
||||||
|
}
|
||||||
|
|
||||||
RPCObjectID newOid = s_id_counter++;
|
RPCObjectID newOid = s_id_counter++;
|
||||||
JSValueProtect(s_context, objectValue);
|
JSValueProtect(s_context, objectValue);
|
||||||
s_objects[newOid] = (JSObjectRef)objectValue;
|
s_objects[newOid] = (JSObjectRef)objectValue;
|
||||||
return "{\"result\":" + std::to_string(newOid) + "}";
|
|
||||||
|
realm::Object *object = RJSGetInternal<realm::Object *>((JSObjectRef)objectValue);
|
||||||
|
return @{
|
||||||
|
@"result": @{
|
||||||
|
@"type": @(RJSTypeGet(realm::PropertyTypeObject).c_str()),
|
||||||
|
@"id": @(newOid),
|
||||||
|
@"schema": [self schemaForObject:object],
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add a handler to respond to GET requests on any URL
|
// Add a handler to respond to GET requests on any URL
|
||||||
|
@ -157,13 +177,32 @@ static RPCObjectID s_id_counter = 0;
|
||||||
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
|
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
|
||||||
RPCRequest action = s_requests[request.path.UTF8String];
|
RPCRequest action = s_requests[request.path.UTF8String];
|
||||||
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[(GCDWebServerDataRequest *)request data] options:0 error:nil];
|
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[(GCDWebServerDataRequest *)request data] options:0 error:nil];
|
||||||
GCDWebServerDataResponse *response = [GCDWebServerDataResponse responseWithHTML:@(action(json).c_str())];
|
GCDWebServerDataResponse *response = [GCDWebServerDataResponse responseWithJSONObject:action(json)];
|
||||||
[response setValue:@"http://localhost:8081" forAdditionalHeader:@"Access-Control-Allow-Origin"];
|
[response setValue:@"http://localhost:8081" forAdditionalHeader:@"Access-Control-Allow-Origin"];
|
||||||
return response;
|
return response;
|
||||||
}];
|
}];
|
||||||
[webServer startWithPort:8082 bonjourName:nil];
|
[webServer startWithPort:8082 bonjourName:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary *)schemaForObject:(realm::Object *)object {
|
||||||
|
realm::ObjectSchema &objectSchema = object->object_schema;
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <JavaScriptCore/JavaScriptCore.h>
|
#include <JavaScriptCore/JavaScriptCore.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include "property.hpp"
|
||||||
#include "schema.hpp"
|
#include "schema.hpp"
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -55,7 +56,11 @@ JSClassRef RJSCreateWrapperClass(const char * name, JSObjectGetPropertyCallback
|
||||||
|
|
||||||
JSObjectRef RJSRegisterGlobalClass(JSContextRef ctx, JSObjectRef globalObject, JSClassRef classRef, const char * name, JSValueRef *exception);
|
JSObjectRef RJSRegisterGlobalClass(JSContextRef ctx, JSObjectRef globalObject, JSClassRef classRef, const char * name, JSValueRef *exception);
|
||||||
|
|
||||||
|
std::string RJSTypeGet(realm::PropertyType propertyType);
|
||||||
|
std::string RJSTypeGet(std::string typeString);
|
||||||
|
|
||||||
std::string RJSStringForJSString(JSStringRef jsString);
|
std::string RJSStringForJSString(JSStringRef jsString);
|
||||||
|
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value);
|
||||||
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name = nullptr);
|
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name = nullptr);
|
||||||
|
|
||||||
JSStringRef RJSStringForString(const std::string &str);
|
JSStringRef RJSStringForString(const std::string &str);
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
#import "RJSUtil.hpp"
|
#import "RJSUtil.hpp"
|
||||||
|
|
||||||
|
using namespace realm;
|
||||||
|
|
||||||
JSObjectRef RJSRegisterGlobalClass(JSContextRef ctx, JSObjectRef globalObject, JSClassRef classRef, const char * name, JSValueRef *exception) {
|
JSObjectRef RJSRegisterGlobalClass(JSContextRef ctx, JSObjectRef globalObject, JSClassRef classRef, const char * name, JSValueRef *exception) {
|
||||||
JSObjectRef classObject = JSObjectMake(ctx, classRef, NULL);
|
JSObjectRef classObject = JSObjectMake(ctx, classRef, NULL);
|
||||||
JSStringRef nameString = JSStringCreateWithUTF8CString(name);
|
JSStringRef nameString = JSStringCreateWithUTF8CString(name);
|
||||||
|
@ -43,6 +45,35 @@ JSValueRef RJSMakeError(JSContextRef ctx, const std::string &message) {
|
||||||
return JSObjectMakeError(ctx, 1, &value, NULL);
|
return JSObjectMakeError(ctx, 1, &value, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RJSTypeGet(PropertyType propertyType) {
|
||||||
|
switch (propertyType) {
|
||||||
|
case PropertyTypeBool:
|
||||||
|
return RJSTypeGet("BOOL");
|
||||||
|
case PropertyTypeInt:
|
||||||
|
return RJSTypeGet("INT");
|
||||||
|
case PropertyTypeFloat:
|
||||||
|
return RJSTypeGet("FLOAT");
|
||||||
|
case PropertyTypeDouble:
|
||||||
|
return RJSTypeGet("DOUBLE");
|
||||||
|
case PropertyTypeString:
|
||||||
|
return RJSTypeGet("STRING");
|
||||||
|
case PropertyTypeDate:
|
||||||
|
return RJSTypeGet("DATE");
|
||||||
|
case PropertyTypeData:
|
||||||
|
return RJSTypeGet("DATA");
|
||||||
|
case PropertyTypeObject:
|
||||||
|
return RJSTypeGet("OBJECT");
|
||||||
|
case PropertyTypeArray:
|
||||||
|
return RJSTypeGet("LIST");
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RJSTypeGet(std::string propertyTypeString) {
|
||||||
|
return "PropTypes" + propertyTypeString;
|
||||||
|
}
|
||||||
|
|
||||||
std::string RJSStringForJSString(JSStringRef jsString) {
|
std::string RJSStringForJSString(JSStringRef jsString) {
|
||||||
std::string str;
|
std::string str;
|
||||||
size_t maxSize = JSStringGetMaximumUTF8CStringSize(jsString);
|
size_t maxSize = JSStringGetMaximumUTF8CStringSize(jsString);
|
||||||
|
@ -51,6 +82,19 @@ std::string RJSStringForJSString(JSStringRef jsString) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value) {
|
||||||
|
JSValueRef *exception;
|
||||||
|
JSStringRef jsString = JSValueToStringCopy(ctx, value, exception);
|
||||||
|
if (!jsString) {
|
||||||
|
throw RJSException(ctx, *exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string string = RJSStringForJSString(jsString);
|
||||||
|
JSStringRelease(jsString);
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name) {
|
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name) {
|
||||||
if (!JSValueIsString(ctx, value)) {
|
if (!JSValueIsString(ctx, value)) {
|
||||||
if (name) {
|
if (name) {
|
||||||
|
@ -61,13 +105,7 @@ std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValueRef *exception;
|
return RJSStringForValue(ctx, value);
|
||||||
JSStringRef jsString = JSValueToStringCopy(ctx, value, exception);
|
|
||||||
if (!jsString) {
|
|
||||||
throw RJSException(ctx, *exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RJSStringForJSString(jsString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStringRef RJSStringForString(const std::string &str) {
|
JSStringRef RJSStringForString(const std::string &str) {
|
||||||
|
|
|
@ -19,9 +19,10 @@
|
||||||
#import "RealmJS.h"
|
#import "RealmJS.h"
|
||||||
#import "RJSRealm.hpp"
|
#import "RJSRealm.hpp"
|
||||||
#import "RJSObject.hpp"
|
#import "RJSObject.hpp"
|
||||||
|
#import "RJSUtil.hpp"
|
||||||
|
|
||||||
JSValueRef RJSTypeGet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
|
JSValueRef RJSTypeGet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
|
||||||
return RJSValueForString(ctx, "PropTypes" + RJSStringForJSString(propertyName));
|
return RJSValueForString(ctx, RJSTypeGet(RJSStringForJSString(propertyName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
JSClassRef RJSRealmTypeClass() {
|
JSClassRef RJSRealmTypeClass() {
|
||||||
|
|
Loading…
Reference in New Issue