mirror of
https://github.com/tsl0922/ttyd.git
synced 2025-12-23 20:24:20 +01:00
html: reuse xterm instance on reconnect
This commit is contained in:
@@ -53,6 +53,7 @@ export class Xterm extends Component<Props> {
|
|||||||
private resizeTimeout: number;
|
private resizeTimeout: number;
|
||||||
private backoff: backoff.Backoff;
|
private backoff: backoff.Backoff;
|
||||||
private backoffLock = false;
|
private backoffLock = false;
|
||||||
|
private reconnect = false;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -65,19 +66,27 @@ export class Xterm extends Component<Props> {
|
|||||||
initialDelay: 100,
|
initialDelay: 100,
|
||||||
maxDelay: 10000,
|
maxDelay: 10000,
|
||||||
});
|
});
|
||||||
|
this.backoff.failAfter(15);
|
||||||
this.backoff.on('ready', () => {
|
this.backoff.on('ready', () => {
|
||||||
this.backoffLock = false;
|
this.backoffLock = false;
|
||||||
this.refreshToken().then(this.openTerminal);
|
this.refreshToken().then(this.connect);
|
||||||
});
|
});
|
||||||
this.backoff.on('backoff', (_, delay: number) => {
|
this.backoff.on('backoff', (_, delay: number) => {
|
||||||
console.log(`[ttyd] will attempt to reconnect websocket in ${delay}ms`);
|
console.log(`[ttyd] will attempt to reconnect websocket in ${delay}ms`);
|
||||||
this.backoffLock = true;
|
this.backoffLock = true;
|
||||||
});
|
});
|
||||||
|
this.backoff.on('fail', () => {
|
||||||
|
this.backoffLock = true; // break backoff
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
await this.refreshToken();
|
await this.refreshToken();
|
||||||
this.openTerminal();
|
this.openTerminal();
|
||||||
|
this.connect();
|
||||||
|
|
||||||
|
window.addEventListener('resize', this.onWindowResize);
|
||||||
|
window.addEventListener('beforeunload', this.onWindowUnload);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@@ -125,32 +134,26 @@ export class Xterm extends Component<Props> {
|
|||||||
this.resizeTimeout = setTimeout(() => fitAddon.fit(), 250) as any;
|
this.resizeTimeout = setTimeout(() => fitAddon.fit(), 250) as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onWindowUnload(event: BeforeUnloadEvent): string {
|
@bind
|
||||||
const message = 'Close terminal? this will also terminate the command.';
|
private onWindowUnload(event: BeforeUnloadEvent): any {
|
||||||
event.returnValue = message;
|
const { socket } = this;
|
||||||
return message;
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||||
|
const message = 'Close terminal? this will also terminate the command.';
|
||||||
|
event.returnValue = message;
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private openTerminal() {
|
private openTerminal() {
|
||||||
if (this.terminal) {
|
|
||||||
this.terminal.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.socket = new WebSocket(this.props.wsUrl, ['tty']);
|
|
||||||
this.terminal = new Terminal(this.props.options);
|
this.terminal = new Terminal(this.props.options);
|
||||||
const { socket, terminal, container, fitAddon, overlayAddon } = this;
|
const { terminal, container, fitAddon, overlayAddon } = this;
|
||||||
window.term = terminal as TtydTerminal;
|
window.term = terminal as TtydTerminal;
|
||||||
window.term.fit = () => {
|
window.term.fit = () => {
|
||||||
this.fitAddon.fit();
|
this.fitAddon.fit();
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.binaryType = 'arraybuffer';
|
|
||||||
socket.onopen = this.onSocketOpen;
|
|
||||||
socket.onmessage = this.onSocketData;
|
|
||||||
socket.onclose = this.onSocketClose;
|
|
||||||
socket.onerror = this.onSocketError;
|
|
||||||
|
|
||||||
terminal.loadAddon(fitAddon);
|
terminal.loadAddon(fitAddon);
|
||||||
terminal.loadAddon(overlayAddon);
|
terminal.loadAddon(overlayAddon);
|
||||||
terminal.loadAddon(new WebLinksAddon());
|
terminal.loadAddon(new WebLinksAddon());
|
||||||
@@ -171,46 +174,61 @@ export class Xterm extends Component<Props> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
terminal.open(container);
|
terminal.open(container);
|
||||||
terminal.focus();
|
|
||||||
|
|
||||||
window.addEventListener('resize', this.onWindowResize);
|
|
||||||
window.addEventListener('beforeunload', this.onWindowUnload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private reconnect() {
|
private connect() {
|
||||||
if (!this.backoffLock) {
|
this.socket = new WebSocket(this.props.wsUrl, ['tty']);
|
||||||
this.backoff.backoff();
|
const { socket } = this;
|
||||||
}
|
|
||||||
|
socket.binaryType = 'arraybuffer';
|
||||||
|
socket.onopen = this.onSocketOpen;
|
||||||
|
socket.onmessage = this.onSocketData;
|
||||||
|
socket.onclose = this.onSocketClose;
|
||||||
|
socket.onerror = this.onSocketError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private onSocketOpen() {
|
private onSocketOpen() {
|
||||||
console.log('[ttyd] Websocket connection opened');
|
console.log('[ttyd] websocket connection opened');
|
||||||
this.backoff.reset();
|
this.backoff.reset();
|
||||||
|
|
||||||
const { socket, textEncoder, fitAddon } = this;
|
const { socket, textEncoder, terminal, fitAddon } = this;
|
||||||
socket.send(textEncoder.encode(JSON.stringify({ AuthToken: this.token })));
|
socket.send(textEncoder.encode(JSON.stringify({ AuthToken: this.token })));
|
||||||
fitAddon.fit();
|
|
||||||
|
if (this.reconnect) {
|
||||||
|
const dims = fitAddon.proposeDimensions();
|
||||||
|
terminal.reset();
|
||||||
|
terminal.resize(dims.cols, dims.rows);
|
||||||
|
this.onTerminalResize(dims); // may not be triggered by terminal.resize
|
||||||
|
} else {
|
||||||
|
this.reconnect = true;
|
||||||
|
fitAddon.fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private onSocketClose(event: CloseEvent) {
|
private onSocketClose(event: CloseEvent) {
|
||||||
console.log(`[ttyd] websocket connection closed with code: ${event.code}`);
|
console.log(`[ttyd] websocket connection closed with code: ${event.code}`);
|
||||||
|
|
||||||
const { overlayAddon } = this;
|
const { backoff, backoffLock, overlayAddon } = this;
|
||||||
overlayAddon.showOverlay('Connection Closed', null);
|
overlayAddon.showOverlay('Connection Closed', null);
|
||||||
window.removeEventListener('beforeunload', this.onWindowUnload);
|
|
||||||
|
|
||||||
// 1000: CLOSE_NORMAL
|
// 1000: CLOSE_NORMAL
|
||||||
if (event.code !== 1000) {
|
if (event.code !== 1000 && !backoffLock) {
|
||||||
this.reconnect();
|
backoff.backoff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private onSocketError() {
|
private onSocketError(event: Event) {
|
||||||
this.reconnect();
|
console.error('[ttyd] websocket connection error: ', event);
|
||||||
|
const { backoff, backoffLock } = this;
|
||||||
|
if (!backoffLock) {
|
||||||
|
backoff.backoff();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ const baseConfig = {
|
|||||||
performance : {
|
performance : {
|
||||||
hints : false
|
hints : false
|
||||||
},
|
},
|
||||||
devtool: 'source-map',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const devConfig = {
|
const devConfig = {
|
||||||
@@ -77,7 +76,8 @@ const devConfig = {
|
|||||||
target: 'http://localhost:7681',
|
target: 'http://localhost:7681',
|
||||||
ws: true
|
ws: true
|
||||||
}]
|
}]
|
||||||
}
|
},
|
||||||
|
devtool: 'inline-source-map',
|
||||||
};
|
};
|
||||||
|
|
||||||
const prodConfig = {
|
const prodConfig = {
|
||||||
@@ -96,7 +96,8 @@ const prodConfig = {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
devtool: 'source-map',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
4034
src/html.h
4034
src/html.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user