Removed connection worker.
This commit is contained in:
parent
f1e787c807
commit
8ae77e1bf3
17 changed files with 22 additions and 618 deletions
3
build.js
3
build.js
|
@ -31,8 +31,7 @@ const exec = require('util').promisify(require('child_process').exec);
|
|||
|
||||
const tasks = {
|
||||
js: [
|
||||
{ source: 'proto.js', target: '/assets', name: 'proto.{hash}.js', vars: { build: 'MAMI_PROTO_JS', html: ':source' } },
|
||||
{ source: 'mami.js', target: '/assets', name: 'mami.{hash}.js', vars: { build: 'MAMI_MAIN_JS', html: ':source' } },
|
||||
{ source: 'mami.js', target: '/assets', name: 'mami.{hash}.js', vars: { build: 'MAMI_JS', html: ':source' } },
|
||||
{ source: 'init.js', target: '/assets', name: 'init.{hash}.js', es: 'es5', vars: { html: ':source' } },
|
||||
],
|
||||
css: [
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
if(isCompatible) {
|
||||
(function(script) {
|
||||
script.src = MAMI_MAIN_JS;
|
||||
script.src = MAMI_JS;
|
||||
script.type = 'text/javascript';
|
||||
script.charset = 'utf-8';
|
||||
document.body.appendChild(script);
|
||||
|
|
|
@ -21,7 +21,6 @@ const MamiContext = function(globalEventTarget, eventTarget) {
|
|||
let textTriggers;
|
||||
let eeprom;
|
||||
let conMan;
|
||||
let protoWorker;
|
||||
|
||||
return {
|
||||
get globalEvents() { return globalEventTarget; },
|
||||
|
@ -88,12 +87,5 @@ const MamiContext = function(globalEventTarget, eventTarget) {
|
|||
throw 'conMan must be a non-null object';
|
||||
conMan = value;
|
||||
},
|
||||
|
||||
get protoWorker() { return protoWorker; },
|
||||
set protoWorker(value) {
|
||||
if(typeof value !== 'object' || value === null)
|
||||
throw 'protoWorker must be a non-null object';
|
||||
protoWorker = value;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@ window.Umi = { UI: {} };
|
|||
#include users.js
|
||||
#include utility.js
|
||||
#include weeb.js
|
||||
#include worker.js
|
||||
#include audio/autoplay.js
|
||||
#include chatform/form.jsx
|
||||
#include colpick/picker.jsx
|
||||
|
@ -905,10 +904,7 @@ const MamiInit = async args => {
|
|||
}
|
||||
};
|
||||
|
||||
const protoWorker = new MamiWorker(MAMI_PROTO_JS, ctx.events.scopeTo('worker'));
|
||||
ctx.protoWorker = protoWorker;
|
||||
|
||||
const sockChat = new MamiSockChat(protoWorker);
|
||||
const sockChat = new MamiSockChat(ctx.events.scopeTo('sockchat'));
|
||||
const conMan = new MamiConnectionManager(sockChat, settings, futami.get('servers'), ctx.events.scopeTo('conn'));
|
||||
ctx.conMan = conMan;
|
||||
|
||||
|
@ -982,40 +978,9 @@ const MamiInit = async args => {
|
|||
conMan.watch('attempt', conManAttempt);
|
||||
conMan.watch('fail', conManFail);
|
||||
|
||||
let workerStarting = false;
|
||||
const initWorker = async () => {
|
||||
if(workerStarting)
|
||||
return;
|
||||
workerStarting = true;
|
||||
|
||||
if(FUTAMI_DEBUG)
|
||||
console.info('[proto] initialising worker...');
|
||||
|
||||
try {
|
||||
await protoWorker.connect();
|
||||
await sockChat.create();
|
||||
conMan.client = sockChat;
|
||||
await conMan.start();
|
||||
} finally {
|
||||
workerStarting = false;
|
||||
}
|
||||
};
|
||||
|
||||
protoWorker.watch(':timeout', ev => {
|
||||
console.warn('worker timeout', ev.detail);
|
||||
initWorker();
|
||||
});
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if(document.visibilityState === 'visible') {
|
||||
protoWorker.ping().catch(ex => {
|
||||
console.warn('worker died', ex);
|
||||
initWorker();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await initWorker();
|
||||
|
||||
return ctx;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include sockchat/utils.js
|
||||
#include proto/sockchat/utils.js
|
||||
|
||||
const SockChatS2CPong = ctx => {
|
||||
const lastPong = Date.now();
|
|
@ -1,9 +1,9 @@
|
|||
#include timedp.js
|
||||
#include sockchat/authed.js
|
||||
#include sockchat/ctx.js
|
||||
#include sockchat/unauthed.js
|
||||
#include proto/sockchat/authed.js
|
||||
#include proto/sockchat/ctx.js
|
||||
#include proto/sockchat/unauthed.js
|
||||
|
||||
const SockChatProtocol = function(dispatch, options) {
|
||||
const SockChatClient = function(dispatch, options) {
|
||||
if(typeof dispatch !== 'function')
|
||||
throw 'dispatch must be a function';
|
||||
if(typeof options !== 'object' || options === null)
|
|
@ -1,4 +1,4 @@
|
|||
#include sockchat/keepalive.js
|
||||
#include proto/sockchat/keepalive.js
|
||||
|
||||
const SockChatContext = function(dispatch, sendPing, pingDelay) {
|
||||
if(typeof dispatch !== 'function')
|
|
@ -1,4 +1,4 @@
|
|||
#include sockchat/utils.js
|
||||
#include proto/sockchat/utils.js
|
||||
|
||||
const SockChatS2CAuthSuccess = (ctx, userId, userName, userColour, userPerms, chanName, maxLength) => {
|
||||
ctx.userId = userId;
|
|
@ -25,7 +25,7 @@ const MamiSettings = function(storageOrPrefix, eventTarget) {
|
|||
});
|
||||
const dispatchUpdate = (name, value, silent, local) => eventTarget.dispatch(createUpdateEvent(name, value, false, silent, local));
|
||||
|
||||
const broadcast = new BroadcastChannel(`${MAMI_MAIN_JS}:settings:${storage.name}`);
|
||||
const broadcast = new BroadcastChannel(`${MAMI_JS}:settings:${storage.name}`);
|
||||
const broadcastUpdate = (name, value, silent) => {
|
||||
setTimeout(() => broadcast.postMessage({ act: 'update', name: name, value: value, silent: !!silent }), 0);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include compat.js
|
||||
#include mszauth.js
|
||||
#include proto/sockchat/client.js
|
||||
|
||||
const MamiSockChat = function(protoWorker) {
|
||||
const events = protoWorker.eventTarget('sockchat');
|
||||
const MamiSockChat = function(eventTarget) {
|
||||
let restarting = false;
|
||||
let client;
|
||||
let dumpPackets = false;
|
||||
|
@ -10,8 +10,8 @@ const MamiSockChat = function(protoWorker) {
|
|||
return {
|
||||
get client() { return client; },
|
||||
|
||||
watch: events.watch,
|
||||
unwatch: events.unwatch,
|
||||
watch: eventTarget.watch,
|
||||
unwatch: eventTarget.unwatch,
|
||||
|
||||
create: async () => {
|
||||
if(client !== undefined && typeof client.close === 'function')
|
||||
|
@ -19,8 +19,8 @@ const MamiSockChat = function(protoWorker) {
|
|||
client.close();
|
||||
|
||||
restarting = false;
|
||||
client = await protoWorker.root.create('sockchat', { ping: futami.get('ping') });
|
||||
await client.setDumpPackets(dumpPackets);
|
||||
client = new SockChatClient(eventTarget.dispatch, { ping: futami.get('ping') });
|
||||
client.setDumpPackets(dumpPackets);
|
||||
|
||||
MamiCompat('Umi.Server', { get: () => client, configurable: true });
|
||||
MamiCompat('Umi.Server.SendMessage', { value: text => client.sendMessage(text), configurable: true });
|
||||
|
@ -38,11 +38,11 @@ const MamiSockChat = function(protoWorker) {
|
|||
const authInfo = MamiMisuzuAuth.getInfo();
|
||||
await client.sendAuth(authInfo.method, authInfo.token);
|
||||
},
|
||||
setDumpPackets: async state => {
|
||||
setDumpPackets: state => {
|
||||
dumpPackets = !!state;
|
||||
|
||||
if(client !== undefined && typeof client.setDumpPackets === 'function')
|
||||
await client.setDumpPackets(dumpPackets);
|
||||
client.setDumpPackets(dumpPackets);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,281 +0,0 @@
|
|||
#include uniqstr.js
|
||||
|
||||
const MamiWorker = function(url, eventTarget) {
|
||||
const timeOutMs = 30000;
|
||||
|
||||
let worker, workerId;
|
||||
let connectTimeout;
|
||||
let pingId;
|
||||
let hasTimedout;
|
||||
|
||||
const root = {};
|
||||
const objects = new Map;
|
||||
const pending = new Map;
|
||||
const clearObjects = () => {
|
||||
for(const [name, object] of objects)
|
||||
for(const method in object)
|
||||
delete object[method];
|
||||
objects.clear();
|
||||
objects.set('', root);
|
||||
};
|
||||
|
||||
clearObjects();
|
||||
|
||||
const broadcastTimeoutZone = body => {
|
||||
const localWorkerId = workerId;
|
||||
|
||||
body(detail => {
|
||||
if(localWorkerId !== workerId || hasTimedout)
|
||||
return;
|
||||
hasTimedout = true;
|
||||
|
||||
eventTarget.dispatch(':timeout', detail);
|
||||
});
|
||||
};
|
||||
|
||||
const handlers = {};
|
||||
|
||||
const handleMessage = ev => {
|
||||
if(typeof ev.data === 'object' && ev.data !== null && typeof ev.data.type === 'string') {
|
||||
if(ev.data.type in handlers)
|
||||
handlers[ev.data.type](ev.data.detail);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const callObjectMethod = (objName, metName, ...args) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if(typeof objName !== 'string')
|
||||
throw 'objName must be a string';
|
||||
if(typeof metName !== 'string')
|
||||
throw 'metName must be a string';
|
||||
|
||||
const id = MamiUniqueStr(8);
|
||||
const info = { id: id, resolve: resolve, reject: reject };
|
||||
pending.set(id, info);
|
||||
|
||||
worker.postMessage({ type: 'metcall', detail: { id: id, object: objName, method: metName, args: args } });
|
||||
|
||||
broadcastTimeoutZone(timeout => {
|
||||
info.timeOut = setTimeout(() => {
|
||||
const reject = info.reject;
|
||||
info.resolve = info.reject = undefined;
|
||||
|
||||
info.timeOut = undefined;
|
||||
pending.delete(id);
|
||||
|
||||
timeout({ at: 'call', obj: objName, met: metName });
|
||||
|
||||
if(typeof reject === 'function')
|
||||
reject('timeout');
|
||||
}, timeOutMs);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const defineObjectMethod = (object, objName, method) => object[method] = (...args) => callObjectMethod(objName, method, ...args);
|
||||
|
||||
handlers['objdef'] = info => {
|
||||
let object = objects.get(info.object);
|
||||
if(object === undefined)
|
||||
objects.set(info.object, object = {});
|
||||
|
||||
if(typeof info.eventPrefix === 'string') {
|
||||
const scopedTarget = eventTarget.scopeTo(info.eventPrefix);
|
||||
object.watch = scopedTarget.watch;
|
||||
object.unwatch = scopedTarget.unwatch;
|
||||
}
|
||||
|
||||
for(const method of info.methods)
|
||||
defineObjectMethod(object, info.object, method);
|
||||
};
|
||||
|
||||
handlers['objdel'] = info => {
|
||||
// this should never happen
|
||||
if(info.object === '') {
|
||||
console.error('Worker attempted to delete root object!!!!!');
|
||||
return;
|
||||
}
|
||||
|
||||
const object = objects.get(info.object);
|
||||
if(object === undefined)
|
||||
return;
|
||||
|
||||
objects.delete(info.object);
|
||||
|
||||
const methods = Object.keys(object);
|
||||
for(const method of methods)
|
||||
delete object[method];
|
||||
};
|
||||
|
||||
handlers['metdef'] = info => {
|
||||
const object = objects.get(info.object);
|
||||
if(object === undefined) {
|
||||
console.error('Worker attempted to define method on undefined object.');
|
||||
return;
|
||||
}
|
||||
|
||||
defineObjectMethod(object, info.object, info.method);
|
||||
};
|
||||
|
||||
handlers['metdel'] = info => {
|
||||
const object = objects.get(info.object);
|
||||
if(object === undefined) {
|
||||
console.error('Worker attempted to delete method on undefined object.');
|
||||
return;
|
||||
}
|
||||
|
||||
delete object[info.method];
|
||||
};
|
||||
|
||||
handlers['funcret'] = resp => {
|
||||
const info = pending.get(resp.id);
|
||||
if(info === undefined)
|
||||
return;
|
||||
|
||||
pending.delete(info.id);
|
||||
|
||||
if(info.timeOut !== undefined)
|
||||
clearTimeout(info.timeOut);
|
||||
|
||||
const handler = resp.success ? info.resolve : info.reject;
|
||||
info.resolve = info.reject = undefined;
|
||||
|
||||
if(handler !== undefined) {
|
||||
let result = resp.result;
|
||||
if(resp.object)
|
||||
result = objects.get(result);
|
||||
|
||||
handler(result);
|
||||
}
|
||||
};
|
||||
|
||||
handlers['evtdisp'] = resp => {
|
||||
eventTarget.dispatch(resp.name, resp.detail);
|
||||
};
|
||||
|
||||
return {
|
||||
get root() { return root; },
|
||||
|
||||
watch: eventTarget.watch,
|
||||
unwatch: eventTarget.unwatch,
|
||||
eventTarget: prefix => eventTarget.scopeTo(prefix),
|
||||
|
||||
ping: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if(worker === undefined)
|
||||
throw 'no worker active';
|
||||
|
||||
let pingTimeout;
|
||||
let localPingId = pingId;
|
||||
|
||||
const pingHandleMessage = ev => {
|
||||
if(typeof ev.data === 'string' && ev.data.startsWith('pong:') && ev.data.substring(5) === localPingId)
|
||||
try {
|
||||
reject = undefined;
|
||||
pingId = undefined;
|
||||
|
||||
if(pingTimeout !== undefined)
|
||||
clearTimeout(pingTimeout);
|
||||
|
||||
worker?.removeEventListener('message', pingHandleMessage);
|
||||
|
||||
if(typeof resolve === 'function')
|
||||
resolve();
|
||||
} finally {
|
||||
resolve = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
worker.addEventListener('message', pingHandleMessage);
|
||||
|
||||
if(localPingId === undefined) {
|
||||
pingId = localPingId = MamiUniqueStr(8);
|
||||
|
||||
broadcastTimeoutZone(timeout => {
|
||||
pingTimeout = setTimeout(() => {
|
||||
try {
|
||||
resolve = undefined;
|
||||
|
||||
worker?.removeEventListener('message', pingHandleMessage);
|
||||
|
||||
timeout({ at: 'ping' });
|
||||
if(typeof reject === 'function')
|
||||
reject('ping timeout');
|
||||
} finally {
|
||||
reject = undefined;
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
|
||||
worker.postMessage(`ping:${localPingId}`);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
sabotage: () => {
|
||||
worker?.terminate();
|
||||
},
|
||||
|
||||
connect: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const connectFinally = () => {
|
||||
if(connectTimeout !== undefined) {
|
||||
clearTimeout(connectTimeout);
|
||||
connectTimeout = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const connectHandleMessage = ev => {
|
||||
worker?.removeEventListener('message', connectHandleMessage);
|
||||
|
||||
if(typeof ev.data !== 'object' || ev.data === null || ev.data.type !== 'objdef'
|
||||
|| typeof ev.data.detail !== 'object' || ev.data.detail.object !== '') {
|
||||
callReject('data');
|
||||
} else
|
||||
callResolve();
|
||||
};
|
||||
|
||||
const callResolve = () => {
|
||||
reject = undefined;
|
||||
connectFinally();
|
||||
try {
|
||||
if(typeof resolve === 'function')
|
||||
resolve(root);
|
||||
} finally {
|
||||
resolve = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const callReject = (...args) => {
|
||||
resolve = undefined;
|
||||
connectFinally();
|
||||
try {
|
||||
broadcastTimeoutZone(timeout => {
|
||||
timeout({ at: 'connect' });
|
||||
});
|
||||
|
||||
if(typeof reject === 'function')
|
||||
reject(...args);
|
||||
} finally {
|
||||
reject = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
if(worker !== undefined) {
|
||||
worker.terminate();
|
||||
workerId = worker = undefined;
|
||||
}
|
||||
|
||||
hasTimedout = false;
|
||||
workerId = MamiUniqueStr(5);
|
||||
worker = new Worker(url);
|
||||
worker.addEventListener('message', handleMessage);
|
||||
worker.addEventListener('message', connectHandleMessage);
|
||||
|
||||
connectTimeout = setTimeout(() => callReject('timeout'), timeOutMs);
|
||||
worker.postMessage({ type: 'init' });
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
#include skel.js
|
||||
#include sockchat/proto.js
|
||||
|
||||
const skel = new WorkerSkeleton;
|
||||
|
||||
skel.defineMethod('create', (name, options) => {
|
||||
if(typeof name !== 'string')
|
||||
throw 'name must be a string';
|
||||
|
||||
let proto, prefix;
|
||||
|
||||
if(name === 'sockchat')
|
||||
proto = new SockChatProtocol(
|
||||
skel.createDispatcher(prefix = 'sockchat'),
|
||||
options
|
||||
);
|
||||
|
||||
return skel.defineObject(proto, prefix);
|
||||
}, true);
|
|
@ -1,214 +0,0 @@
|
|||
#include uniqstr.js
|
||||
|
||||
const WorkerSkeletonObject = function(name, defineObjectMethod, deleteObjectMethod, deleteObject) {
|
||||
if(typeof name !== 'string')
|
||||
throw 'name must be a string';
|
||||
if(typeof defineObjectMethod !== 'function')
|
||||
throw 'defineObjectMethod must be a function';
|
||||
if(typeof deleteObjectMethod !== 'function')
|
||||
throw 'deleteObjectMethod must be a function';
|
||||
if(typeof deleteObject !== 'function')
|
||||
throw 'deleteObject must be a function';
|
||||
|
||||
return {
|
||||
getObjectName: () => name,
|
||||
defineMethod: (...args) => defineObjectMethod(name, ...args),
|
||||
deleteMethod: (...args) => deleteObjectMethod(name, ...args),
|
||||
destroy: () => deleteObject(name),
|
||||
};
|
||||
};
|
||||
|
||||
const WorkerSkeleton = function(globalScope) {
|
||||
if(globalScope === undefined)
|
||||
globalScope = self;
|
||||
|
||||
const objects = new Map;
|
||||
const handlers = {};
|
||||
let initialised = false;
|
||||
|
||||
const sendPayload = (type, detail) => {
|
||||
globalScope.postMessage({ type: type, detail: detail });
|
||||
};
|
||||
|
||||
const sendObjectDefinePayload = (objName, objBody, eventPrefix) => {
|
||||
sendPayload('objdef', { object: objName, methods: Object.keys(objBody), eventPrefix: eventPrefix });
|
||||
};
|
||||
|
||||
const defineObject = (objName, objBody, eventPrefix) => {
|
||||
if(typeof objName !== 'string')
|
||||
throw 'objName must be a string';
|
||||
if(typeof eventPrefix !== 'string' && eventPrefix !== undefined)
|
||||
throw 'eventPrefix must be string or undefined';
|
||||
if(objects.has(objName))
|
||||
throw 'objName is already defined';
|
||||
|
||||
const object = {};
|
||||
for(const name in objBody) {
|
||||
const item = objBody[name];
|
||||
if(typeof item === 'function')
|
||||
object[name] = { body: item };
|
||||
}
|
||||
|
||||
objects.set(objName, object);
|
||||
if(initialised)
|
||||
sendObjectDefinePayload(objName, object, eventPrefix);
|
||||
};
|
||||
|
||||
const deleteObject = objName => {
|
||||
if(typeof objName !== 'string')
|
||||
throw 'objName must be a string';
|
||||
if(!objects.has(objName))
|
||||
throw 'objName is not defined';
|
||||
|
||||
objects.delete(objName);
|
||||
if(initialised)
|
||||
sendPayload('objdel', { object: objName });
|
||||
};
|
||||
|
||||
const defineObjectMethod = (objName, metName, metBody, returnsObject) => {
|
||||
if(typeof objName !== 'string')
|
||||
throw 'objName must be a string';
|
||||
if(typeof metName !== 'string')
|
||||
throw 'metName must be a string';
|
||||
if(typeof metBody !== 'function')
|
||||
throw 'metBody must be a function';
|
||||
|
||||
const objBody = objects.get(objName);
|
||||
if(objBody === undefined)
|
||||
throw 'objName has not been defined';
|
||||
|
||||
objBody[metName] = { body: metBody, returnsObject: returnsObject === true };
|
||||
if(initialised)
|
||||
sendPayload('metdef', { object: objName, method: metName });
|
||||
};
|
||||
|
||||
const deleteObjectMethod = (objName, metName) => {
|
||||
if(typeof objName !== 'string')
|
||||
throw 'objName must be a string';
|
||||
if(typeof metName !== 'string')
|
||||
throw 'metName must be a string';
|
||||
|
||||
const objBody = objects.get(objName);
|
||||
if(objBody === undefined)
|
||||
throw 'objName has not been defined';
|
||||
|
||||
delete objBody[objName];
|
||||
if(initialised)
|
||||
sendPayload('metdel', { object: objName, method: metName });
|
||||
};
|
||||
|
||||
const createDispatcher = prefix => {
|
||||
if(prefix === undefined)
|
||||
prefix = '';
|
||||
else if(typeof prefix !== 'string')
|
||||
throw 'prefix must be a string or undefined';
|
||||
|
||||
if(prefix !== '' && !prefix.endsWith(':'))
|
||||
prefix += ':';
|
||||
|
||||
return (name, detail) => sendPayload('evtdisp', { name: prefix + name, detail: detail });
|
||||
};
|
||||
|
||||
defineObject('', {});
|
||||
|
||||
const defineHandler = (name, handler) => {
|
||||
if(typeof name !== 'string')
|
||||
throw 'name must be a string';
|
||||
if(typeof handler !== 'function')
|
||||
throw 'handler must be a function';
|
||||
if(name in handlers)
|
||||
throw 'name is already defined';
|
||||
|
||||
handlers[name] = handler;
|
||||
};
|
||||
|
||||
defineHandler('init', () => {
|
||||
if(initialised)
|
||||
return;
|
||||
initialised = true;
|
||||
|
||||
sendObjectDefinePayload('', objects.get(''));
|
||||
});
|
||||
|
||||
defineHandler('metcall', req => {
|
||||
if(typeof req.id !== 'string')
|
||||
throw 'call id is not a string';
|
||||
|
||||
const respond = (id, success, result, mightBeObject) => {
|
||||
let isObject = false;
|
||||
if(mightBeObject) {
|
||||
const resultType = typeof result;
|
||||
if(resultType === 'string' && objects.has(result))
|
||||
isObject = true;
|
||||
else if(resultType === 'object' && result !== null && typeof result.getObjectName === 'function') {
|
||||
const objectName = result.getObjectName();
|
||||
if(objects.has(objectName)) {
|
||||
isObject = true;
|
||||
result = objectName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendPayload('funcret', {
|
||||
id: id,
|
||||
success: success,
|
||||
result: result,
|
||||
object: isObject,
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
if(typeof req.object !== 'string')
|
||||
throw 'object name is not a string';
|
||||
if(typeof req.method !== 'string')
|
||||
throw 'method name is not a string';
|
||||
|
||||
const object = objects.get(req.object);
|
||||
if(object === undefined)
|
||||
throw 'object is not defined';
|
||||
if(!(req.method in object))
|
||||
throw 'method is not defined in object';
|
||||
|
||||
const args = Array.isArray(req.args) ? req.args : [];
|
||||
const info = object[req.method];
|
||||
let result = info.body(...args);
|
||||
|
||||
if(result instanceof Promise) {
|
||||
result.then(result => respond(req.id, true, result, info.returnsObject)).catch(ex => respond(req.id, false, ex));
|
||||
} else
|
||||
respond(req.id, true, result, info.returnsObject);
|
||||
} catch(ex) {
|
||||
respond(req.id, false, ex);
|
||||
}
|
||||
});
|
||||
|
||||
globalScope.addEventListener('message', ev => {
|
||||
if(typeof ev.data === 'string') {
|
||||
if(ev.data.startsWith('ping:')) {
|
||||
globalScope.postMessage(`pong:${ev.data.substring(5)}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof ev.data === 'object' && ev.data !== null && typeof ev.data.type === 'string') {
|
||||
if(ev.data.type in handlers)
|
||||
handlers[ev.data.type](ev.data.detail);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
sendPayload: sendPayload,
|
||||
createDispatcher: createDispatcher,
|
||||
defineObject: (object, eventPrefix) => {
|
||||
if(typeof object !== 'object' || object === null)
|
||||
return undefined;
|
||||
|
||||
const name = MamiUniqueStr(8);
|
||||
defineObject(name, object, eventPrefix);
|
||||
return new WorkerSkeletonObject(name, defineObjectMethod, deleteObjectMethod, deleteObject);
|
||||
},
|
||||
defineMethod: (...args) => defineObjectMethod('', ...args),
|
||||
deleteMethod: (...args) => deleteObjectMethod('', ...args),
|
||||
};
|
||||
};
|
|
@ -1,38 +0,0 @@
|
|||
const MamiRandomInt = (min, max) => {
|
||||
let ret = 0;
|
||||
const range = max - min;
|
||||
|
||||
const bitsNeeded = Math.ceil(Math.log2(range));
|
||||
if(bitsNeeded > 53)
|
||||
return -1;
|
||||
|
||||
const bytesNeeded = Math.ceil(bitsNeeded / 8),
|
||||
mask = Math.pow(2, bitsNeeded) - 1;
|
||||
|
||||
const bytes = new Uint8Array(bytesNeeded);
|
||||
crypto.getRandomValues(bytes);
|
||||
|
||||
let p = (bytesNeeded - 1) * 8;
|
||||
for(let i = 0; i < bytesNeeded; ++i) {
|
||||
ret += bytes[i] * Math.pow(2, p);
|
||||
p -= 8;
|
||||
}
|
||||
|
||||
ret &= mask;
|
||||
|
||||
if(ret >= range)
|
||||
return MamiRandomInt(min, max);
|
||||
|
||||
return min + ret;
|
||||
};
|
||||
|
||||
const MamiUniqueStr = (() => {
|
||||
const chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789';
|
||||
|
||||
return length => {
|
||||
let str = '';
|
||||
for(let i = 0; i < length; ++i)
|
||||
str += chars[MamiRandomInt(0, chars.length)];
|
||||
return str;
|
||||
};
|
||||
})();
|
Loading…
Reference in a new issue