Make RPC server return Results properly

Still doesn't handle returning property values.
This commit is contained in:
Scott Kyle 2015-10-07 18:42:08 -07:00
parent 141ce2cb6d
commit e136da5117
4 changed files with 106 additions and 23 deletions

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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() {