Notifications
This commit is contained in:
parent
24890e9a4c
commit
ca973c4114
@ -1,12 +1,20 @@
|
|||||||
import { WebSocketServer } from "ws";
|
import { WebSocketServer } from "ws";
|
||||||
import child_process from "child_process";
|
import child_process from "child_process";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
import { send_notification } from "./notifications.mjs"
|
||||||
|
|
||||||
async function spawnPromise(program, args) {
|
async function spawnPromise(program, args) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
let output = "";
|
||||||
const process = child_process.spawn(program, args);
|
const process = child_process.spawn(program, args);
|
||||||
process.on("close", (_) => {
|
process.stdout.on('data', (data) => {
|
||||||
resolve();
|
output += data;
|
||||||
|
});
|
||||||
|
process.stderr.on('data', (data) => {
|
||||||
|
output += data;
|
||||||
|
});
|
||||||
|
process.on("close", (code) => {
|
||||||
|
resolve({output, code});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -32,7 +40,8 @@ wss.on("connection", (ws) => {
|
|||||||
} else if (data === "home") {
|
} else if (data === "home") {
|
||||||
await spawnPromise("bash", ["/conf/home.sh"]);
|
await spawnPromise("bash", ["/conf/home.sh"]);
|
||||||
} else if (data === "install") {
|
} else if (data === "install") {
|
||||||
await spawnPromise("bash", ["/conf/install.sh"]);
|
const res = await spawnPromise("bash", ["/conf/install.sh"]);
|
||||||
|
send_notification(res.code === 0, "Installing the application", res.output);
|
||||||
} else if (data.includes("drag")) {
|
} else if (data.includes("drag")) {
|
||||||
const dataSplit = data.split(" ");
|
const dataSplit = data.split(" ");
|
||||||
|
|
||||||
|
36
android/code/notifications.mjs
Normal file
36
android/code/notifications.mjs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { WebSocket } from "ws";
|
||||||
|
import { WebSocketServer } from "ws";
|
||||||
|
|
||||||
|
const notification_proxy = new WebSocketServer({ port: 3001 });
|
||||||
|
let notification_subs = [];
|
||||||
|
|
||||||
|
notification_proxy.on('connection', (ws) => {
|
||||||
|
notification_subs.push(ws);
|
||||||
|
});
|
||||||
|
|
||||||
|
export function send_notification(is_ok, context, message)
|
||||||
|
{
|
||||||
|
let updated_subs = [];
|
||||||
|
|
||||||
|
if (notification_subs.length === 0) {
|
||||||
|
console.log("WARNING: Got a notification, but nobody is subscribed");
|
||||||
|
}
|
||||||
|
for (const sub of notification_subs) {
|
||||||
|
if (sub.readyState == WebSocket.CONNECTING) {
|
||||||
|
console.log("WARNING: Unable to forward a notification to client that is still connecting");
|
||||||
|
updated_subs.push(sub);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
sub.send(JSON.stringify({
|
||||||
|
is_ok,
|
||||||
|
context,
|
||||||
|
message
|
||||||
|
}));
|
||||||
|
updated_subs.push(sub);
|
||||||
|
} catch {
|
||||||
|
sub.close();
|
||||||
|
console.log("WARNING: Fail to send a notification, closing the connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ services:
|
|||||||
- 45457:45459 # This cannot change
|
- 45457:45459 # This cannot change
|
||||||
- 10001:10001 # api port
|
- 10001:10001 # api port
|
||||||
- 3000:3000 # android server port
|
- 3000:3000 # android server port
|
||||||
|
- 3001:3001 # Notifications server
|
||||||
volumes:
|
volumes:
|
||||||
- $PWD/shared_buffer:/shared_buffer
|
- $PWD/shared_buffer:/shared_buffer
|
||||||
- $PWD/android/conf:/conf
|
- $PWD/android/conf:/conf
|
||||||
|
@ -128,10 +128,16 @@
|
|||||||
#upload_form button:hover, #upload_form label:hover {
|
#upload_form button:hover, #upload_form label:hover {
|
||||||
background-color: #ddd;
|
background-color: #ddd;
|
||||||
}
|
}
|
||||||
|
#notifications {
|
||||||
|
width: 40%;
|
||||||
|
margin-left: 60%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="resp"></div>
|
<div id="notifications"></div>
|
||||||
|
<div id="resp" style="display: none;"></div>
|
||||||
<main>
|
<main>
|
||||||
<section class="screen-section" >
|
<section class="screen-section" >
|
||||||
<img
|
<img
|
||||||
@ -316,5 +322,6 @@
|
|||||||
screenshot_loop();
|
screenshot_loop();
|
||||||
</script>
|
</script>
|
||||||
<script src="/trafficLog.js"></script>
|
<script src="/trafficLog.js"></script>
|
||||||
|
<script src="/notifications.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -16,6 +16,8 @@ const device_size_y = 640;
|
|||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.urlencoded({ extended: false }));
|
app.use(express.urlencoded({ extended: false }));
|
||||||
|
|
||||||
|
app.use(express.static('/code/dist'))
|
||||||
|
|
||||||
console.log("Waiting for full boot...");
|
console.log("Waiting for full boot...");
|
||||||
await waitFullBoot();
|
await waitFullBoot();
|
||||||
console.log("Boot detected! activating endpoints");
|
console.log("Boot detected! activating endpoints");
|
||||||
@ -25,10 +27,6 @@ app.get("/favicon.ico", function (req, res) {
|
|||||||
res.sendFile("/code/favicon.ico");
|
res.sendFile("/code/favicon.ico");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/trafficLog.js", function (req, res) {
|
|
||||||
res.sendFile("/code/dist/trafficLog.js");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/htmx.js", function (req, res) {
|
app.get("/htmx.js", function (req, res) {
|
||||||
res.sendFile("/code/node_modules/htmx.org/dist/htmx.min.js");
|
res.sendFile("/code/node_modules/htmx.org/dist/htmx.min.js");
|
||||||
});
|
});
|
||||||
@ -69,11 +67,15 @@ app.post('/upload_apk', async function (req, res) {
|
|||||||
return res.status(400).send('No files were uploaded.');
|
return res.status(400).send('No files were uploaded.');
|
||||||
}
|
}
|
||||||
execSync("rm -rf /shared_buffer/*");
|
execSync("rm -rf /shared_buffer/*");
|
||||||
console.log(req.files);
|
if (Array.isArray(req.files.app)) {
|
||||||
for (const [idx, file] of req.files.app.entries()) {
|
for (const [idx, file] of req.files.app.entries()) {
|
||||||
let uploadPath = '/shared_buffer/app' + idx + '.apk';
|
let uploadPath = '/shared_buffer/app' + idx + '.apk';
|
||||||
await file.mv(uploadPath);
|
await file.mv(uploadPath);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let uploadPath = '/shared_buffer/app' + 0 + '.apk';
|
||||||
|
await req.files.app.mv(uploadPath);
|
||||||
|
}
|
||||||
android_websocket.send(`install`);
|
android_websocket.send(`install`);
|
||||||
res.send('Files uploaded!');
|
res.send('Files uploaded!');
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "esbuild --sourcemap --bundle src/trafficLog.jsx --outfile=dist/trafficLog.js --jsx-factory=h --jsx-fragment=Fragment"
|
"build": "esbuild --sourcemap --bundle src/trafficLog.jsx src/notifications.jsx --outdir=dist/ --jsx-factory=h --jsx-fragment=Fragment"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
69
http_server/code/src/notifications.jsx
Normal file
69
http_server/code/src/notifications.jsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { render, Component } from "preact";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
|
||||||
|
function rand_num() {
|
||||||
|
return Math.floor(Math.random() * Number.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Notifications extends Component {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = { notifications: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_notification (id) {
|
||||||
|
const newNotifications = this.state.notifications.filter(
|
||||||
|
(notification) => notification.id !== id
|
||||||
|
);
|
||||||
|
this.setState({ notifications: newNotifications });
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// This should also be dynamic
|
||||||
|
this.connection = new WebSocket("ws://127.0.0.1:3001");
|
||||||
|
|
||||||
|
this.connection.onmessage = (msg) => {
|
||||||
|
let new_id = rand_num();
|
||||||
|
this.setState({
|
||||||
|
notifications: [
|
||||||
|
{ id: new_id, notification: JSON.parse(msg.data) },
|
||||||
|
...this.state.notifications,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
// a 10 sec timeout
|
||||||
|
setTimeout(() => {
|
||||||
|
this.remove_notification(new_id)
|
||||||
|
}, 10000)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
console.log("Render", this.state.notifications);
|
||||||
|
return this.state.notifications.map(({ id, notification }) => (
|
||||||
|
<div
|
||||||
|
onClick={() => this.remove_notification(id)}
|
||||||
|
style={`
|
||||||
|
background-color: ${notification.is_ok ? "#66ff99" : "#ff5c33"};
|
||||||
|
border-radius: 5px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: ${notification.is_ok ? "#369648" : "#a23915"};
|
||||||
|
padding: 5px;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<b>{notification.context}</b>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{notification.message.split("\n").map((line) => (
|
||||||
|
<p>{line}</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(<Notifications />, document.getElementById("notifications"));
|
Loading…
x
Reference in New Issue
Block a user