Skip to content

Commit

Permalink
html: implement flow control for xterm
Browse files Browse the repository at this point in the history
  • Loading branch information
tsl0922 committed Dec 27, 2020
1 parent 61a9bcd commit 4ab5479
Show file tree
Hide file tree
Showing 5 changed files with 628 additions and 544 deletions.
26 changes: 24 additions & 2 deletions html/src/components/terminal/index.tsx
Expand Up @@ -7,7 +7,7 @@ import { WebglAddon } from 'xterm-addon-webgl';
import { WebLinksAddon } from 'xterm-addon-web-links';

import { OverlayAddon } from './overlay';
import { ZmodemAddon } from '../zmodem';
import { ZmodemAddon, FlowControl } from '../zmodem';

import 'xterm/css/xterm.css';

Expand All @@ -30,6 +30,8 @@ const enum Command {
// client side
INPUT = '0',
RESIZE_TERMINAL = '1',
PAUSE = '2',
RESUME = '3',
}

export interface ClientOptions {
Expand Down Expand Up @@ -112,13 +114,33 @@ export class Xterm extends Component<Props> {
}

render({ id }: Props) {
const control = {
limit: 100000,
highWater: 10,
lowWater: 4,
pause: () => this.pause(),
resume: () => this.resume(),
} as FlowControl;

return (
<div id={id} ref={c => (this.container = c)}>
<ZmodemAddon ref={c => (this.zmodemAddon = c)} sender={this.sendData} />
<ZmodemAddon ref={c => (this.zmodemAddon = c)} sender={this.sendData} control={control} />
</div>
);
}

@bind
private pause() {
const { textEncoder, socket } = this;
socket.send(textEncoder.encode(Command.PAUSE));
}

@bind
private resume() {
const { textEncoder, socket } = this;
socket.send(textEncoder.encode(Command.RESUME));
}

@bind
private sendData(data: ArrayLike<number>) {
const { socket } = this;
Expand Down
34 changes: 33 additions & 1 deletion html/src/components/zmodem/index.tsx
Expand Up @@ -6,8 +6,18 @@ import * as Zmodem from 'zmodem.js/src/zmodem_browser';

import { Modal } from '../modal';

export interface FlowControl {
limit: number;
highWater: number;
lowWater: number;

pause: () => void;
resume: () => void;
}

interface Props {
sender: (data: ArrayLike<number>) => void;
control: FlowControl;
}

interface State {
Expand All @@ -20,6 +30,9 @@ export class ZmodemAddon extends Component<Props, State> implements ITerminalAdd
private sentry: Zmodem.Sentry;
private session: Zmodem.Session;

private written = 0;
private pending = 0;

constructor(props: Props) {
super(props);

Expand Down Expand Up @@ -84,7 +97,26 @@ export class ZmodemAddon extends Component<Props, State> implements ITerminalAdd

@bind
private zmodemWrite(data: ArrayBuffer): void {
this.terminal.write(new Uint8Array(data));
const { limit, highWater, lowWater, pause, resume } = this.props.control;
const { terminal } = this;
const rawData = new Uint8Array(data);

this.written += rawData.length;
if (this.written > limit) {
terminal.write(rawData, () => {
this.pending = Math.max(this.pending - 1, 0);
if (this.pending < lowWater) {
resume();
}
});
this.pending++;
this.written = 0;
if (this.pending > highWater) {
pause();
}
} else {
terminal.write(rawData);
}
}

@bind
Expand Down

0 comments on commit 4ab5479

Please sign in to comment.