-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathterminal.ts
131 lines (109 loc) · 3.36 KB
/
terminal.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
import { IShell } from '@jupyterlite/cockle';
import { JSONPrimitive } from '@lumino/coreutils';
import { ISignal, Signal } from '@lumino/signaling';
import {
Server as WebSocketServer,
Client as WebSocketClient
} from 'mock-socket';
import { Shell } from './shell';
import { ITerminal } from './tokens';
export class Terminal implements ITerminal {
/**
* Construct a new Terminal.
*/
constructor(readonly options: ITerminal.IOptions) {
this._shell = new Shell({
mountpoint: '/drive',
driveFsBaseUrl: options.baseUrl,
wasmBaseUrl:
options.baseUrl + 'extensions/@jupyterlite/terminal/static/wasm/',
outputCallback: this._outputCallback.bind(this)
});
this._shell.disposed.connect(() => this.dispose());
}
private _outputCallback(text: string): void {
if (this._socket) {
const ret = JSON.stringify(['stdout', text]);
this._socket.send(ret);
}
}
dispose(): void {
if (this._isDisposed) {
return;
}
console.log('Terminal.dispose');
this._isDisposed = true;
if (this._socket !== undefined) {
// Disconnect from frontend.
this._socket.send(JSON.stringify(['disconnect']));
this._socket.close();
this._socket = undefined;
}
if (this._server !== undefined) {
this._server.close();
this._server = undefined;
}
this._shell.dispose();
this._disposed.emit();
}
get disposed(): ISignal<this, void> {
return this._disposed;
}
get isDisposed(): boolean {
return this._isDisposed;
}
/**
* Get the name of the terminal.
*/
get name(): string {
return this.options.name;
}
async wsConnect(url: string) {
console.log('Terminal wsConnect', url);
this._server = new WebSocketServer(url);
this._server.on('connection', async (socket: WebSocketClient) => {
console.log('Terminal server connection');
if (this._socket !== undefined) {
this._socket.send(JSON.stringify(['disconnect']));
this._socket.close();
this._socket = undefined;
}
this._socket = socket;
socket.on('message', async (message: any) => {
const data = JSON.parse(message) as JSONPrimitive[];
//console.log('==> socket message', data);
const message_type = data[0];
const content = data.slice(1);
if (message_type === 'stdin') {
await this._shell.input(content[0] as string);
} else if (message_type === 'set_size') {
const rows = content[0] as number;
const columns = content[1] as number;
await this._shell.setSize(rows, columns);
}
});
socket.on('close', () => {
console.log('Terminal socket close');
});
socket.on('error', () => {
console.log('Terminal socket error');
});
// Return handshake.
const res = JSON.stringify(['setup']);
console.log('Terminal returning handshake via socket');
socket.send(res);
if (!this._running) {
this._running = true;
await this._shell.start();
}
});
}
private _disposed = new Signal<this, void>(this);
private _isDisposed = false;
private _server?: WebSocketServer;
private _socket?: WebSocketClient;
private _shell: IShell;
private _running = false;
}