From 8f754b153c80615228f431b073adb9d8c45f7494 Mon Sep 17 00:00:00 2001 From: Shuanglei Tao Date: Sat, 29 Oct 2022 23:47:23 +0800 Subject: [PATCH] html: add option to toggle zmodem --- html/src/components/app.tsx | 1 + html/src/components/terminal/index.tsx | 39 +- html/src/components/zmodem/index.tsx | 14 +- src/html.h | 6408 ++++++++++++------------ 4 files changed, 3246 insertions(+), 3216 deletions(-) diff --git a/html/src/components/app.tsx b/html/src/components/app.tsx index 808f85b..6a7ceb9 100644 --- a/html/src/components/app.tsx +++ b/html/src/components/app.tsx @@ -16,6 +16,7 @@ const clientOptions = { rendererType: 'webgl', disableLeaveAlert: false, disableResizeOverlay: false, + enableZmodem: false, titleFixed: null, } as ClientOptions; const termOptions = { diff --git a/html/src/components/terminal/index.tsx b/html/src/components/terminal/index.tsx index 9f111a9..5fb25c7 100644 --- a/html/src/components/terminal/index.tsx +++ b/html/src/components/terminal/index.tsx @@ -43,9 +43,12 @@ export interface ClientOptions { rendererType: RendererType; disableLeaveAlert: boolean; disableResizeOverlay: boolean; + enableZmodem: boolean; titleFixed: string; } +type Options = ITerminalOptions & ClientOptions; + export interface FlowControl { limit: number; highWater: number; @@ -61,7 +64,11 @@ interface Props { flowControl: FlowControl; } -export class Xterm extends Component { +interface State { + zmodem: boolean; +} + +export class Xterm extends Component { private textEncoder: TextEncoder; private textDecoder: TextDecoder; private container: HTMLElement; @@ -72,11 +79,11 @@ export class Xterm extends Component { private fitAddon: FitAddon; private overlayAddon: OverlayAddon; - private zmodemAddon: ZmodemAddon; private webglAddon: WebglAddon; private canvasAddon: CanvasAddon; private socket: WebSocket; + private writeFunc: (data: ArrayBuffer) => void; private token: string; private opened = false; private title: string; @@ -89,6 +96,7 @@ export class Xterm extends Component { constructor(props: Props) { super(props); + this.writeFunc = (data: ArrayBuffer) => this.writeData(new Uint8Array(data)); this.textEncoder = new TextEncoder(); this.textDecoder = new TextDecoder(); this.fitAddon = new FitAddon(); @@ -112,10 +120,10 @@ export class Xterm extends Component { window.removeEventListener('beforeunload', this.onWindowUnload); } - render({ id }: Props) { + render({ id }: Props, { zmodem }: State) { return (
(this.container = c)}> - (this.zmodemAddon = c)} sender={this.sendData} writer={this.writeData} /> + {zmodem && }
); } @@ -132,6 +140,12 @@ export class Xterm extends Component { socket.send(textEncoder.encode(Command.RESUME)); } + @bind + private zmodemCb(addon: ZmodemAddon) { + this.terminal.loadAddon(addon); + this.writeFunc = (data: ArrayBuffer) => addon.consume(data); + } + @bind private sendData(data: string | Uint8Array) { const { socket, textEncoder } = this; @@ -190,7 +204,6 @@ export class Xterm extends Component { terminal.loadAddon(fitAddon); terminal.loadAddon(overlayAddon); terminal.loadAddon(new WebLinksAddon()); - terminal.loadAddon(this.zmodemAddon); terminal.loadAddon(new ImageAddon(imageWorkerUrl)); terminal.onTitleChange(data => { @@ -308,9 +321,8 @@ export class Xterm extends Component { } @bind - private applyOptions(options: ITerminalOptions) { + private applyOptions(options: Options) { const { terminal, fitAddon } = this; - Object.keys(options).forEach(key => { const value = options[key]; switch (key) { @@ -336,6 +348,12 @@ export class Xterm extends Component { this.doReconnect = false; } break; + case 'enableZmodem': + if (value) { + this.setState({ zmodem: true }); + console.log(`[ttyd] Zmodem enabled`); + } + break; case 'titleFixed': if (!value || value === '') return; console.log(`[ttyd] setting fixed title: ${value}`); @@ -417,14 +435,14 @@ export class Xterm extends Component { @bind private onSocketData(event: MessageEvent) { - const { textDecoder, zmodemAddon } = this; + const { textDecoder } = this; const rawData = event.data as ArrayBuffer; const cmd = String.fromCharCode(new Uint8Array(rawData)[0]); const data = rawData.slice(1); switch (cmd) { case Command.OUTPUT: - zmodemAddon.consume(data); + this.writeFunc(data); break; case Command.SET_WINDOW_TITLE: this.title = textDecoder.decode(data); @@ -432,8 +450,7 @@ export class Xterm extends Component { break; case Command.SET_PREFERENCES: const prefs = JSON.parse(textDecoder.decode(data)); - const options = Object.assign({}, this.props.clientOptions, prefs) as ITerminalOptions; - this.applyOptions(options); + this.applyOptions({ ...this.props.clientOptions, ...prefs } as Options); break; default: console.warn(`[ttyd] unknown command: ${cmd}`); diff --git a/html/src/components/zmodem/index.tsx b/html/src/components/zmodem/index.tsx index 7850bf3..6022950 100644 --- a/html/src/components/zmodem/index.tsx +++ b/html/src/components/zmodem/index.tsx @@ -7,6 +7,7 @@ import * as Zmodem from 'zmodem.js/src/zmodem_browser'; import { Modal } from '../modal'; interface Props { + callback: (addon: ZmodemAddon) => void; sender: (data: string | Uint8Array) => void; writer: (data: string | Uint8Array) => void; } @@ -27,7 +28,7 @@ export class ZmodemAddon extends Component implements ITerminalAdd this.zmodemInit(); } - render(_, { modal }: State) { + render(_: Props, { modal }: State) { return (