@casual-simulation/aux-vm-browser
Version:
A set of utilities required to securely run an AUX in a web browser.
218 lines • 7.38 kB
JavaScript
import { remapProgressPercent } from '@casual-simulation/aux-common';
// import Worker from './AuxWorker';
// import Worker from './AuxChannel.worker?worker&inline';
import { BrowserAuxChannel } from './BrowserAuxChannel';
import { Subject } from 'rxjs';
export const DEFAULT_IFRAME_ALLOW_ATTRIBUTE = 'accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking';
export const DEFAULT_IFRAME_SANDBOX_ATTRIBUTE = 'allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts allow-downloads';
/**
* Defines an interface for an AUX that is run inside a virtual machine.
* That is, the AUX is run inside a web worker.
*
* This implementation works similarly to the one in AuxVMImpl, but instead of using an iframe, it loads the web worker directly.
*/
export default class StaticAuxVMImpl {
/**
* The ID of the simulation.
*/
get id() {
return this._id;
}
get configBotId() {
return this._config.configBotId;
}
/**
* Creates a new Simulation VM.
* @param id The ID of the simulation.
* @param origin The origin of the simulation.
* @param config The config that should be used.
* @param relaxOrigin Whether to relax the origin of the VM.
*/
constructor(id, origin, config, relaxOrigin = false) {
this._id = id;
this._origin = origin;
this._config = config;
this._relaxOrigin = relaxOrigin;
this._localEvents = new Subject();
this._deviceEvents = new Subject();
this._stateUpdated = new Subject();
this._versionUpdated = new Subject();
this._connectionStateChanged = new Subject();
this._onError = new Subject();
this._subVMAdded = new Subject();
this._subVMRemoved = new Subject();
this._subVMMap = new Map();
this._onAuthMessage = new Subject();
}
get origin() {
return this._origin;
}
get subVMAdded() {
return this._subVMAdded;
}
get subVMRemoved() {
return this._subVMRemoved;
}
get connectionStateChanged() {
return this._connectionStateChanged;
}
get onError() {
return this._onError;
}
get onAuthMessage() {
return this._onAuthMessage;
}
/**
* The observable list of events that should be produced locally.
*/
get localEvents() {
return this._localEvents;
}
get deviceEvents() {
return this._deviceEvents;
}
/**
* The observable list of bot state updates from this simulation.
*/
get stateUpdated() {
return this._stateUpdated;
}
get versionUpdated() {
return this._versionUpdated;
}
/**
* Initaializes the VM.
*/
async init() {
return await this._init();
}
async _init() {
this._connectionStateChanged.next({
type: 'progress',
message: 'Initializing web worker...',
progress: 0.1,
});
this._connectionStateChanged.next({
type: 'progress',
message: 'Creating VM...',
progress: 0.2,
});
if (!this._channel) {
this._channel = new BrowserAuxChannel(location.origin, this._config);
}
return await this._connect();
}
async _connect() {
let statusMapper = remapProgressPercent(0.2, 1);
return await this._channel.init((events) => this._localEvents.next(events), (events) => this._deviceEvents.next(events), (state) => this._stateUpdated.next(state), (version) => this._versionUpdated.next(version), (state) => this._connectionStateChanged.next(statusMapper(state)), (err) => this._onError.next(err), (channel) => this._handleAddedSubChannel(channel), (id) => this._handleRemovedSubChannel(id), (message) => this._onAuthMessage.next(message));
}
/**
* Sends the given list of events to the simulation.
* @param events The events to send to the simulation.
*/
async sendEvents(events) {
if (!this._channel)
return null;
return await this._channel.sendEvents(events);
}
/**
* Executes a shout with the given event name on the given bot IDs with the given argument.
* Also dispatches any actions and errors that occur.
* Returns the results from the event.
* @param eventName The name of the event.
* @param botIds The IDs of the bots that the shout is being sent to.
* @param arg The argument to include in the shout.
*/
async shout(eventName, botIds, arg) {
if (!this._channel)
return null;
return await this._channel.shout(eventName, botIds, arg);
}
async formulaBatch(formulas) {
if (!this._channel)
return null;
return await this._channel.formulaBatch(formulas);
}
async forkAux(newId) {
if (!this._channel)
return null;
return await this._channel.forkAux(newId);
}
async exportBots(botIds) {
if (!this._channel)
return null;
return await this._channel.exportBots(botIds);
}
/**
* Exports the causal tree for the simulation.
*/
async export() {
if (!this._channel)
return null;
return await this._channel.export();
}
async getTags() {
if (!this._channel)
return null;
return await this._channel.getTags();
}
async updateDevice(device) {
if (!this._channel)
return null;
return await this._channel.updateDevice(device);
}
/**
* Gets a new endpoint for the aux channel.
* Can then be used with a ConnectableAuxVM.
*/
createEndpoint() {
return null;
// return this._channel[createEndpoint]();
}
sendAuthMessage(message) {
return this._channel.sendAuthMessage(message);
}
unsubscribe() {
if (this.closed) {
return;
}
this.closed = true;
if (this._channel) {
this._channel.unsubscribe();
this._channel = null;
}
this._connectionStateChanged.unsubscribe();
this._connectionStateChanged = null;
this._localEvents.unsubscribe();
this._localEvents = null;
}
_createSubVM(id, origin, configBotId, channel) {
const vm = new StaticAuxVMImpl(id, origin, {
...this._config,
configBotId,
});
vm._channel = channel;
return vm;
// return null;
// return new RemoteAuxVM(id, origin, configBotId, channel);
}
async _handleAddedSubChannel(subChannel) {
const { id, configBotId } = await subChannel.getInfo();
const channel = (await subChannel.getChannel());
const subVM = {
id: id,
vm: this._createSubVM(id, this.origin, configBotId, channel),
channel,
};
this._subVMMap.set(id, subVM);
this._subVMAdded.next(subVM);
}
async _handleRemovedSubChannel(channelId) {
const vm = this._subVMMap.get(channelId);
if (vm) {
this._subVMMap.delete(channelId);
this._subVMRemoved.next(vm);
}
}
}
//# sourceMappingURL=StaticAuxVMImpl.js.map