]> git.proxmox.com Git - pve-xtermjs.git/blame - src/www/main.js
upgrade: use cmd not depreacated upgrade param
[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);
b9bbd688 88const fitAddon = new FitAddon.FitAddon();
dcf3d43b
DC
89
90createTerminal();
91
92function createTerminal() {
37445374 93 term = new Terminal(getTerminalSettings());
b9bbd688 94 term.loadAddon(fitAddon);
dcf3d43b 95
b9bbd688 96 term.onResize(function (size) {
dcf3d43b
DC
97 if (state === states.connected) {
98 socket.send("1:" + size.cols + ":" + size.rows + ":");
99 }
100 });
101
102 protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
103
104 var params = {};
dcf3d43b
DC
105 var url = '/nodes/' + nodename;
106 switch (type) {
107 case 'kvm':
108 url += '/qemu/' + vmid;
dcf3d43b
DC
109 break;
110 case 'lxc':
111 url += '/lxc/' + vmid;
dcf3d43b
DC
112 break;
113 case 'upgrade':
af39a6f0 114 params.cmd = 'upgrade';
dcf3d43b 115 break;
6c7c792d
TM
116 case 'cmd':
117 params.cmd = decodeURI(cmd);
118 break;
dcf3d43b
DC
119 }
120 API2Request({
121 method: 'POST',
122 params: params,
123 url: url + '/termproxy',
124 success: function(result) {
125 var port = encodeURIComponent(result.data.port);
126 ticket = result.data.ticket;
127 socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/api2/json' + url + '/vncwebsocket?port=' + port + '&vncticket=' + encodeURIComponent(ticket);
128
129 term.open(terminalContainer, true);
130 socket = new WebSocket(socketURL, 'binary');
131 socket.binaryType = 'arraybuffer';
132 socket.onopen = runTerminal;
291e1a24
DC
133 socket.onclose = tryReconnect;
134 socket.onerror = tryReconnect;
dcf3d43b
DC
135 window.onbeforeunload = stopTerminal;
136 updateState(states.connecting);
137 },
138 failure: function(msg) {
139 updateState(states.disconnected,msg);
140 }
141 });
142
143}
144
145function runTerminal() {
146 socket.onmessage = function(event) {
920ae86d 147 var answer = new Uint8Array(event.data);
dcf3d43b
DC
148 if (state === states.connected) {
149 term.write(answer);
150 } else if(state === states.connecting) {
920ae86d 151 if (answer[0] === 79 && answer[1] === 75) { // "OK"
dcf3d43b
DC
152 updateState(states.connected);
153 term.write(answer.slice(2));
154 } else {
155 socket.close();
156 }
157 }
158 };
159
b9bbd688 160 term.onData(function(data) {
dcf3d43b
DC
161 if (state === states.connected) {
162 socket.send("0:" + unescape(encodeURIComponent(data)).length.toString() + ":" + data);
163 }
164 });
165
166 ping = setInterval(function() {
167 socket.send("2");
168 }, 30*1000);
169
170 window.addEventListener('resize', function() {
171 clearTimeout(resize);
172 resize = setTimeout(function() {
173 // done resizing
b9bbd688 174 fitAddon.fit();
dcf3d43b
DC
175 }, 250);
176 });
177
5e91985c 178 socket.send(PVE.UserName + ':' + ticket + "\n");
dcf3d43b 179
1553e6ef
DC
180 // initial focus and resize
181 setTimeout(function() {
182 term.focus();
b9bbd688 183 fitAddon.fit();
1553e6ef 184 }, 250);
dcf3d43b
DC
185}
186
291e1a24
DC
187function getLxcStatus(callback) {
188 API2Request({
189 method: 'GET',
190 url: '/nodes/' + nodename + '/lxc/' + vmid + '/status/current',
191 success: function(result) {
192 if (typeof callback === 'function') {
193 callback(true, result);
194 }
195 },
196 failure: function(msg) {
197 if (typeof callback === 'function') {
198 callback(false, msg);
199 }
200 }
201 });
202}
203
204function checkMigration() {
205 var apitype = type;
206 if (apitype === 'kvm') {
207 apitype = 'qemu';
208 }
209 API2Request({
210 method: 'GET',
211 params: {
212 type: 'vm'
213 },
214 url: '/cluster/resources',
215 success: function(result) {
216 // if not yet migrated , wait and try again
217 // if not migrating and stopped, cancel
218 // if started, connect
219 result.data.forEach(function(entity) {
220 if (entity.id === (apitype + '/' + vmid)) {
221 var started = entity.status === 'running';
222 var migrated = entity.node !== nodename;
223 if (migrated) {
224 if (started) {
225 // goto different node
226 location.href = '?console=' + type +
227 '&xtermjs=1&vmid=' + vmid + '&vmname=' +
228 vmname + '&node=' + entity.node;
229 } else {
230 // wait again
231 updateState(states.reconnecting, 'waiting for migration to finish...');
232 setTimeout(checkMigration, 5000);
233 }
234 } else {
235 if (type === 'lxc') {
236 // we have to check the status of the
237 // container to know if it has the
238 // migration lock
239 getLxcStatus(function(success, result) {
240 if (success) {
241 if (result.data.lock === 'migrate') {
242 // still waiting
243 updateState(states.reconnecting, 'waiting for migration to finish...');
244 setTimeout(checkMigration, 5000);
8f2ac472
DC
245 } else if (started) {
246 // container was rebooted
247 location.reload();
291e1a24
DC
248 } else {
249 stopTerminal();
250 }
251 } else {
252 // probably the status call failed because
253 // the ct is already somewhere else, so retry
254 setTimeout(checkMigration, 1000);
255 }
256 });
257 } else if (started) {
258 // this happens if we have old data in
259 // /cluster/resources, or the connection
260 // disconnected, so simply try to reload here
261 location.reload();
262 } else if (type === 'kvm') {
263 // it seems the guest simply stopped
264 stopTerminal();
265 }
266 }
267
268 return;
269 }
270 });
271 },
272 failure: function(msg) {
273 errorTerminal({msg: msg});
274 }
275 });
276}
277
278function tryReconnect() {
279 var time_since_started = new Date() - starttime;
280 var type = getQueryParameter('console');
6c7c792d 281 if (time_since_started < 5*1000 || type === 'shell' || type === 'cmd') { // 5 seconds
8c502b81 282 stopTerminal();
291e1a24 283 return;
291e1a24
DC
284 }
285
286 updateState(states.disconnecting, 'Detecting migration...');
287 setTimeout(checkMigration, 5000);
288}
289
b9bbd688
DC
290function clearEvents() {
291 term.onResize(() => {});
292 term.onData(() => {});
293}
294
dcf3d43b 295function stopTerminal(event) {
8c502b81 296 event = event || {};
b9bbd688 297 clearEvents();
dcf3d43b
DC
298 clearInterval(ping);
299 socket.close();
300 updateState(states.disconnected, event.msg + event.code);
301}
302
303function errorTerminal(event) {
8c502b81 304 even = event || {};
b9bbd688 305 clearEvents();
dcf3d43b
DC
306 clearInterval(ping);
307 socket.close();
f21a83b7 308 term.dispose();
dcf3d43b
DC
309 updateState(states.disconnected, event.msg + event.code);
310}