11 var callPackagelist
= rpc
.declare({
13 method
: 'packagelist',
16 var callSystemBoard
= rpc
.declare({
21 var callUpgradeStart
= rpc
.declare({
23 method
: 'upgrade_start',
27 function get_branch(version
) {
28 // determine branch of a version
29 // SNAPSHOT -> SNAPSHOT
30 // 21.02-SNAPSHOT -> 21.02
31 // 21.02.0-rc1 -> 21.02
33 return version
.replace('-SNAPSHOT', '').split('.').slice(0, 2).join('.');
36 function get_revision_count(revision
) {
37 return parseInt(revision
.substring(1).split('-')[0]);
40 function error_api_connect(response
) {
41 ui
.showModal(_('Error connecting to upgrade server'), [
43 _('Could not reach API at "%s". Please try again later.')
44 .format(response
.url
)),
45 E('pre', {}, response
.responseText
),
59 function install_sysupgrade(url
, keep
, sha256
) {
60 displayStatus('notice spinning',
61 E('p', _('Downloading firmware from server to browser')));
65 'Content-Type': 'application/x-www-form-urlencoded',
70 var form_data
= new FormData();
71 form_data
.append('sessionid', rpc
.getSessionID());
72 form_data
.append('filename', '/tmp/firmware.bin');
73 form_data
.append('filemode', 600);
74 form_data
.append('filedata', response
.blob());
76 displayStatus('notice spinning',
77 E('p', _('Uploading firmware from browser to device')));
79 .get(`${L.env.cgi_base}/cgi-upload`, {
83 .then((response
) => response
.json())
85 if (response
.sha256sum
!= sha256
) {
86 displayStatus('warning', [
87 E('b', _('Wrong checksum')),
89 _('Error during download of firmware. Please try again')),
100 _('Installing the sysupgrade. Do not unpower device!')));
101 L
.resolveDefault(callUpgradeStart(keep
), {})
102 .then((response
) => {
104 ui
.awaitReconnect(window
.location
.host
);
106 ui
.awaitReconnect('192.168.1.1', 'openwrt.lan');
114 function request_sysupgrade(server_url
, data
) {
117 if (data
.request_hash
) {
118 req
= request
.get(`${server_url}/api/v1/build/${data.request_hash}`);
120 req
= request
.post(`${server_url}/api/v1/build`, {
121 profile
: data
.board_name
,
123 version
: data
.version
,
124 packages
: data
.packages
,
129 req
.then((response
) => {
130 switch (response
.status
) {
132 res
= response
.json();
134 for (image
of res
.images
) {
135 if (image
.type
== 'sysupgrade') {
139 if (image
.name
!= undefined) {
140 var sysupgrade_url
= `${server_url}/store/${res.bin_dir}/${image.name}`;
142 var keep
= E('input', {
149 `${res.version_number} ${res.version_code}`,
152 href
: sysupgrade_url
,
163 var table
= E('div', {
167 for (var i
= 0; i
< fields
.length
; i
+= 2) {
168 table
.appendChild(E('tr', {
186 E('p', {class: 'mt-2'},
192 _('Keep settings and retain the current configuration')
205 class: 'btn cbi-button-action',
207 install_sysupgrade(sysupgrade_url
, keep
.checked
,
211 _('Install Sysupgrade')),
215 ui
.showModal(_('Successfully created sysupgrade image'), modal_body
);
220 res
= response
.json();
221 data
.request_hash
= res
.request_hash
;
223 if ('queue_position' in res
)
224 displayStatus('notice spinning',
225 E('p', _('Request in build queue position %s')
226 .format(res
.queue_position
)));
228 displayStatus('notice spinning',
229 E('p', _('Building firmware sysupgrade image')));
231 setTimeout(function() { request_sysupgrade(server_url
, data
); }, 5000);
233 case 400: // bad request
234 case 422: // bad package
235 case 500: // build failed
236 res
= response
.json();
238 E('p', {}, res
.detail
),
239 E('p', {}, _('Please report the error message and request')),
240 E('b', {}, _('Request to server:')),
241 E('pre', {}, JSON
.stringify(data
, null, 4)),
245 body
.push(E('b', {}, 'STDOUT:'));
246 body
.push(E('pre', {}, res
.stdout
));
250 body
.push(E('b', {}, 'STDERR:'));
251 body
.push(E('pre', {}, res
.stderr
));
266 ui
.showModal(_('Error building the sysupgrade'), body
);
272 async
function check_sysupgrade(server_url
, system_board
, packages
) {
273 var {board_name
} = system_board
;
274 var {target
, version
, revision
} = system_board
.release
;
275 var current_branch
= get_branch(version
);
277 uci
.get_first('attendedsysupgrade', 'client', 'advanced_mode') || 0;
281 displayStatus('notice spinning',
282 E('p', _('Searching for an available sysupgrade of %s - %s')
283 .format(version
, revision
)));
285 if (version
.endsWith('SNAPSHOT')) {
287 await request
.get(`${server_url}/api/v1/revision/${version}/${target}`);
289 error_api_connect(response
);
293 const remote_revision
= response
.json().revision
;
295 if (get_revision_count(revision
) < get_revision_count(remote_revision
)) {
296 candidates
.push(version
);
299 response
= await request
.get(`${server_url}/api/overview`, {
304 error_api_connect(response
);
308 const latest
= response
.json().latest
;
310 for (let remote_version
of latest
) {
311 var remote_branch
= get_branch(remote_version
);
313 // already latest version installed
314 if (version
== remote_version
) {
318 // skip branch upgrades outside the advanced mode
319 if (current_branch
!= remote_branch
&& advanced_mode
== 0) {
323 candidates
.unshift(remote_version
);
325 // don't offer branches older than the current
326 if (current_branch
== remote_branch
) {
332 if (candidates
.length
) {
337 board_name
: board_name
,
339 version
: candidates
[0],
340 packages
: Object
.keys(packages
).sort(),
344 m
= new form
.JSONMap(mapdata
, '');
346 s
= m
.section(form
.NamedSection
, 'request', 'example', '',
347 'Use defaults for the safest update');
348 o
= s
.option(form
.ListValue
, 'version', 'Select firmware version');
349 for (let candidate
of candidates
) {
350 o
.value(candidate
, candidate
);
353 if (advanced_mode
== 1) {
354 o
= s
.option(form
.Value
, 'board_name', 'Board Name / Profile');
355 o
= s
.option(form
.DynamicList
, 'packages', 'Packages');
358 m
.render().then(function(form_rendered
) {
359 ui
.showModal(_('New upgrade available'), [
372 class: 'btn cbi-button-action',
374 m
.save().then((foo
) => {
375 request_sysupgrade(server_url
, mapdata
.request
);
379 _('Request Sysupgrade')),
384 ui
.showModal(_('No upgrade available'), [
386 _('The device runs the latest firmware version %s - %s')
387 .format(version
, revision
)),
402 function displayStatus(type
, content
) {
404 var message
= ui
.showModal('', '');
406 message
.classList
.add('alert-message');
407 DOMTokenList
.prototype.add
.apply(message
.classList
, type
.split(/\s+/));
410 dom
.content(message
, content
);
419 L
.resolveDefault(callPackagelist(), {}),
420 L
.resolveDefault(callSystemBoard(), {}),
421 uci
.load('attendedsysupgrade'),
424 render: function(res
) {
425 var packages
= res
[0].packages
;
426 var system_board
= res
[1];
428 uci
.get_first('attendedsysupgrade', 'client', 'auto_search') || 1;
429 var server_url
= uci
.get_first('attendedsysupgrade', 'server', 'url');
432 E('h2', _('Attended Sysupgrade')),
434 _('The attended sysupgrade service allows to easily upgrade vanilla and custom firmware images.')),
436 _('This is done by building a new firmware on demand via an online service.')),
439 if (auto_search
== 1) {
440 check_sysupgrade(server_url
, system_board
, packages
);
444 class: 'btn cbi-button-positive',
446 function() { check_sysupgrade(server_url
, system_board
, packages
); },
448 _('Search for sysupgrade')));