2016-02-18 11:59:34 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Copyright 2016 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.
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
2015-10-08 11:57:07 -06:00
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
#include <cassert>
|
2015-10-19 15:26:42 -07:00
|
|
|
#include <dlfcn.h>
|
2015-10-08 11:57:07 -06:00
|
|
|
#include <map>
|
|
|
|
#include <string>
|
2016-04-12 14:42:05 -07:00
|
|
|
|
|
|
|
#include "rpc.hpp"
|
|
|
|
|
|
|
|
#include "jsc_init.hpp"
|
2016-04-15 13:47:01 -07:00
|
|
|
#include "jsc_types.hpp"
|
2015-11-27 18:36:04 -08:00
|
|
|
#include "js_object.hpp"
|
|
|
|
#include "js_results.hpp"
|
|
|
|
#include "js_realm.hpp"
|
2015-10-08 11:57:07 -06:00
|
|
|
|
2015-11-16 03:33:11 -08:00
|
|
|
#include "base64.hpp"
|
2015-10-08 11:57:07 -06:00
|
|
|
#include "object_accessor.hpp"
|
|
|
|
#include "shared_realm.hpp"
|
|
|
|
#include "results.hpp"
|
2016-04-12 14:42:05 -07:00
|
|
|
|
|
|
|
using namespace realm;
|
|
|
|
using namespace realm::rpc;
|
|
|
|
|
|
|
|
using Accessor = NativeAccessor<JSValueRef, JSContextRef>;
|
2015-10-08 11:57:07 -06:00
|
|
|
|
2015-11-02 22:16:50 -08:00
|
|
|
static const char * const RealmObjectTypesData = "data";
|
|
|
|
static const char * const RealmObjectTypesDate = "date";
|
|
|
|
static const char * const RealmObjectTypesDictionary = "dict";
|
|
|
|
static const char * const RealmObjectTypesFunction = "function";
|
|
|
|
static const char * const RealmObjectTypesList = "list";
|
|
|
|
static const char * const RealmObjectTypesObject = "object";
|
|
|
|
static const char * const RealmObjectTypesResults = "results";
|
|
|
|
static const char * const RealmObjectTypesUndefined = "undefined";
|
2015-10-19 12:06:47 -07:00
|
|
|
|
2015-10-22 10:44:10 -07:00
|
|
|
RPCServer::RPCServer() {
|
2015-10-22 17:59:05 -07:00
|
|
|
m_context = JSGlobalContextCreate(NULL);
|
2015-10-08 11:57:07 -06:00
|
|
|
|
2015-10-22 10:44:10 -07:00
|
|
|
// 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) {
|
2015-10-22 17:59:05 -07:00
|
|
|
setIncludesNativeCallStack(m_context, false);
|
2015-10-15 18:50:20 -07:00
|
|
|
}
|
|
|
|
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/create_session"] = [this](const json dict) {
|
2015-10-26 01:14:33 -07:00
|
|
|
RJSInitializeInContext(m_context);
|
2015-10-15 18:50:20 -07:00
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
jsc::String realm_string = "Realm";
|
|
|
|
JSObjectRef realm_constructor = jsc::Object::validated_get_constructor(m_context, JSContextGetGlobalObject(m_context), realm_string);
|
2015-10-15 03:00:13 -07:00
|
|
|
|
2015-10-22 17:59:05 -07:00
|
|
|
m_session_id = store_object(realm_constructor);
|
|
|
|
return (json){{"result", m_session_id}};
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/create_realm"] = [this](const json dict) {
|
|
|
|
JSObjectRef realm_constructor = m_session_id ? m_objects[m_session_id] : NULL;
|
2015-10-22 10:44:10 -07:00
|
|
|
if (!realm_constructor) {
|
|
|
|
throw std::runtime_error("Realm constructor not found!");
|
2015-10-19 15:26:42 -07:00
|
|
|
}
|
|
|
|
|
2015-10-22 10:44:10 -07:00
|
|
|
json::array_t args = dict["arguments"];
|
|
|
|
size_t arg_count = args.size();
|
|
|
|
JSValueRef arg_values[arg_count];
|
2015-10-15 18:50:20 -07:00
|
|
|
|
2015-10-22 10:44:10 -07:00
|
|
|
for (size_t i = 0; i < arg_count; i++) {
|
|
|
|
arg_values[i] = deserialize_json_value(args[i]);
|
|
|
|
}
|
2015-10-20 15:10:22 -07:00
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
JSObjectRef realm_object = jsc::Function::construct(m_context, realm_constructor, arg_count, arg_values);
|
2015-10-22 17:59:05 -07:00
|
|
|
RPCObjectID realm_id = store_object(realm_object);
|
|
|
|
return (json){{"result", realm_id}};
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/begin_transaction"] = [this](const json dict) {
|
|
|
|
RPCObjectID realm_id = dict["realmId"].get<RPCObjectID>();
|
2016-04-15 13:47:01 -07:00
|
|
|
SharedRealm realm = *jsc::Object::get_internal<js::RealmClass<jsc::Types>>(m_objects[realm_id]);
|
2016-04-12 14:42:05 -07:00
|
|
|
|
|
|
|
realm->begin_transaction();
|
2015-10-22 16:49:32 -07:00
|
|
|
return json::object();
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/cancel_transaction"] = [this](const json dict) {
|
|
|
|
RPCObjectID realm_id = dict["realmId"].get<RPCObjectID>();
|
2016-04-15 13:47:01 -07:00
|
|
|
SharedRealm realm = *jsc::Object::get_internal<js::RealmClass<jsc::Types>>(m_objects[realm_id]);
|
2016-04-12 14:42:05 -07:00
|
|
|
|
|
|
|
realm->cancel_transaction();
|
2015-10-22 16:49:32 -07:00
|
|
|
return json::object();
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/commit_transaction"] = [this](const json dict) {
|
|
|
|
RPCObjectID realm_id = dict["realmId"].get<RPCObjectID>();
|
2016-04-15 13:47:01 -07:00
|
|
|
SharedRealm realm = *jsc::Object::get_internal<js::RealmClass<jsc::Types>>(m_objects[realm_id]);
|
2016-04-12 14:42:05 -07:00
|
|
|
|
|
|
|
realm->commit_transaction();
|
2015-10-22 16:49:32 -07:00
|
|
|
return json::object();
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/call_method"] = [this](const json dict) {
|
|
|
|
JSObjectRef object = m_objects[dict["id"].get<RPCObjectID>()];
|
2016-04-12 14:42:05 -07:00
|
|
|
std::string method_string = dict["name"].get<std::string>();
|
|
|
|
JSObjectRef function = jsc::Object::validated_get_function(m_context, object, method_string);
|
2015-10-22 10:44:10 -07:00
|
|
|
|
|
|
|
json args = dict["arguments"];
|
2016-04-12 14:42:05 -07:00
|
|
|
size_t arg_count = args.size();
|
|
|
|
JSValueRef arg_values[arg_count];
|
|
|
|
for (size_t i = 0; i < arg_count; i++) {
|
2015-10-22 17:59:05 -07:00
|
|
|
arg_values[i] = deserialize_json_value(args[i]);
|
2015-10-22 10:44:10 -07:00
|
|
|
}
|
2015-10-15 03:00:13 -07:00
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
JSValueRef result = jsc::Function::call(m_context, function, object, arg_count, arg_values);
|
2015-10-22 16:49:32 -07:00
|
|
|
return (json){{"result", serialize_json_value(result)}};
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/get_property"] = [this](const json dict) {
|
2015-10-22 10:44:10 -07:00
|
|
|
RPCObjectID oid = dict["id"].get<RPCObjectID>();
|
|
|
|
json name = dict["name"];
|
2016-04-12 14:42:05 -07:00
|
|
|
JSValueRef value;
|
2015-10-22 10:44:10 -07:00
|
|
|
|
|
|
|
if (name.is_number()) {
|
2016-04-12 14:42:05 -07:00
|
|
|
value = jsc::Object::get_property(m_context, m_objects[oid], name.get<unsigned int>());
|
2015-10-22 10:44:10 -07:00
|
|
|
}
|
|
|
|
else {
|
2016-04-12 14:42:05 -07:00
|
|
|
value = jsc::Object::get_property(m_context, m_objects[oid], name.get<std::string>());
|
2015-10-22 10:44:10 -07:00
|
|
|
}
|
2015-10-15 03:00:13 -07:00
|
|
|
|
2015-10-22 16:49:32 -07:00
|
|
|
return (json){{"result", serialize_json_value(value)}};
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/set_property"] = [this](const json dict) {
|
2015-10-22 10:44:10 -07:00
|
|
|
RPCObjectID oid = dict["id"].get<RPCObjectID>();
|
|
|
|
json name = dict["name"];
|
|
|
|
JSValueRef value = deserialize_json_value(dict["value"]);
|
|
|
|
|
|
|
|
if (name.is_number()) {
|
2016-04-12 14:42:05 -07:00
|
|
|
jsc::Object::set_property(m_context, m_objects[oid], name.get<unsigned int>(), value);
|
2015-10-22 10:44:10 -07:00
|
|
|
}
|
|
|
|
else {
|
2016-04-12 14:42:05 -07:00
|
|
|
jsc::Object::set_property(m_context, m_objects[oid], name.get<std::string>(), value);
|
2015-10-22 10:44:10 -07:00
|
|
|
}
|
2015-10-15 03:00:13 -07:00
|
|
|
|
2015-10-22 16:49:32 -07:00
|
|
|
return json::object();
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/dispose_object"] = [this](const json dict) {
|
2015-10-22 10:44:10 -07:00
|
|
|
RPCObjectID oid = dict["id"].get<RPCObjectID>();
|
2015-10-22 17:59:05 -07:00
|
|
|
JSValueUnprotect(m_context, m_objects[oid]);
|
|
|
|
m_objects.erase(oid);
|
2015-10-22 16:49:32 -07:00
|
|
|
return json::object();
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
2015-10-22 17:59:05 -07:00
|
|
|
m_requests["/clear_test_state"] = [this](const json dict) {
|
|
|
|
for (auto object : m_objects) {
|
2015-10-22 10:44:10 -07:00
|
|
|
// The session ID points to the Realm constructor object, which should remain.
|
2015-10-22 17:59:05 -07:00
|
|
|
if (object.first == m_session_id) {
|
2015-10-22 10:44:10 -07:00
|
|
|
continue;
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-08 15:30:29 -07:00
|
|
|
|
2015-10-22 17:59:05 -07:00
|
|
|
JSValueUnprotect(m_context, object.second);
|
|
|
|
m_objects.erase(object.first);
|
2015-10-22 10:44:10 -07:00
|
|
|
}
|
2015-10-22 17:59:05 -07:00
|
|
|
JSGarbageCollect(m_context);
|
2016-04-12 14:42:05 -07:00
|
|
|
js::clear_test_state();
|
2015-10-22 16:49:32 -07:00
|
|
|
return json::object();
|
2015-10-22 10:44:10 -07:00
|
|
|
};
|
|
|
|
}
|
2015-10-15 17:07:10 -07:00
|
|
|
|
2015-10-22 10:44:10 -07:00
|
|
|
RPCServer::~RPCServer() {
|
2015-10-22 17:59:05 -07:00
|
|
|
for (auto item : m_objects) {
|
|
|
|
JSValueUnprotect(m_context, item.second);
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-22 10:44:10 -07:00
|
|
|
|
2015-10-22 17:59:05 -07:00
|
|
|
JSGlobalContextRelease(m_context);
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
|
|
|
|
2015-10-22 16:49:32 -07:00
|
|
|
json RPCServer::perform_request(std::string name, json &args) {
|
2015-10-22 18:06:11 -07:00
|
|
|
try {
|
|
|
|
RPCRequest action = m_requests[name];
|
|
|
|
assert(action);
|
|
|
|
|
|
|
|
if (name == "/create_session" || m_session_id == args["sessionId"].get<RPCObjectID>()) {
|
|
|
|
return action(args);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return {{"error", "Invalid session ID"}};
|
2015-10-08 12:23:42 -06:00
|
|
|
}
|
2015-10-22 18:06:11 -07:00
|
|
|
} catch (std::exception &exception) {
|
2016-04-12 14:42:05 -07:00
|
|
|
return {{"error", exception.what()}};
|
2015-10-22 18:06:11 -07:00
|
|
|
}
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
|
|
|
|
2015-10-22 10:44:10 -07:00
|
|
|
RPCObjectID RPCServer::store_object(JSObjectRef object) {
|
2015-10-08 11:57:07 -06:00
|
|
|
static RPCObjectID s_next_id = 1;
|
|
|
|
RPCObjectID next_id = s_next_id++;
|
2015-10-22 17:59:05 -07:00
|
|
|
JSValueProtect(m_context, object);
|
|
|
|
m_objects[next_id] = object;
|
2015-10-08 11:57:07 -06:00
|
|
|
return next_id;
|
|
|
|
}
|
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
json RPCServer::serialize_json_value(JSValueRef js_value) {
|
|
|
|
switch (JSValueGetType(m_context, js_value)) {
|
2015-10-08 11:57:07 -06:00
|
|
|
case kJSTypeUndefined:
|
2015-10-22 16:49:32 -07:00
|
|
|
return json::object();
|
2015-10-08 11:57:07 -06:00
|
|
|
case kJSTypeNull:
|
2015-10-22 16:49:32 -07:00
|
|
|
return {{"value", json(nullptr)}};
|
2015-10-08 11:57:07 -06:00
|
|
|
case kJSTypeBoolean:
|
2016-04-12 14:42:05 -07:00
|
|
|
return {{"value", jsc::Value::to_boolean(m_context, js_value)}};
|
2015-10-08 11:57:07 -06:00
|
|
|
case kJSTypeNumber:
|
2016-04-12 14:42:05 -07:00
|
|
|
return {{"value", jsc::Value::to_number(m_context, js_value)}};
|
2015-10-08 11:57:07 -06:00
|
|
|
case kJSTypeString:
|
2016-04-12 14:42:05 -07:00
|
|
|
return {{"value", jsc::Value::to_string(m_context, js_value)}};
|
2015-10-08 11:57:07 -06:00
|
|
|
case kJSTypeObject:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
JSObjectRef js_object = jsc::Value::validated_to_object(m_context, js_value);
|
2015-10-08 11:57:07 -06:00
|
|
|
|
2016-04-15 13:47:01 -07:00
|
|
|
if (jsc::Object::is_instance<js::RealmObjectClass<jsc::Types>>(m_context, js_object)) {
|
|
|
|
auto object = jsc::Object::get_internal<js::RealmObjectClass<jsc::Types>>(js_object);
|
2015-10-22 10:44:10 -07:00
|
|
|
return {
|
2015-11-02 22:16:50 -08:00
|
|
|
{"type", RealmObjectTypesObject},
|
2015-10-22 17:59:05 -07:00
|
|
|
{"id", store_object(js_object)},
|
2016-01-04 18:13:09 -08:00
|
|
|
{"schema", serialize_object_schema(object->get_object_schema())}
|
2015-10-08 11:57:07 -06:00
|
|
|
};
|
|
|
|
}
|
2016-04-15 13:47:01 -07:00
|
|
|
else if (jsc::Object::is_instance<js::ListClass<jsc::Types>>(m_context, js_object)) {
|
|
|
|
auto list = jsc::Object::get_internal<js::ListClass<jsc::Types>>(js_object);
|
2015-10-22 10:44:10 -07:00
|
|
|
return {
|
2015-11-02 22:16:50 -08:00
|
|
|
{"type", RealmObjectTypesList},
|
2015-10-22 17:59:05 -07:00
|
|
|
{"id", store_object(js_object)},
|
2015-11-18 14:36:46 -08:00
|
|
|
{"size", list->size()},
|
2016-01-04 18:13:09 -08:00
|
|
|
{"schema", serialize_object_schema(list->get_object_schema())}
|
2015-10-08 11:57:07 -06:00
|
|
|
};
|
|
|
|
}
|
2016-04-15 13:47:01 -07:00
|
|
|
else if (jsc::Object::is_instance<js::ResultsClass<jsc::Types>>(m_context, js_object)) {
|
|
|
|
auto results = jsc::Object::get_internal<js::ResultsClass<jsc::Types>>(js_object);
|
2015-10-22 10:44:10 -07:00
|
|
|
return {
|
2015-10-22 16:49:32 -07:00
|
|
|
{"type", RealmObjectTypesResults},
|
2015-10-22 17:59:05 -07:00
|
|
|
{"id", store_object(js_object)},
|
2015-10-22 16:49:32 -07:00
|
|
|
{"size", results->size()},
|
2016-01-04 18:13:09 -08:00
|
|
|
{"schema", serialize_object_schema(results->get_object_schema())}
|
2015-10-08 11:57:07 -06:00
|
|
|
};
|
|
|
|
}
|
2016-04-12 14:42:05 -07:00
|
|
|
else if (jsc::Value::is_array(m_context, js_object)) {
|
|
|
|
uint32_t length = jsc::Object::validated_get_length(m_context, js_object);
|
2015-10-22 10:44:10 -07:00
|
|
|
std::vector<json> array;
|
2016-04-12 14:42:05 -07:00
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
|
|
array.push_back(serialize_json_value(jsc::Object::get_property(m_context, js_object, i)));
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-22 16:49:32 -07:00
|
|
|
return {{"value", array}};
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2016-04-12 14:42:05 -07:00
|
|
|
else if (jsc::Value::is_array_buffer(m_context, js_object)) {
|
|
|
|
std::string data = Accessor::to_binary(m_context, js_value);
|
2015-11-16 03:33:11 -08:00
|
|
|
return {
|
2015-11-02 22:16:50 -08:00
|
|
|
{"type", RealmObjectTypesData},
|
2015-11-16 03:33:11 -08:00
|
|
|
{"value", base64_encode((unsigned char *)data.data(), data.size())},
|
|
|
|
};
|
|
|
|
}
|
2016-04-12 14:42:05 -07:00
|
|
|
else if (jsc::Value::is_date(m_context, js_object)) {
|
2015-10-22 10:44:10 -07:00
|
|
|
return {
|
2015-11-02 22:16:50 -08:00
|
|
|
{"type", RealmObjectTypesDate},
|
2016-04-12 14:42:05 -07:00
|
|
|
{"value", jsc::Value::to_number(m_context, js_object)},
|
2015-10-19 16:46:56 -07:00
|
|
|
};
|
|
|
|
}
|
2015-11-02 16:36:24 -08:00
|
|
|
else {
|
2016-01-13 14:53:39 -08:00
|
|
|
// Serialize this JS object as a plain object since it doesn't match any known types above.
|
2016-04-12 14:42:05 -07:00
|
|
|
std::vector<jsc::String> js_keys = jsc::Object::get_property_names(m_context, js_object);
|
2015-11-02 16:36:24 -08:00
|
|
|
std::vector<std::string> keys;
|
|
|
|
std::vector<json> values;
|
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
for (auto &js_key : js_keys) {
|
|
|
|
JSValueRef js_value = jsc::Object::get_property(m_context, js_object, js_key);
|
2015-11-02 16:36:24 -08:00
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
keys.push_back(js_key);
|
|
|
|
values.push_back(js_value);
|
2015-11-02 16:36:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
{"type", RealmObjectTypesDictionary},
|
|
|
|
{"keys", keys},
|
|
|
|
{"values", values},
|
|
|
|
};
|
|
|
|
}
|
2015-10-22 10:44:10 -07:00
|
|
|
assert(0);
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
|
|
|
|
2015-10-26 15:27:43 -07:00
|
|
|
json RPCServer::serialize_object_schema(const realm::ObjectSchema &object_schema) {
|
2015-11-02 21:54:05 -08:00
|
|
|
std::vector<std::string> properties;
|
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
for (auto &prop : object_schema.properties) {
|
2015-11-02 21:54:05 -08:00
|
|
|
properties.push_back(prop.name);
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
|
|
|
|
2015-10-22 10:44:10 -07:00
|
|
|
return {
|
2015-10-22 17:59:05 -07:00
|
|
|
{"name", object_schema.name},
|
2015-10-22 16:49:32 -07:00
|
|
|
{"properties", properties},
|
2015-10-08 11:57:07 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
JSValueRef RPCServer::deserialize_json_value(const json dict) {
|
2015-10-22 16:49:32 -07:00
|
|
|
json oid = dict["id"];
|
|
|
|
if (oid.is_number()) {
|
2015-10-22 17:59:05 -07:00
|
|
|
return m_objects[oid.get<RPCObjectID>()];
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
|
|
|
|
2015-10-22 15:31:26 -07:00
|
|
|
json value = dict["value"];
|
2015-10-22 16:49:32 -07:00
|
|
|
json type = dict["type"];
|
2016-04-12 14:42:05 -07:00
|
|
|
|
2015-10-22 16:49:32 -07:00
|
|
|
if (type.is_string()) {
|
|
|
|
std::string type_string = type.get<std::string>();
|
2016-04-12 14:42:05 -07:00
|
|
|
|
2015-10-22 16:49:32 -07:00
|
|
|
if (type_string == RealmObjectTypesFunction) {
|
|
|
|
// FIXME: Make this actually call the function by its id once we need it to.
|
2016-04-12 14:42:05 -07:00
|
|
|
return JSObjectMakeFunction(m_context, NULL, 0, NULL, jsc::String(""), NULL, 1, NULL);
|
2015-10-22 16:49:32 -07:00
|
|
|
}
|
2015-11-02 16:36:24 -08:00
|
|
|
else if (type_string == RealmObjectTypesDictionary) {
|
2016-04-12 14:42:05 -07:00
|
|
|
JSObjectRef js_object = jsc::Object::create_empty(m_context);
|
2015-11-02 16:36:24 -08:00
|
|
|
json keys = dict["keys"];
|
|
|
|
json values = dict["values"];
|
|
|
|
size_t count = keys.size();
|
|
|
|
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
2016-04-12 14:42:05 -07:00
|
|
|
std::string js_key = keys.at(i);
|
2015-11-02 16:36:24 -08:00
|
|
|
JSValueRef js_value = deserialize_json_value(values.at(i));
|
2016-04-12 14:42:05 -07:00
|
|
|
jsc::Object::set_property(m_context, js_object, js_key, js_value);
|
2015-11-02 16:36:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return js_object;
|
|
|
|
}
|
2015-11-02 22:16:50 -08:00
|
|
|
else if (type_string == RealmObjectTypesData) {
|
2015-11-16 03:33:11 -08:00
|
|
|
std::string bytes;
|
|
|
|
if (!base64_decode(value.get<std::string>(), &bytes)) {
|
|
|
|
throw std::runtime_error("Failed to decode base64 encoded data");
|
|
|
|
}
|
2016-04-12 14:42:05 -07:00
|
|
|
return Accessor::from_binary(m_context, realm::BinaryData(bytes));
|
2015-11-16 03:33:11 -08:00
|
|
|
}
|
2015-11-02 22:16:50 -08:00
|
|
|
else if (type_string == RealmObjectTypesDate) {
|
2016-04-12 14:42:05 -07:00
|
|
|
return jsc::Object::create_date(m_context, value.get<double>());
|
2015-10-19 16:46:56 -07:00
|
|
|
}
|
2015-11-02 22:16:50 -08:00
|
|
|
else if (type_string == RealmObjectTypesUndefined) {
|
2016-04-12 14:42:05 -07:00
|
|
|
return jsc::Value::from_undefined(m_context);
|
2015-10-27 12:13:19 -07:00
|
|
|
}
|
|
|
|
assert(0);
|
2015-10-19 16:46:56 -07:00
|
|
|
}
|
2015-10-14 18:00:21 -07:00
|
|
|
|
2015-10-22 16:49:32 -07:00
|
|
|
if (value.is_null()) {
|
2016-04-12 14:42:05 -07:00
|
|
|
return jsc::Value::from_null(m_context);
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-22 15:31:26 -07:00
|
|
|
else if (value.is_boolean()) {
|
2016-04-12 14:42:05 -07:00
|
|
|
return jsc::Value::from_boolean(m_context, value.get<bool>());
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-22 15:31:26 -07:00
|
|
|
else if (value.is_number()) {
|
2016-04-12 14:42:05 -07:00
|
|
|
return jsc::Value::from_number(m_context, value.get<double>());
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-22 15:31:26 -07:00
|
|
|
else if (value.is_string()) {
|
2016-04-12 14:42:05 -07:00
|
|
|
return jsc::Value::from_string(m_context, value.get<std::string>());
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-22 15:31:26 -07:00
|
|
|
else if (value.is_array()) {
|
|
|
|
size_t count = value.size();
|
2015-10-22 17:59:05 -07:00
|
|
|
JSValueRef js_values[count];
|
2015-10-08 11:57:07 -06:00
|
|
|
|
2015-10-22 15:31:26 -07:00
|
|
|
for (size_t i = 0; i < count; i++) {
|
2015-10-22 17:59:05 -07:00
|
|
|
js_values[i] = deserialize_json_value(value.at(i));
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
|
|
|
|
2016-04-12 14:42:05 -07:00
|
|
|
return jsc::Object::create_array(m_context, (uint32_t)count, js_values);
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|
2015-10-27 12:13:19 -07:00
|
|
|
assert(0);
|
2015-10-08 11:57:07 -06:00
|
|
|
}
|