UNPKG

@casual-simulation/aux-vm-browser

Version:

A set of utilities required to securely run an AUX in a web browser.

139 lines 4.47 kB
import { merge, applyUpdates, stateUpdatedEvent, } from '@casual-simulation/aux-common'; import { BehaviorSubject, Subject } from 'rxjs'; import { wrap, proxy, releaseProxy } from 'comlink'; import { startWith } from 'rxjs/operators'; /** * Attempts to create a proxy client partition that is loaded from a remote inst. * @param options The options to use. * @param config The config to use. */ export async function createProxyClientPartition(config) { if (config.type === 'proxy_client') { const partition = new ProxyClientPartitionImpl(config); await partition.init(); return partition; } return undefined; } export class ProxyClientPartitionImpl { get space() { return this._space; } set space(value) { this._space = value; this._bridge.setSpace(value); } get onBotsAdded() { return this._onBotsAdded.pipe(startWith(Object.values(this.state))); } get onBotsRemoved() { return this._onBotsRemoved; } get onBotsUpdated() { return this._onBotsUpdated; } get onStateUpdated() { return this._onStateUpdated.pipe(startWith(stateUpdatedEvent(this.state))); } get onVersionUpdated() { return this._onVersionUpdated; } get onError() { return this._onError; } get onEvents() { return this._onEvents; } get onStatusUpdated() { return this._onStatusUpdated; } constructor(config) { this._bridge = wrap(config.port); this.private = config.private; this.realtimeStrategy = config.editStrategy; this.state = {}; this._onBotsAdded = new Subject(); this._onBotsRemoved = new Subject(); this._onBotsUpdated = new Subject(); this._onStateUpdated = new Subject(); this._onVersionUpdated = new BehaviorSubject({ currentSite: null, remoteSite: null, vector: {}, }); this._onError = new Subject(); this._onEvents = new Subject(); this._onStatusUpdated = new Subject(); } async init() { const proxies = [ proxy((bots) => this._handleOnBotsAdded(bots)), proxy((bots) => this._handleOnBotsRemoved(bots)), proxy((bots) => this._handleOnBotsUpdated(bots)), proxy((update) => this._handleOnStateUpdated(update)), proxy((error) => this._onError.next(error)), proxy((events) => this._onEvents.next(events)), proxy((status) => this._onStatusUpdated.next(status)), proxy((version) => this._onVersionUpdated.next(version)), ]; this._proxies = proxies; await this._bridge.addListeners(...proxies); } _handleOnBotsAdded(bots) { let newState = Object.assign({}, this.state); for (let b of bots) { newState[b.id] = { ...b, space: this.space, }; } this.state = newState; this._onBotsAdded.next(bots); } _handleOnBotsRemoved(bots) { let newState = Object.assign({}, this.state); for (let b of bots) { delete newState[b]; } this.state = newState; this._onBotsRemoved.next(bots); } _handleOnBotsUpdated(bots) { let newState = Object.assign({}, this.state); for (let b of bots) { const existing = newState[b.bot.id]; newState[b.bot.id] = merge(existing, b.bot); } this.state = newState; this._onBotsUpdated.next(bots); } _handleOnStateUpdated(update) { this.state = applyUpdates(this.state, update); this._onStateUpdated.next(update); } applyEvents(events) { // Unwrap the nested promise // (technically gets unwrapped automatically, but this // fixes a return type issue) return this._bridge.applyEvents(events).then((a) => a); } async sendRemoteEvents(events) { if (this._bridge.sendRemoteEvents) { await this._bridge.sendRemoteEvents(events); } } connect() { this._bridge.connect(); } unsubscribe() { if (this.closed) { return; } this._bridge.unsubscribe(); for (let p of this._proxies) { p[releaseProxy](); } this.closed = true; } } //# sourceMappingURL=ProxyClientPartition.js.map