/** * Copyright (c) 2017 The xterm.js authors. All rights reserved. * @license MIT */ /// import { Terminal } from 'xterm'; /** * * Allow xterm.js to handle ZMODEM uploads and downloads. * * This addon is a wrapper around zmodem.js. It adds the following to the * Terminal class: * * - function `zmodemAttach(, )` - creates a Zmodem.Sentry * on the passed WebSocket object. The Object passed is optional and * can contain: * - noTerminalWriteOutsideSession: Suppress writes from the Sentry * object to the Terminal while there is no active Session. This * is necessary for compatibility with, for example, the * `attach.js` addon. * * - event `zmodemDetect` - fired on Zmodem.Sentry’s `on_detect` callback. * Passes the zmodem.js Detection object. * * - event `zmodemRetract` - fired on Zmodem.Sentry’s `on_retract` callback. * * You’ll need to provide logic to handle uploads and downloads. * See zmodem.js’s documentation for more details. * * **IMPORTANT:** After you confirm() a zmodem.js Detection, if you have * used the `attach` or `terminado` addons, you’ll need to suspend their * operation for the duration of the ZMODEM session. (The demo does this * via `detach()` and a re-`attach()`.) */ let zmodem; export interface IZmodemOptions { noTerminalWriteOutsideSession?: boolean; } function zmodemAttach(ws: WebSocket, opts: IZmodemOptions = {}): void { const term = this; const senderFunc = (octets: ArrayLike) => ws.send(new Uint8Array(octets)); let zsentry; function _shouldWrite(): boolean { return !!zsentry.get_confirmed_session() || !opts.noTerminalWriteOutsideSession; } zsentry = new zmodem.Sentry({ to_terminal: (octets: ArrayLike) => { if (_shouldWrite()) { term.write( String.fromCharCode.apply(String, octets) ); } }, sender: senderFunc, on_retract: () => (term).emit('zmodemRetract'), on_detect: (detection: any) => (term).emit('zmodemDetect', detection) }); function handleWSMessage(evt: MessageEvent): void { // In testing with xterm.js’s demo the first message was // always text even if the rest were binary. While that // may be specific to xterm.js’s demo, ultimately we // should reject anything that isn’t binary. if (typeof evt.data === 'string') { if (_shouldWrite()) { term.write(evt.data); } } else { zsentry.consume(evt.data); } } ws.binaryType = 'arraybuffer'; ws.addEventListener('message', handleWSMessage); } export function apply(terminalConstructor: typeof Terminal): void { zmodem = (typeof window === 'object') ? (window).Zmodem : {Browser: null}; // Nullify browser for tests (terminalConstructor.prototype).zmodemAttach = zmodemAttach; (terminalConstructor.prototype).zmodemBrowser = zmodem.Browser; }