mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-10 14:25:58 +00:00
be0c2a91ea
Specifically for objects with lists, since the mutation listener would fire on a list that no longer is attached. If during the mutation listener that error is thrown, then the listener will be removed and the error will not be propagated.
182 lines
4.4 KiB
JavaScript
182 lines
4.4 KiB
JavaScript
/* Copyright 2015 Realm Inc - All Rights Reserved
|
|
* Proprietary and Confidential
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const base64 = require('./base64');
|
|
const constants = require('./constants');
|
|
|
|
const DEVICE_HOST = 'localhost:8082';
|
|
|
|
const {keys, objectTypes, propTypes} = constants;
|
|
const typeConverters = {};
|
|
|
|
let XMLHttpRequest = global.originalXMLHttpRequest || global.XMLHttpRequest;
|
|
let sessionId;
|
|
|
|
// Check if XMLHttpRequest has been overridden, and get the native one if that's the case.
|
|
if (XMLHttpRequest.__proto__ != global.XMLHttpRequestEventTarget) {
|
|
let fakeXMLHttpRequest = XMLHttpRequest;
|
|
delete global.XMLHttpRequest;
|
|
XMLHttpRequest = global.XMLHttpRequest;
|
|
global.XMLHttpRequest = fakeXMLHttpRequest;
|
|
}
|
|
|
|
module.exports = {
|
|
registerTypeConverter,
|
|
|
|
createSession,
|
|
createRealm,
|
|
callMethod,
|
|
getProperty,
|
|
setProperty,
|
|
beginTransaction,
|
|
cancelTransaction,
|
|
commitTransaction,
|
|
|
|
clearTestState,
|
|
};
|
|
|
|
registerTypeConverter(propTypes.DATA, (_, {value}) => base64.decode(value));
|
|
registerTypeConverter(propTypes.DATE, (_, {value}) => new Date(value));
|
|
|
|
function registerTypeConverter(type, handler) {
|
|
typeConverters[type] = handler;
|
|
}
|
|
|
|
function createSession() {
|
|
sessionId = sendRequest('create_session');
|
|
return sessionId;
|
|
}
|
|
|
|
function createRealm(args) {
|
|
if (args) {
|
|
args = args.map((arg) => serialize(null, arg));
|
|
}
|
|
|
|
return sendRequest('create_realm', {arguments: args});
|
|
}
|
|
|
|
function callMethod(realmId, id, name, args) {
|
|
if (args) {
|
|
args = args.map((arg) => serialize(realmId, arg));
|
|
}
|
|
|
|
let result = sendRequest('call_method', {realmId, id, name, arguments: args});
|
|
return deserialize(realmId, result);
|
|
}
|
|
|
|
function getProperty(realmId, id, name) {
|
|
let result = sendRequest('get_property', {realmId, id, name});
|
|
return deserialize(realmId, result);
|
|
}
|
|
|
|
function setProperty(realmId, id, name, value) {
|
|
value = serialize(realmId, value);
|
|
sendRequest('set_property', {realmId, id, name, value});
|
|
}
|
|
|
|
function beginTransaction(realmId) {
|
|
sendRequest('begin_transaction', {realmId});
|
|
}
|
|
|
|
function cancelTransaction(realmId) {
|
|
sendRequest('cancel_transaction', {realmId});
|
|
}
|
|
|
|
function commitTransaction(realmId) {
|
|
sendRequest('commit_transaction', {realmId});
|
|
}
|
|
|
|
function clearTestState() {
|
|
sendRequest('clear_test_state');
|
|
}
|
|
|
|
function serialize(realmId, value) {
|
|
if (typeof value == 'function') {
|
|
return {type: objectTypes.FUNCTION};
|
|
}
|
|
|
|
if (typeof value === 'undefined') {
|
|
return {type: 'undefined'};
|
|
}
|
|
|
|
if (!value || typeof value != 'object') {
|
|
return {value: value};
|
|
}
|
|
|
|
let id = value[keys.id];
|
|
if (id) {
|
|
if (value[keys.realm] != realmId) {
|
|
throw new Error('Unable to serialize value from another Realm');
|
|
}
|
|
|
|
return {id};
|
|
}
|
|
|
|
if (value instanceof Date) {
|
|
return {type: propTypes.DATE, value: value.getTime()};
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
let array = value.map((item) => serialize(realmId, item));
|
|
return {value: array};
|
|
}
|
|
|
|
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
return {type: propTypes.DATA, value: base64.encode(value)};
|
|
}
|
|
|
|
let object = {};
|
|
for (let key in value) {
|
|
object[key] = serialize(realmId, value[key]);
|
|
}
|
|
return {value: object};
|
|
}
|
|
|
|
function deserialize(realmId, info) {
|
|
let type = info.type;
|
|
let handler = type && typeConverters[type];
|
|
if (handler) {
|
|
return handler(realmId, info);
|
|
}
|
|
|
|
let value = info.value;
|
|
if (value && Array.isArray(value)) {
|
|
return value.map((item) => deserialize(realmId, item));
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
function sendRequest(command, data) {
|
|
data = Object.assign({}, data, sessionId ? {sessionId} : null);
|
|
|
|
let body = JSON.stringify(data);
|
|
let request = new XMLHttpRequest();
|
|
let url = 'http://' + DEVICE_HOST + '/' + command;
|
|
|
|
request.open('POST', url, false);
|
|
request.send(body);
|
|
|
|
if (request.status != 200) {
|
|
throw new Error(request.responseText);
|
|
}
|
|
|
|
let response = JSON.parse(request.responseText);
|
|
|
|
if (!response || response.error) {
|
|
let error = response && response.error;
|
|
|
|
// Remove the type prefix from the error message (e.g. "Error: ").
|
|
if (error) {
|
|
error = error.replace(/^[a-z]+: /i, '');
|
|
}
|
|
|
|
throw new Error(error || `Invalid response for "${command}"`);
|
|
}
|
|
|
|
return response.result;
|
|
}
|