]> git.proxmox.com Git - pve-xtermjs.git/blame - src/www/main.js
upgrade xterm.js to version 4.3.0
[pve-xtermjs.git] / src / www / main.js
CommitLineData
dcf3d43b
DC
1console.log('xtermjs: starting');
2
3var states = {
4 start: 1,
5 connecting: 2,
6 connected: 3,
7 disconnecting: 4,
8 disconnected: 5,
291e1a24 9 reconnecting: 6,
dcf3d43b
DC
10};
11
12var term,
13 protocol,
14 socketURL,
15 socket,
16 ticket,
dcf3d43b
DC
17 resize,
18 ping,
291e1a24
DC
19 state = states.start,
20 starttime = new Date();
21
22var type = getQueryParameter('console');
23var vmid = getQueryParameter('vmid');
24var vmname = getQueryParameter('vmname');
25var nodename = getQueryParameter('node');
6c7c792d 26var cmd = getQueryParameter('cmd');
dcf3d43b
DC
27
28function updateState(newState, msg) {
29 var timeout, severity, message;
30 switch (newState) {
31 case states.connecting:
32 message = "Connecting...";
33 timeout = 0;
34 severity = severities.warning;
35 break;
36 case states.connected:
37 message = "Connected";
38 break;
39 case states.disconnecting:
40 message = "Disconnecting...";
41 timeout = 0;
42 severity = severities.warning;
43 break;
291e1a24
DC
44 case states.reconnecting:
45 message = "Reconnecting...";
46 timeout = 0;
47 severity = severities.warning;
48 break;
dcf3d43b
DC
49 case states.disconnected:
50 switch (state) {
51 case states.start:
52 case states.connecting:
291e1a24 53 case states.reconnecting:
dcf3d43b
DC
54 message = "Connection failed";
55 timeout = 0;
56 severity = severities.error;
57 break;
58 case states.connected:
59 case states.disconnecting:
291e1a24
DC
60 var time_since_started = new Date() - starttime;
61 timeout = 5000;
3645b3f4 62 if (time_since_started > 5*1000 || type === 'shell') {
291e1a24
DC
63 message = "Connection closed";
64 } else {
65 message = "Connection failed";
66 severity = severities.error;
67 }
dcf3d43b
DC
68 break;
69 case states.disconnected:
70 // no state change
71 break;
72 default:
73 throw "unknown state";
74 }
75 break;
76 default:
77 throw "unknown state";
78 }
79 if (msg) {
80 message += " (" + msg + ")";
81 }
82 state = newState;
83 showMsg(message, timeout, severity);
84}
85
86var terminalContainer = document.getElementById('terminal-container');
87document.getElementById('status_bar').addEventListener('click', hideMsg);
5e8b8730 88Terminal.applyAddon(fit);
dcf3d43b
DC
89
90createTerminal();
91
92function createTerminal() {
37445374 93 term = new Terminal(getTerminalSettings());
dcf3d43b
DC
94
95 term.on('resize', function (size) {
96 if (state === states.connected) {
97 socket.send("1:" + size.cols + ":" + size.rows + ":");
98 }
99 });
100
101 protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
102
103 var params = {};
dcf3d43b
DC
104 var url = '/nodes/' + nodename;
105 switch (type) {
106 case 'kvm':
107 url += '/qemu/' + vmid;
dcf3d43b
DC
108 break;
109 case 'lxc':
110 url += '/lxc/' + vmid;
dcf3d43b
DC
111 break;
112 case 'upgrade':
113 params.upgrade = 1;
dcf3d43b 114 break;
6c7c792d
TM
115 case 'cmd':
116 params.cmd = decodeURI(cmd);
117 break;
dcf3d43b
DC
118 }
119 API2Request({
120 method: 'POST',
121 params: params,
122 url: url + '/termproxy',
123 success: function(result) {
124 var port = encodeURIComponent(result.data.port);
125 ticket = result.data.ticket;
126 socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/api2/json' + url + '/vncwebsocket?port=' + port + '&vncticket=' + encodeURIComponent(ticket);
127
128 term.open(terminalContainer, true);
129 socket = new WebSocket(socketURL, 'binary');
130 socket.binaryType = 'arraybuffer';
131 socket.onopen = runTerminal;
291e1a24
DC
132 socket.onclose = tryReconnect;
133 socket.onerror = tryReconnect;
dcf3d43b
DC
134 window.onbeforeunload = stopTerminal;
135 updateState(states.connecting);
136 },
137 failure: function(msg) {
138 updateState(states.disconnected,msg);
139 }
140 });
141
142}
143
144function runTerminal() {
145 socket.onmessage = function(event) {
146 var answer = Utf8ArrayToStr(event.data);
147 if (state === states.connected) {
148 term.write(answer);
149 } else if(state === states.connecting) {
150 if (answer.slice(0,2) === "OK") {
151 updateState(states.connected);
152 term.write(answer.slice(2));
153 } else {
154 socket.close();
155 }
156 }
157 };
158
159 term.on('data', function(data) {
160 if (state === states.connected) {
161 socket.send("0:" + unescape(encodeURIComponent(data)).length.toString() + ":" + data);
162 }
163 });
164
165 ping = setInterval(function() {
166 socket.send("2");
167 }, 30*1000);
168
169 window.addEventListener('resize', function() {
170 clearTimeout(resize);
171 resize = setTimeout(function() {
172 // done resizing
173 term.fit();
174 }, 250);
175 });
176
5e91985c 177 socket.send(PVE.UserName + ':' + ticket + "\n");
dcf3d43b 178
1553e6ef
DC
179 // initial focus and resize
180 setTimeout(function() {
181 term.focus();
182 term.fit();
183 }, 250);
dcf3d43b
DC
184}
185
291e1a24
DC
186function getLxcStatus(callback) {
187 API2Request({
188 method: 'GET',
189 url: '/nodes/' + nodename + '/lxc/' + vmid + '/status/current',
190 success: function(result) {
191 if (typeof callback === 'function') {
192 callback(true, result);
193 }
194 },
195 failure: function(msg) {
196 if (typeof callback === 'function') {
197 callback(false, msg);
198 }
199 }
200 });
201}
202
203function checkMigration() {
204 var apitype = type;
205 if (apitype === 'kvm') {
206 apitype = 'qemu';
207 }
208 API2Request({
209 method: 'GET',
210 params: {
211 type: 'vm'
212 },
213 url: '/cluster/resources',
214 success: function(result) {
215 // if not yet migrated , wait and try again
216 // if not migrating and stopped, cancel
217 // if started, connect
218 result.data.forEach(function(entity) {
219 if (entity.id === (apitype + '/' + vmid)) {
220 var started = entity.status === 'running';
221 var migrated = entity.node !== nodename;
222 if (migrated) {
223 if (started) {
224 // goto different node
225 location.href = '?console=' + type +
226 '&xtermjs=1&vmid=' + vmid + '&vmname=' +
227 vmname + '&node=' + entity.node;
228 } else {
229 // wait again
230 updateState(states.reconnecting, 'waiting for migration to finish...');
231 setTimeout(checkMigration, 5000);
232 }
233 } else {
234 if (type === 'lxc') {
235 // we have to check the status of the
236 // container to know if it has the
237 // migration lock
238 getLxcStatus(function(success, result) {
239 if (success) {
240 if (result.data.lock === 'migrate') {
241 // still waiting
242 updateState(states.reconnecting, 'waiting for migration to finish...');
243 setTimeout(checkMigration, 5000);
8f2ac472
DC
244 } else if (started) {
245 // container was rebooted
246 location.reload();
291e1a24
DC
247 } else {
248 stopTerminal();
249 }
250 } else {
251 // probably the status call failed because
252 // the ct is already somewhere else, so retry
253 setTimeout(checkMigration, 1000);
254 }
255 });
256 } else if (started) {
257 // this happens if we have old data in
258 // /cluster/resources, or the connection
259 // disconnected, so simply try to reload here
260 location.reload();
261 } else if (type === 'kvm') {
262 // it seems the guest simply stopped
263 stopTerminal();
264 }
265 }
266
267 return;
268 }
269 });
270 },
271 failure: function(msg) {
272 errorTerminal({msg: msg});
273 }
274 });
275}
276
277function tryReconnect() {
278 var time_since_started = new Date() - starttime;
279 var type = getQueryParameter('console');
6c7c792d 280 if (time_since_started < 5*1000 || type === 'shell' || type === 'cmd') { // 5 seconds
8c502b81 281 stopTerminal();
291e1a24 282 return;
291e1a24
DC
283 }
284
285 updateState(states.disconnecting, 'Detecting migration...');
286 setTimeout(checkMigration, 5000);
287}
288
dcf3d43b 289function stopTerminal(event) {
8c502b81 290 event = event || {};
dcf3d43b
DC
291 term.off('resize');
292 term.off('data');
293 clearInterval(ping);
294 socket.close();
295 updateState(states.disconnected, event.msg + event.code);
296}
297
298function errorTerminal(event) {
8c502b81 299 even = event || {};
dcf3d43b
DC
300 term.off('resize');
301 term.off('data');
302 clearInterval(ping);
303 socket.close();
f21a83b7 304 term.dispose();
dcf3d43b
DC
305 updateState(states.disconnected, event.msg + event.code);
306}