diff options
Diffstat (limited to 'web/share/js/kvm/msd.js')
-rw-r--r-- | web/share/js/kvm/msd.js | 472 |
1 files changed, 254 insertions, 218 deletions
diff --git a/web/share/js/kvm/msd.js b/web/share/js/kvm/msd.js index 3885bd50..3a558b00 100644 --- a/web/share/js/kvm/msd.js +++ b/web/share/js/kvm/msd.js @@ -35,10 +35,6 @@ export function Msd() { var __state = null; var __http = null; - var __parts_names_json = ""; - var __parts_names_len = 0; - var __parts = {}; - var __init__ = function() { $("msd-led").title = "Unknown state"; @@ -68,8 +64,206 @@ export function Msd() { /************************************************************************/ self.setState = function(state) { - __state = state; - __applyState(); + if (state) { + if (!__state) { + __state = {}; + __state.storage = {}; + } + if (state.enabled !== undefined) { + tools.feature.setEnabled($("msd-dropdown"), state.enabled); + __state.enabled = state.enabled; + } + if (__state.enabled !== undefined) { + if (state.online !== undefined) { + __state.online = state.online; + } + if (state.busy !== undefined) { + __state.busy = state.busy; + } + if (state.drive !== undefined || (state.storage && state.storage.images !== undefined)) { + let drive = (state.drive !== undefined ? state.drive : __state.drive); + let images = ( + state.storage && state.storage.images !== undefined + ? state.storage.images + : __state.storage && __state.storage.images !== undefined + ? __state.storage.images + : null + ); + if (drive && images) { + __updateImageSelector(drive, images); + } + __state.drive = drive; + __state.storage.images = images; + } + if (state.storage && state.storage.parts !== undefined) { + __updateParts(state.storage.parts); + __state.storage.parts = state.storage.parts; + } + if (state.storage && state.storage.uploading !== undefined) { + __updateUploading(state.storage.uploading); + __state.storage.uploading = state.storage.uploading; + } + if (state.storage && state.storage.downloading !== undefined) { + __state.storage.downloading = state.storage.downloading; + } + } + } else { + __state = null; + } + __refreshControls(); + }; + + var __refreshControls = function() { + __updateControls(__state && (__state.online !== undefined) ? __state : null); + }; + + var __updateControls = function(state) { + let o = (state && state.online); + let d = (state ? state.drive : null); + let s = (state ? state.storage : null); + let busy = !!(state && state.busy); + + tools.hidden.setVisible($("msd-message-offline"), (state && !state.online)); + tools.hidden.setVisible($("msd-message-image-broken"), (o && d.image && !d.image.complete && !s.uploading)); + tools.hidden.setVisible($("msd-message-too-big-for-cdrom"), (o && d.cdrom && d.image && d.image.size >= 2359296000)); + tools.hidden.setVisible($("msd-message-out-of-storage"), (o && d.image && !d.image.in_storage)); + tools.hidden.setVisible($("msd-message-rw-enabled"), (o && d.rw)); + tools.hidden.setVisible($("msd-message-another-user-uploads"), (o && s.uploading && !__http)); + tools.hidden.setVisible($("msd-message-downloads"), (o && s.downloading)); + + tools.el.setEnabled($("msd-image-selector"), (o && !d.connected && !busy)); + tools.el.setEnabled($("msd-download-button"), (o && d.image && !d.connected && !busy)); + tools.el.setEnabled($("msd-remove-button"), (o && d.image && d.image.removable && !d.connected && !busy)); + + tools.radio.setEnabled("msd-mode-radio", (o && !d.connected && !busy)); + tools.radio.setValue("msd-mode-radio", `${Number(o && d.cdrom)}`); + + tools.el.setEnabled($("msd-rw-switch"), (o && !d.connected && !busy)); + $("msd-rw-switch").checked = (o && d.rw); + + tools.el.setEnabled($("msd-connect-button"), (o && d.image && !d.connected && !busy)); + tools.el.setEnabled($("msd-disconnect-button"), (o && d.connected && !busy)); + + tools.el.setEnabled($("msd-select-new-button"), (o && !d.connected && !__http && !busy)); + tools.el.setEnabled($("msd-upload-new-button"), + (o && !d.connected && (tools.input.getFile($("msd-new-file")) || $("msd-new-url").value.length > 0) && !busy)); + tools.el.setEnabled($("msd-abort-new-button"), (o && __http)); + + tools.el.setEnabled($("msd-reset-button"), (state && state.enabled && !busy)); + + tools.el.setEnabled($("msd-new-file"), (o && !d.connected && !__http && !busy)); + tools.el.setEnabled($("msd-new-url"), (o && !d.connected && !__http && !busy)); + tools.el.setEnabled($("msd-new-part-selector"), (o && !d.connected && !__http && !busy)); + + if (o && s.uploading) { + tools.hidden.setVisible($("msd-new-sub"), false); + $("msd-new-file").value = ""; + $("msd-new-url").value = ""; + } + tools.hidden.setVisible($("msd-uploading-sub"), (o && s.uploading)); + tools.hidden.setVisible($("msd-new-tips"), (o && s.uploading && __http)); + + let led_cls = "led-gray"; + let msg = "Unavailable"; + if (o && d.connected) { + led_cls = "led-green"; + msg = "Connected to Server"; + } else if (o && s.uploading) { + led_cls = "led-yellow-rotating-fast"; + msg = "Uploading new image"; + } else if (o && s.downloading) { + led_cls = "led-yellow-rotating-fast"; + msg = "Serving the image to download"; + } else if (o) { // Sic! + msg = "Disconnected"; + } + $("msd-led").className = led_cls; + $("msd-status").innerText = $("msd-led").title = msg; + }; + + var __updateUploading = function(uploading) { + $("msd-uploading-name").innerText = (uploading ? uploading.name : ""); + $("msd-uploading-size").innerText = (uploading ? tools.formatSize(uploading.size) : ""); + if (uploading) { + tools.progress.setPercentOf($("msd-uploading-progress"), uploading.size, uploading.written); + } + }; + + var __updateParts = function(parts) { + let names = Object.keys(parts).sort(); + { + let writable = names.filter(name => (name === "" || parts[name].writable)); + let writable_json = JSON.stringify(writable); + let el = $("msd-new-part-selector"); + if (el.__writable_json !== writable_json) { + let sel = (el.value || ""); + el.options.length = 0; + for (let name of writable) { + let title = (name || "\u2500 Internal \u2500"); + tools.selector.addOption(el, title, name, (name === sel)); + } + tools.hidden.setVisible($("msd-new-part"), (writable.length > 1)); + el.__writable_json = writable_json; + } + } + { + let names_json = JSON.stringify(names); + let el = $("msd-storages"); + if (el.__names_json !== names_json) { + el.innerHTML = names.map(name => ` + <div class="text"> + <div id="__msd-storage-${tools.makeIdByText(name)}-progress" class="progress"> + <span class="progress-value"></span> + </div> + </div> + `).join("<hr>"); + el.__names_json = names_json; + } + } + for (let name of names) { + let part = parts[name]; + let title = ( + name === "" + ? `${names.length === 1 ? "Storage: %s" : "Internal storage: %s"}` // eslint-disable-line + : `Storage [${name}${part.writable ? "]" : ", read-only]"}: %s` // eslint-disable-line + ); + let id = `__msd-storage-${tools.makeIdByText(name)}-progress`; + tools.progress.setSizeOf($(id), title, part.size, part.free); + } + }; + + var __updateImageSelector = function(drive, images) { + let sel = ""; + let el = $("msd-image-selector"); + el.options.length = 1; + for (let name of Object.keys(images).sort()) { + tools.selector.addSeparator(el); + tools.selector.addOption(el, name, name); + tools.selector.addComment(el, __makeImageSelectorInfo(images[name])); + if (drive.image && drive.image.name === name && drive.image.in_storage) { + sel = name; + } + } + if (drive.image && !drive.image.in_storage) { + sel = ".__external__"; // Just some magic name + tools.selector.addOption(el, drive.image.name, sel); + tools.selector.addComment(el, __makeImageSelectorInfo(drive.image)); + } + el.value = sel; + }; + + var __makeImageSelectorInfo = function(image) { + let text = `\xA0\xA0\xA0\xA0\xA0\u2570 ${tools.formatSize(image.size)}`; + if (!image.complete) { + text += ", broken"; + } + if (image.in_storage !== undefined && !image.in_storage) { + text += ", out of storage"; + } + let ts = new Date(image.mod_ts * 1000); + ts = new Date(ts.getTime() - (ts.getTimezoneOffset() * 60000)); + ts = ts.toISOString().slice(0, -8).replaceAll("-", ".").replace("T", "-"); + return `${text} \u2500 ${ts}`; }; var __selectImage = function() { @@ -80,8 +274,8 @@ export function Msd() { }; var __clickDownloadButton = function() { - let name = $("msd-image-selector").value; - window.open(`/api/msd/read?image=${name}`); + let image = encodeURIComponent($("msd-image-selector").value); + window.open(`/api/msd/read?image=${image}`); }; var __clickRemoveButton = function() { @@ -102,6 +296,7 @@ export function Msd() { if (http.status !== 200) { wm.error("Can't configure Mass Storage", http.responseText); } + __refreshControls(); }); }; @@ -110,60 +305,63 @@ export function Msd() { __http = new XMLHttpRequest(); let prefix = encodeURIComponent($("msd-new-part-selector").value); if (file) { - __http.open("POST", `/api/msd/write?prefix=${prefix}&image=${encodeURIComponent(file.name)}&remove_incomplete=1`, true); + let image = encodeURIComponent(file.name); + __http.open("POST", `/api/msd/write?prefix=${prefix}&image=${image}&remove_incomplete=1`, true); } else { - let url = $("msd-new-url").value; - __http.open("POST", `/api/msd/write_remote?prefix=${prefix}&url=${encodeURIComponent(url)}&remove_incomplete=1`, true); + let url = encodeURIComponent($("msd-new-url").value); + __http.open("POST", `/api/msd/write_remote?prefix=${prefix}&url=${url}&remove_incomplete=1`, true); } __http.upload.timeout = 7 * 24 * 3600; - __http.onreadystatechange = __httpStateChange; + __http.onreadystatechange = __uploadStateChange; __http.send(file); - __applyState(); + __refreshControls(); }; - var __httpStateChange = function() { - if (__http.readyState === 4) { - if (__http.status !== 200) { - wm.error("Can't upload image", __http.responseText); - } else if ($("msd-new-url").value.length > 0) { - let html = ""; - let msg = ""; - try { - let end = __http.responseText.lastIndexOf("\r\n"); - if (end < 0) { - end = __http.responseText.length; - } - let begin = __http.responseText.lastIndexOf("\r\n", end - 2); - if (begin < 0) { - end = 0; - } - let result_str = __http.responseText.slice(begin, end); - let result = JSON.parse(result_str); - if (!result.ok) { - html = "Can't upload image"; - msg = result_str; - } - } catch (ex) { - html = "Can't parse upload result"; - msg = `${ex}`; + var __uploadStateChange = function() { + if (__http.readyState !== 4) { + return; + } + if (__http.status !== 200) { + wm.error("Can't upload image", __http.responseText); + } else if ($("msd-new-url").value.length > 0) { + let html = ""; + let msg = ""; + try { + let end = __http.responseText.lastIndexOf("\r\n"); + if (end < 0) { + end = __http.responseText.length; } - if (html.length > 0) { - wm.error(html, msg); + let begin = __http.responseText.lastIndexOf("\r\n", end - 2); + if (begin < 0) { + end = 0; } + let result_str = __http.responseText.slice(begin, end); + let result = JSON.parse(result_str); + if (!result.ok) { + html = "Can't upload image"; + msg = result_str; + } + } catch (ex) { + html = "Can't parse upload result"; + msg = `${ex}`; + } + if (html.length > 0) { + wm.error(html, msg); } - tools.hidden.setVisible($("msd-new-sub"), false); - $("msd-new-file").value = ""; - $("msd-new-url").value = ""; - __http = null; - __applyState(); } + tools.hidden.setVisible($("msd-new-sub"), false); + $("msd-new-file").value = ""; + $("msd-new-url").value = ""; + __http = null; + __refreshControls(); }; var __clickAbortNewButton = function() { __http.onreadystatechange = null; __http.abort(); __http = null; - tools.progress.setValue($("msd-uploading-progress"), "Aborted", 0); + __refreshControls(); + tools.hidden.setVisible($("msd-new-sub"), true); }; var __clickConnectButton = function(connected) { @@ -171,9 +369,9 @@ export function Msd() { if (http.status !== 200) { wm.error("Can't switch Mass Storage", http.responseText); } - __applyState(); + __refreshControls(); }); - __applyState(); + __refreshControls(); tools.el.setEnabled($(`msd-${connected ? "connect" : "disconnect"}-button`), false); }; @@ -184,9 +382,7 @@ export function Msd() { if (http.status !== 200) { wm.error("Mass Storage reset error", http.responseText); } - __applyState(); }); - __applyState(); } }); }; @@ -194,193 +390,33 @@ export function Msd() { var __toggleSelectSub = function() { let el_sub = $("msd-new-sub"); let visible = tools.hidden.isVisible(el_sub); + tools.hidden.setVisible(el_sub, !visible); if (visible) { $("msd-new-file").value = ""; $("msd-new-url").value = ""; } - tools.hidden.setVisible(el_sub, !visible); - __applyState(); + __refreshControls(); }; var __selectNewFile = function() { - let el_input = $("msd-new-file"); - let file = tools.input.getFile($("msd-new-file")); + let el = $("msd-new-file"); + let file = tools.input.getFile(el); if (file) { $("msd-new-url").value = ""; let part = __state.storage.parts[$("msd-new-part-selector").value]; if (file.size > part.size) { - wm.error(`New image is too big for the Mass Storage partition.<br>Maximum: ${tools.formatSize(part.size)}`); - el_input.value = ""; + wm.error(`The new image is too big for the Mass Storage partition.<br>Maximum: ${tools.formatSize(part.size)}`); + el.value = ""; } } - __applyState(); + __refreshControls(); }; var __selectNewUrl = function() { if ($("msd-new-url").value.length > 0) { $("msd-new-file").value = ""; } - __applyState(); - }; - - var __applyState = function() { - __applyStateStatus(); - - let s = __state; - let online = (s && s.online); - - if (s) { - tools.feature.setEnabled($("msd-dropdown"), s.enabled); - tools.feature.setEnabled($("msd-reset-button"), s.enabled); - } - tools.hidden.setVisible($("msd-message-offline"), (s && !s.online)); - tools.hidden.setVisible($("msd-message-image-broken"), (online && s.drive.image && !s.drive.image.complete && !s.storage.uploading)); - tools.hidden.setVisible($("msd-message-too-big-for-cdrom"), (online && s.drive.cdrom && s.drive.image && s.drive.image.size >= 2359296000)); - tools.hidden.setVisible($("msd-message-out-of-storage"), (online && s.drive.image && !s.drive.image.in_storage)); - tools.hidden.setVisible($("msd-message-rw-enabled"), (online && s.drive.rw)); - tools.hidden.setVisible($("msd-message-another-user-uploads"), (online && s.storage.uploading && !__http)); - tools.hidden.setVisible($("msd-message-downloads"), (online && s.storage.downloading)); - - if (online) { - let names = Object.keys(s.storage.parts).sort(); - let parts_names_json = JSON.stringify(names); - if (__parts_names_json !== parts_names_json) { - $("msd-storages").innerHTML = names.map(name => ` - <div class="text"> - <div id="msd-storage-${tools.makeIdByText(name)}-progress" class="progress"> - <span class="progress-value"></span> - </div> - </div> - `).join("<hr>"); - __parts_names_json = parts_names_json; - __parts_names_len = names.length; - } - __parts = s.storage.parts; - } - for (let name in __parts) { - let part = __parts[name]; - let title = ( - name.length === 0 - ? `${__parts_names_len === 1 ? "Storage: %s" : "Internal storage: %s"}` // eslint-disable-line - : `Storage [${name}${part.writable ? "]" : ", read-only]"}: %s` // eslint-disable-line - ); - let id = `msd-storage-${tools.makeIdByText(name)}-progress`; - if (online) { - tools.progress.setSizeOf($(id), title, part.size, part.free); - } else { - tools.progress.setValue($(id), title.replace("%s", "unavailable"), 0); - } - } - - tools.el.setEnabled($("msd-image-selector"), (online && !s.drive.connected && !s.busy)); - __applyStateImageSelector(); - tools.el.setEnabled($("msd-download-button"), (online && s.drive.image && !s.drive.connected && !s.busy)); - tools.el.setEnabled($("msd-remove-button"), (online && s.drive.image && s.drive.image.removable && !s.drive.connected && !s.busy)); - - tools.radio.setEnabled("msd-mode-radio", (online && !s.drive.connected && !s.busy)); - tools.radio.setValue("msd-mode-radio", `${Number(online && s.drive.cdrom)}`); - - tools.el.setEnabled($("msd-rw-switch"), (online && !s.drive.connected && !s.busy)); - $("msd-rw-switch").checked = (online && s.drive.rw); - - tools.el.setEnabled($("msd-connect-button"), (online && s.drive.image && !s.drive.connected && !s.busy)); - tools.el.setEnabled($("msd-disconnect-button"), (online && s.drive.connected && !s.busy)); - - tools.el.setEnabled($("msd-select-new-button"), (online && !s.drive.connected && !__http && !s.busy)); - tools.el.setEnabled($("msd-upload-new-button"), - (online && !s.drive.connected && (tools.input.getFile($("msd-new-file")) || $("msd-new-url").value.length > 0) && !s.busy)); - tools.el.setEnabled($("msd-abort-new-button"), (online && __http)); - - tools.el.setEnabled($("msd-reset-button"), (s && s.enabled && !s.busy)); - - tools.el.setEnabled($("msd-new-file"), (online && !s.drive.connected && !__http && !s.busy)); - tools.el.setEnabled($("msd-new-url"), (online && !s.drive.connected && !__http && !s.busy)); - tools.el.setEnabled($("msd-new-part-selector"), (online && !s.drive.connected && !__http && !s.busy)); - if (online && !s.storage.uploading && !s.storage.downloading) { - let parts = Object.keys(s.storage.parts).sort().filter(name => (name === "" || s.storage.parts[name].writable)); - tools.selector.setValues($("msd-new-part-selector"), parts, "\u2500 Internal \u2500"); - tools.hidden.setVisible($("msd-new-part"), (parts.length > 1)); - } - - tools.hidden.setVisible($("msd-uploading-sub"), (online && s.storage.uploading)); - $("msd-uploading-name").innerHTML = ((online && s.storage.uploading) ? s.storage.uploading.name : ""); - $("msd-uploading-size").innerHTML = ((online && s.storage.uploading) ? tools.formatSize(s.storage.uploading.size) : ""); - if (online) { - if (s.storage.uploading) { - tools.progress.setPercentOf($("msd-uploading-progress"), s.storage.uploading.size, s.storage.uploading.written); - } else if (!__http) { - tools.progress.setValue($("msd-uploading-progress"), "Waiting for upload (press UPLOAD button) ...", 0); - } - } else { - $("msd-new-file").value = ""; - $("msd-new-url").value = ""; - tools.progress.setValue($("msd-uploading-progress"), "", 0); - } - }; - - var __applyStateStatus = function() { - let s = __state; - let online = (s && s.online); - - let led_cls = "led-gray"; - let msg = "Unavailable"; - - if (online && s.drive.connected) { - led_cls = "led-green"; - msg = "Connected to Server"; - } else if (online && s.storage.uploading) { - led_cls = "led-yellow-rotating-fast"; - msg = "Uploading new image"; - } else if (online && s.storage.downloading) { - led_cls = "led-yellow-rotating-fast"; - msg = "Serving the image to download"; - } else if (online) { // Sic! - msg = "Disconnected"; - } - - $("msd-led").className = led_cls; - $("msd-status").innerHTML = $("msd-led").title = msg; - }; - - var __applyStateImageSelector = function() { - let s = __state; - if (!(s && s.online) || s.storage.uploading || s.storage.downloading) { - return; - } - - let el = $("msd-image-selector"); - el.options.length = 1; - - let selected = ""; - - for (let name of Object.keys(s.storage.images).sort()) { - tools.selector.addSeparator(el); - tools.selector.addOption(el, name, name); - tools.selector.addComment(el, __makeImageSelectorInfo(s.storage.images[name])); - if (s.drive.image && s.drive.image.name === name && s.drive.image.in_storage) { - selected = name; - } - } - - if (s.drive.image && !s.drive.image.in_storage) { - selected = ".__external"; - tools.selector.addOption(el, s.drive.image.name, selected); - tools.selector.addComment(el, __makeImageSelectorInfo(s.drive.image)); - } - - el.value = selected; - }; - - var __makeImageSelectorInfo = function(image) { - let info = `\xA0\xA0\xA0\xA0\xA0\u2570 ${tools.formatSize(image.size)}`; - info += (image.complete ? "" : ", broken"); - if (image.in_storage !== undefined && !image.in_storage) { - info += ", out of storage"; - } - let dt = new Date(image.mod_ts * 1000); - dt = new Date(dt.getTime() - (dt.getTimezoneOffset() * 60000)); - info += " \u2500 " + dt.toISOString().slice(0, -8).replaceAll("-", ".").replace("T", "-"); - return info; + __refreshControls(); }; __init__(); |