|
| 1 | +import * as log from 'loglevel'; |
| 2 | +import ExternalInterface, {ExternalInterfaceCtx} from './util/ExternalInterface'; |
| 3 | +import Vienna from './folding/Vienna'; |
| 4 | +import Vienna2 from './folding/Vienna2'; |
| 5 | +import NuPACK from './folding/NuPACK'; |
| 6 | +import Contrafold from './folding/Contrafold'; |
| 7 | +import EternaFold from './folding/Eternafold'; |
| 8 | +import EternaFoldThreshknot from './folding/EternafoldThreshknot'; |
| 9 | +import RNAFoldBasic from './folding/RNAFoldBasic'; |
| 10 | +import FolderManager from './folding/FolderManager'; |
| 11 | +import LinearFoldC from './folding/LinearFoldC'; |
| 12 | +import LinearFoldE from './folding/LinearFoldE'; |
| 13 | +import LinearFoldV from './folding/LinearFoldV'; |
| 14 | +import Folder from './folding/Folder'; |
| 15 | +import FoldingAPI from './eternaScript/FoldingAPI'; |
| 16 | + |
| 17 | +interface FoldingAppParams { |
| 18 | + containerID?: string; |
| 19 | + folderName?: string; |
| 20 | +} |
| 21 | + |
| 22 | +interface ProcessedFoldingAppParams { |
| 23 | + containerID: string; |
| 24 | + folderName: string; |
| 25 | +} |
| 26 | + |
| 27 | +export class WasmNotSupportedError extends Error {} |
| 28 | + |
| 29 | +export class ContainerElementNotFound extends Error {} |
| 30 | + |
| 31 | +/** |
| 32 | + * Entry point for the folding API provider. |
| 33 | + * |
| 34 | + * This is an alternate version of EternaJS, only exposing the API needed for scripts to work |
| 35 | + * (e.g. `Lib.fold` via `document.getElementById("maingame").fold`). |
| 36 | + * */ |
| 37 | +export default class FoldingAPIApp { |
| 38 | + constructor(params: FoldingAppParams) { |
| 39 | + // Default param values |
| 40 | + params.containerID = params.containerID || 'maingame'; |
| 41 | + params.folderName = 'vienna'; |
| 42 | + |
| 43 | + this._params = {containerID: params.containerID, folderName: params.folderName}; |
| 44 | + |
| 45 | + const appContainer: HTMLElement | null = document.getElementById(params.containerID); |
| 46 | + if (!appContainer) { |
| 47 | + throw new ContainerElementNotFound(`Could not find HTML element with ID ${params.containerID}`); |
| 48 | + } |
| 49 | + this._appContainer = appContainer; |
| 50 | + |
| 51 | + ExternalInterface.init(appContainer); |
| 52 | + } |
| 53 | + |
| 54 | + private static isWebAssemblySupported() { |
| 55 | + return typeof WebAssembly === 'object'; |
| 56 | + } |
| 57 | + |
| 58 | + public async run(): Promise<void> { |
| 59 | + if (!FoldingAPIApp.isWebAssemblySupported()) { |
| 60 | + throw new WasmNotSupportedError( |
| 61 | + "Can't initialize the folding API app, since the browser doesn't support WASM" |
| 62 | + ); |
| 63 | + } |
| 64 | + |
| 65 | + await this.initFoldingEngines(); |
| 66 | + this.initScriptInterface(); |
| 67 | + } |
| 68 | + |
| 69 | + public disposeNow(): void { |
| 70 | + this._appContainer.innerHTML = ''; |
| 71 | + |
| 72 | + FolderManager.dispose(); |
| 73 | + ExternalInterface.dispose(); |
| 74 | + } |
| 75 | + |
| 76 | + private async initFoldingEngines(): Promise<void> { |
| 77 | + log.info('Initializing folding engines...'); |
| 78 | + const folders: (Folder | null)[] = await Promise.all([ |
| 79 | + Vienna.create(), |
| 80 | + Vienna2.create(), |
| 81 | + NuPACK.create(), |
| 82 | + LinearFoldC.create(), |
| 83 | + LinearFoldE.create(), |
| 84 | + LinearFoldV.create(), |
| 85 | + Contrafold.create(), |
| 86 | + EternaFold.create(), |
| 87 | + EternaFoldThreshknot.create(), |
| 88 | + RNAFoldBasic.create()]); |
| 89 | + |
| 90 | + log.info('Folding engines intialized'); |
| 91 | + for (const folder of folders) { |
| 92 | + if (folder !== null) { |
| 93 | + FolderManager.instance.addFolder(folder); |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + const folder = FolderManager.instance.getFolder(this._params.folderName); |
| 98 | + if (folder === null) { |
| 99 | + log.warn(`No such folder '${this._params.folderName}'`); |
| 100 | + } else { |
| 101 | + this._folder = folder; |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + private initScriptInterface(): void { |
| 106 | + new FoldingAPI({ |
| 107 | + getFolder: () => this._folder, |
| 108 | + getIsPseudoknot: () => false |
| 109 | + }).registerToScriptInterface(this._scriptInterface); |
| 110 | + |
| 111 | + ExternalInterface.pushContext(this._scriptInterface); |
| 112 | + } |
| 113 | + |
| 114 | + private readonly _params: ProcessedFoldingAppParams; |
| 115 | + private readonly _scriptInterface: ExternalInterfaceCtx = new ExternalInterfaceCtx(); |
| 116 | + private readonly _appContainer: HTMLElement; |
| 117 | + // private readonly _folderSwitcher: FolderSwitcher; |
| 118 | + private _folder: Folder; |
| 119 | +} |
0 commit comments