Skip to content

Commit

Permalink
feat(www): preliminary support for uploading to the shared storage
Browse files Browse the repository at this point in the history
Signed-off-by: Cedric Hombourger <cedric.hombourger@siemens.com>
  • Loading branch information
chombourger committed Oct 4, 2024
1 parent e8b4a47 commit 233f015
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 6 deletions.
40 changes: 40 additions & 0 deletions mtda/assets/dropzone.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* ---------------------------------------------------------------------------
Copyright (C) 2024 Siemens AG
---------------------------------------------------------------------------
SPDX-License-Identifier: MIT
---------------------------------------------------------------------------
*/

#dropzone {
width: 100%;
max-width: 600px;
height: 200px;
border: 2px dashed #888;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: #888;
font-size: 18px;
margin: 20px auto;
cursor: pointer;
}

#dropzone.hover {
border-color: #333;
color: #333;
}

button {
display: block;
margin: 20px auto;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}

button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
1 change: 1 addition & 0 deletions mtda/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class STORAGE:
ON_TARGET = "TARGET"
LOCKED = "LOCKED"
UNLOCKED = "UNLOCKED"
OPENED = "OPENED"
UNKNOWN = "???"
RETRY_INTERVAL = 0.5
TIMEOUT = 30
Expand Down
1 change: 1 addition & 0 deletions mtda/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@ def storage_open(self, session=None):
self._storage_opened = True
self._storage_owner = session
self._writer.start()
self._storage_event(CONSTS.STORAGE.OPENED, session)
if self.storage is not None:
self.storage_locked()

Expand Down
99 changes: 97 additions & 2 deletions mtda/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- Apple iOS Safari settings -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="./assets/dropzone.css">
<link rel="stylesheet" href="./assets/material_icons.css">
<link rel="stylesheet" href="./assets/modern.min.css">
<link rel="stylesheet" href="novnc/app/styles/base.css">
Expand Down Expand Up @@ -81,6 +82,7 @@
<ul class="nav">
<li><a href="#" id=power-toggle><i id=power-status-icon class="large material-icons">power</i></a></li>
<li><a href="#" id=storage-toggle><i id=storage-status-icon class="large material-icons">no_sim</i></a></li>
<li><a href="#" id=storage-write><i id=storage-write-icon class="large material-icons">upload_file</i></a></li>
<li id="mtda_status">Connecting...</li>
<li id="vnc_status">Loading Video</li>
<li id="mtda_version">&nbsp;</li>
Expand All @@ -102,6 +104,13 @@
height: "768px",
hidden: true,
});
uploadWindow = new WinBox("Upload", {
html: "<div id=dropzone>Drag and drop your file here</div><button id='upload' disabled></button>",
class: ["no-full", "no-max", "modern"],
width: "600px",
height: "340px",
hidden: true,
});
consoleWindow.focus()
</script>
<script src="./assets/jquery.min.js"></script>
Expand All @@ -116,14 +125,15 @@
shift: key.shift,
alt: key.alt,
meta: key.cmd,
session: localStorage.getItem('session')
}, function(key) {
// do nothing
});
});
$(function() {
$('a#power-toggle').bind('click', function() {
document.getElementById("power-status-icon").innerHTML = "downloading"
$.getJSON('./power-toggle', function(data) {
$.getJSON('./power-toggle', {session: localStorage.getItem('session')}, function(data) {
// do nothing
});
return false;
Expand All @@ -132,7 +142,24 @@
$(function() {
$('a#storage-toggle').bind('click', function() {
document.getElementById("storage-status-icon").innerHTML = "downloading"
$.getJSON('./storage-toggle', function(data) {
$.getJSON('./storage-toggle', {session: localStorage.getItem('session')}, function(data) {
// do nothing
});
return false;
});
});
$(function() {
$('a#storage-write').bind('click', function() {
upload.innerHTML = 'Upload File'
uploadWindow.move('center', 'center');
uploadWindow.toggleClass('modal');
uploadWindow.show();
uploadWindow.focus();
});
});
$(function() {
$('#upload').bind('click', function() {
$.getJSON('./storage-open', {session: localStorage.getItem('session')}, function(data) {
// do nothing
});
return false;
Expand Down Expand Up @@ -207,6 +234,10 @@
status.innerHTML = '<span style="color: #ff8383;"><b>Disconnected</b></span>';
});

socket.on("session", (data) => {
localStorage.setItem('session', data.id);
});

socket.on("power-event", (data) => {
switch(data.event) {
case 'ON': power_status.innerHTML = "power_off"; break;
Expand Down Expand Up @@ -235,11 +266,75 @@
storage_status.innerHTML = "no_sim";
storage_status.title = data
break;
case 'OPENED':
if (localStorage.getItem('session') == data) {
if (selectedFile) {
upload.innerHTML = 'Uploading...'
uploadSelectedFile();
}
}
break;
default:
storage_status.innerHTML = "unknown_document"
storage_status.title = "storage status unknown"
}
});
const CHUNK_SIZE = 512 * 1024;
const dropzone = document.getElementById('dropzone');
const upload = document.getElementById('upload');
let selectedFile = null;

['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, (e) => e.preventDefault());
});

['dragenter', 'dragover'].forEach(eventName => {
dropzone.addEventListener(eventName, () => dropzone.classList.add('hover'));
});

['dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, () => dropzone.classList.remove('hover'));
});

dropzone.addEventListener('drop', (event) => {
const files = event.dataTransfer.files;
if (files.length) {
selectedFile = files[0];
dropzone.textContent = `${selectedFile.name}`;
upload.disabled = false;
}
});

function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

async function uploadSelectedFile() {
const sendFileInChunks = (file) => {
let offset = 0;
const reader = new FileReader();

const readNextChunk = () => {
const slice = file.slice(offset, offset + CHUNK_SIZE);
reader.readAsArrayBuffer(slice);
};

reader.onload = async (event) => {
socket.emit("storage-write", { data: event.target.result });
offset += CHUNK_SIZE;
await delay(10);

if (offset < file.size) {
readNextChunk();
} else {
socket.emit("storage-close", { });
uploadWindow.hide();
}
};
readNextChunk();
};
await sendFileInChunks(selectedFile);
};
</script>
</body>
</html>
40 changes: 36 additions & 4 deletions mtda/www.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,18 @@ def connect():
session['id'] = uuid.uuid4().hex
mtda = app.config['mtda']
if mtda is not None:
socket.emit("session", {"id": session['id']}, namespace="/mtda")

version = mtda.agent_version()
socket.emit("mtda-version", {"version": version}, namespace="/mtda")

data = mtda.console_dump()
socket.emit("console-output", {"output": data}, namespace="/mtda")

power = mtda.target_status(session_id())
power = mtda.target_status(session['id'])
socket.emit("power-event", {"event": power}, namespace="/mtda")

status, _, _ = mtda.storage_status(session_id())
status, _, _ = mtda.storage_status(session['id'])
socket.emit("storage-event", {"event": status}, namespace="/mtda")

if mtda.video is not None:
Expand Down Expand Up @@ -116,7 +118,7 @@ def keyboard_input():

@app.route('/power-toggle')
def power_toggle():
sid = session_id()
sid = request.args.get('session')
mtda = app.config['mtda']
if mtda is not None:
return mtda.target_toggle(session=sid)
Expand All @@ -125,7 +127,7 @@ def power_toggle():

@app.route('/storage-toggle')
def storage_toggle():
sid = session_id()
sid = request.args.get('session')
mtda = app.config['mtda']
if mtda is not None:
status, _, _ = mtda.storage_status(session=sid)
Expand All @@ -137,8 +139,38 @@ def storage_toggle():
return ''


@app.route('/storage-open')
def storage_open():
sid = request.args.get('session')
mtda = app.config['mtda']
if mtda is not None:
mtda.storage_open(session=sid)
return ''


@socket.on("storage-close", namespace="/mtda")
def storage_open(data):
sid = request.args.get('session')
mtda = app.config['mtda']
if mtda is not None:
mtda.storage_close(sid)
mtda.storage_to_target(sid)
return ''


@socket.on("storage-write", namespace="/mtda")
def storage_write(data):
sid = session_id()
mtda = app.config['mtda']
if mtda is not None:
data = data['data']
mtda.storage_write(data, sid)
return ''


def session_id():
sid = None
mtda = app.config['mtda']
if 'id' in session:
sid = session['id']
return sid
Expand Down

0 comments on commit 233f015

Please sign in to comment.