tson-rpc
Version:
Connect objects anywhere in pairs like quantum entanglement.
158 lines (157 loc) • 4.45 kB
JavaScript
// Copyright (c) 2022 System233
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
import { TSON } from "tson-serializer";
import { v4 as uuidv4 } from 'uuid';
import { BiMap } from "./bimap";
export class Handler {
apply(target, thisArg, argArray) {
return target.apply(thisArg, argArray);
}
construct(target, argArray, newTarget) {
return new target(...argArray);
}
defineProperty(target, p, attributes) {
Object.defineProperty(target, p, attributes);
return true;
}
deleteProperty(target, p) {
return delete target[p];
}
get(target, p, receiver) {
return target[p];
}
getOwnPropertyDescriptor(target, p) {
return Object.getOwnPropertyDescriptor(target, p);
}
getPrototypeOf(target) {
return Object.getPrototypeOf(target);
}
has(target, p) {
return p in target;
}
isExtensible(target) {
return Object.isExtensible(target);
}
ownKeys(target) {
return Object.keys(target);
}
preventExtensions(target) {
return Object.isFrozen(target);
}
set(target, p, value, receiver) {
target[p] = value;
return true;
}
setPrototypeOf(target, v) {
Object.setPrototypeOf(target, v);
return true;
}
}
;
export class WrappedObject {
handler;
data;
constructor(handler, data) {
this.handler = handler;
this.data = data;
const target = data.type == 'function' ? function () { } : data.type == 'array' ? [] : {};
return new Proxy(target, new Proxy({}, this));
}
call(method, args) {
return this.handler.call(this.data, method, args);
}
get(target, p, receiver) {
if (p in target) {
return target[p];
}
const handler = (_, ...args) => this.call(p, args);
target[p] = handler;
return handler;
}
has(target, p) {
return p in target;
}
}
export const typeOf = (value) => value != null && !(value instanceof ArrayBuffer) ? Array.isArray(value) ? 'array' : typeof value == 'object' ? 'object' : typeof value == 'function' ? 'function' : null : null;
export class WrappedHandler {
request;
map = new BiMap;
tson = new TSON;
handler = new Handler;
constructor(request) {
this.request = request;
this.tson.register('Wrapped', (data) => this.load(data), (obj) => this.dump(obj), (value) => !!typeOf(value));
}
id(value) {
if (this.map.hasValue(value)) {
return this.map.getByValue(value);
}
return this.new(value);
}
dump(obj) {
const type = typeOf(obj);
let id = this.map.getByValue(obj);
if (id == null) {
id = uuidv4();
this.map.set(id, obj);
}
return {
id,
type
};
}
load(data) {
if (this.map.has(data.id)) {
return this.map.get(data.id);
}
return this.remote(data);
}
new(value, id) {
id = id || uuidv4();
this.map.set(id, value);
return id;
}
join(value, id) {
const type = typeOf(value);
id = this.new(value, id);
return {
id,
type
};
}
local(id) {
const value = this.get(id);
if (value == null) {
return null;
}
const type = typeOf(value);
return {
type,
id
};
}
remote(data) {
const obj = new WrappedObject(this, data);
this.new(obj, data.id);
return obj;
}
call(target, method, params) {
const data = params.map(x => this.tson.forward(x));
const result = this.request({ target, method, data });
return this.tson.backward(result);
}
handle(request) {
const { target, method, data } = request;
const args = this.tson.backward(data);
const result = this.handler[method].call(this.handler, this.load(target), ...args);
return this.tson.forward(result);
}
delete(id) {
return this.map.delete(id);
}
get(id) {
return this.map.getByKey(id);
}
}