From 66141472e1fc1ff2348306d3e154d42c95904b33 Mon Sep 17 00:00:00 2001 From: Alban Date: Tue, 22 Sep 2020 11:38:58 +0200 Subject: [PATCH] alpha --- .gitignore | 3 + public/index.html | 71 ++++++++ public/manifest.json | 9 ++ public/sym/dark.css | 250 +++++++++++++++++++++++++++++ public/sym/ic_close_white_24px.svg | 4 + public/sym/script.js | 32 ++++ server.js | 113 +++++++++++++ 7 files changed, 482 insertions(+) create mode 100644 .gitignore create mode 100644 public/index.html create mode 100644 public/manifest.json create mode 100644 public/sym/dark.css create mode 100644 public/sym/ic_close_white_24px.svg create mode 100644 public/sym/script.js create mode 100644 server.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e259ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +./node_modules/ +./package-lock.json diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..04e5fe3 --- /dev/null +++ b/public/index.html @@ -0,0 +1,71 @@ + + + + + esp-iot + + + + + + + + + + + +
ESP-IoT
+
LED 1:
+
+
on
+
+
+
off
+
+ +
+
+ +
+
+
+
+ + \ No newline at end of file diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..70b9a12 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "ESP IoT", + "short_name": "ESP-IoT", + "start_url": "/", + "display": "standalone", + "background_color": "#14181b", + "theme_color": "#00BCD4", + "orientation": "portrait-primary" +} \ No newline at end of file diff --git a/public/sym/dark.css b/public/sym/dark.css new file mode 100644 index 0000000..596de62 --- /dev/null +++ b/public/sym/dark.css @@ -0,0 +1,250 @@ +html{ + width: 100%; + height: 100%; + margin: 0px; + background-color: #14181b; +} +body{ + position: relative; + width: 100%; + padding-top: 20px; + padding-bottom: 130px; + min-height: calc(100% - 150px); + max-width: 70rem; + min-width: 25rem; + margin: auto; + background-color: #1f262b; +} +table{ + position: relative; + margin: auto; + width: calc(100% - 50px); + max-width: 600px; + background-color: #1f262b; + box-shadow: 3px 3px 10px #333; + border: 2px solid #fff; + border-collapse: separate; + border-spacing: 2px; + border-radius: 10px; + color: #fff; + font-size: 15pt; + font-family:"Roboto", regular, sans-serif; +} +tr{ + margin: auto; + border: 1px solid #fff; +} +th{ + margin: auto; + border: 0px solid #aaa; + background-color: #546E7A; + padding: 20px; + border-radius: 8px; +} +td{ + margin: auto; + border: 0px solid #aaa; + background-color: #37474F ; + padding: 10px; + border-radius: 8px; +} +td.left,th.left{ + border-radius: 8px 0px 0px 8px; +} +td.right,th.right{ + border-radius: 0px 8px 8px 0px; +} +td.mid,th.mid{ + border-radius: 0px 0px 0px 0px; +} + + +div.input-box { + position: absolute; + left: calc(50% - 14rem); + top: calc(50% - 7rem); + width: 28rem; + height: 14rem; + background-color: #14181b00; + border-radius: 8px; + border: 0px solid #fff; +} +div.input-field { + position: relative; + margin-left: 5%; + margin-top: 20px; + width: 90%; + height: 2.5rem; + background-color: #14181b; + border-radius: 1.25rem; + border: 1px solid #fff; +} +.input { + position: absolute; + left: 1rem; + top: calc(50% - 1rem); + width: calc(100% - 2rem); + height: 2rem; + text-align: center; + color:#fff; + font-size: 15pt; + font-family:Arial, "lucida console", sans-serif; + border: 0px solid #fff; + background-color: transparent; + outline: 0 none; +} +input[id="longurl-input"]::-webkit-input-placeholder { + color: #ffffff; +} +.btn-blue{ + cursor: pointer; + height: 2.5rem; + background-color: #00BCD4; + box-shadow: 3px 3px 10px #333; + border-radius: 1.25rem; +} +.btn-green{ + cursor: pointer; + height: 2.5rem; + background-color: #009688; + box-shadow: 3px 3px 10px #333; + border-radius: 1.25rem; +} +.btn-red{ + cursor: pointer; + height: 2.5rem; + background-color: #E53935; + box-shadow: 3px 3px 10px #333; + border-radius: 1.25rem; +} +.btn-text { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 1.4rem; + color:#fff; + font-family:Arial, "lucida console", sans-serif; +} +.sym_btn-red{ + cursor: pointer; + height: 2.5rem; + width: 2.5rem; + background-color: #E53935; + border-radius: 1.25rem; + box-shadow: 3px 3px 10px #333; + float: left; +} +.sym_btn-blue{ + cursor: pointer; + height: 2.5rem; + width: 2.5rem; + background-color: #1E88E5; + border-radius: 1.25rem; + box-shadow: 3px 3px 10px #333; + float: left; +} +.sym_btn-invisible{ + cursor: pointer; + height: 2.5rem; + width: 2.5rem; + border-radius: 1.25rem; + float: left; +} +img.icon { + margin-top: 8px; + margin-left: 8px; +} +.title { + text-align: center; + width: 100%; + color:#fff; + font-size: 30pt; + font-family:"Roboto", bold, sans-serif; +} +.title2 { + margin-top: 20px; + text-align: center; + width: 100%; + color:#fff; + font-size: 20pt; + font-family:"Roboto", bold, sans-serif; +} +.box-dark{ + position: relative; + margin: auto; + width: calc(100% - 50px); + max-width: 600px; + background-color: #1f262b; + box-shadow: 3px 3px 10px #333; + border: 2px solid #fff; + border-radius: 10px; + color: #fff; + font-size: 15pt; + font-family:"Roboto", regular, sans-serif; +} +.error{ + position: absolute; + bottom: 1rem; + left: 1rem; + height: 10rem; + width: 16rem; + background-color: #E53935; + border-radius: 15px; +} + + +#short-btn { + position: absolute; + width: 10rem; + margin-left: calc(50% - 5rem); + margin-top: 20px; +} +#copy-btn { + position: absolute; + width: 10rem; + margin-left: calc(50% - 5rem); + margin-top: 1rem; +} +#surl-popup{ + position: absolute; + width: 30rem; + height: 14rem; + left: calc(50% - 15rem); + top: calc(50% - 7rem); + display: none; + animation: slide-from-top alternate 0.4s; +} +#error-box{ + display: none; +} + + +@keyframes slide-from-top{ + from{top:20%;opacity: 0} + to{top:calc(50% - 7rem);opacity: 1} +} +@keyframes slide-from-left{ + from{left:-30rem;opacity: 0} + to{left:1rem;opacity: 1} +} + + + +@media (max-width: 35rem){ + div.input-box { + left: 5%; + width: 90%; + } + .error{ + bottom: 1rem; + left: 1rem; + height: 8rem; + width: calc(100% - 2rem); + } + #surl-popup{ + width: calc(100% - 2rem); + height: 14rem; + left: 1rem; + } +} \ No newline at end of file diff --git a/public/sym/ic_close_white_24px.svg b/public/sym/ic_close_white_24px.svg new file mode 100644 index 0000000..5704800 --- /dev/null +++ b/public/sym/ic_close_white_24px.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/public/sym/script.js b/public/sym/script.js new file mode 100644 index 0000000..445706e --- /dev/null +++ b/public/sym/script.js @@ -0,0 +1,32 @@ +function selected(id){ + var element = document.getElementById(id); + element.style.boxShadow = '1px 1px 2px #999'; + element.style.backgroundColor = "#ffffff"; + + var element = document.getElementById(id+'-input'); + element.style.color = "#000000"; +} +function deselected(id){ + var element = document.getElementById(id); + element.style.boxShadow = '0px 0px 0px #999'; + element.style.backgroundColor = "#14181b"; + + var element = document.getElementById(id+'-input'); + element.style.color = "#ffffff"; +} + +function visible(id, status){ + if(status == "on"){ + document.getElementById(id).style.display = 'block'; + } + else{ + document.getElementById(id).style.display = 'none'; + } +} + +function session_end() { + if (confirm("Session timed out! Please login.")) { + window.location.replace('https://adb.sh/robo-remote/login.php'); + } else { + } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..4325633 --- /dev/null +++ b/server.js @@ -0,0 +1,113 @@ +const http = require('http') +const url = require('url') +const fs = require('fs') +const ws = require('ws') +const redis = require('redis') +const mime = require('mime') +const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest + +const host = 'http://127.0.0.1:8080/' +const outpath = ['sym', '', 'manifest.json', 'admin', 'stats', 'analytics'] + +let led1_status = 'off'; + +//redis client +const redis_cli = redis.createClient({ + host: '127.0.0.1', + port: 6379 +}) +redis_cli.on("error", function (error) { + console.error(error) +}) + +//HTTP server +http.createServer(function (req, res) { + const q = url.parse(req.url, true); + let filename = "./public" + q.pathname; + let path_split = q.pathname.split("/", 3); + if (path_split[path_split.length - 1] === "") filename += "/index.html"; + let file_type = mime.getType(filename) + if (path_split[1] === "connect") { + res.writeHead(200, {'Content-Type': file_type}); + res.write(""); + return res.end(); + } + fs.readFile(filename, function(err, data) { + if (err) { + res.writeHead(404, {'Content-Type': "text/html"}); + return res.end("404 Not Found"); + } + res.writeHead(200, {'Content-Type': file_type}); + res.write(data); + return res.end(); + }) +}).listen(8080); + +//WS server +const wss = new ws.Server({ + port: 8081, + perMessageDeflate: { + zlibDeflateOptions: { + // See zlib defaults. + chunkSize: 1024, + memLevel: 7, + level: 3 + }, + zlibInflateOptions: { + chunkSize: 10 * 1024 + }, + // Other options settable: + clientNoContextTakeover: true, // Defaults to negotiated value. + serverNoContextTakeover: true, // Defaults to negotiated value. + serverMaxWindowBits: 10, // Defaults to negotiated value. + // Below options specified as default values. + concurrencyLimit: 10, // Limits zlib concurrency for perf. + threshold: 1024 // Size (in bytes) below which messages + // should not be compressed. + } +}); + +//WS handler +wss.on('connection', ws => { + ws.on('message', message => { + console.log(`Received message => ${message}`) + let msg = message.split(";", 2) + if (msg[0] === 'led1') { + if (msg[1] === '') ws.send('error;try again') + else if (msg[1] === 'on' || msg[1] === "off"){ + let xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + wss.clients.forEach(clients => { + clients.send(message) + }) + led1_status = msg[1] + } + } + xhr.open('GET', `http://192.168.1.210/${msg[1]}`, true); + xhr.timeout = 1000; + xhr.ontimeout = function(e) {ws.send('error;device "led1" is offline')} + xhr.send(); + setTimeout(to => {if (xhr.readyState !== 4) ws.send('error;device "led1" took too long to reach');xhr.abort()}, 1500) + }else ws.send('error;try again') + } + }) + ws.send('websocket connected') + ws.send(`led1;${led1_status}`) +}) + +//random key +function get_key(length) { + let forbidden = false; let output = '' + let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + do{ + for (let i = 0; i < length; i++ ) + output += characters.charAt(Math.floor(Math.random() * characters.length)) + for (let i = 0; i < output.length; i++) if (output === outpath[i]) forbidden = true + redis_cli.hget("surl;"+output, "url", function(err, obj) { + if(err) console.log(err) + if(obj) forbidden = true + }) + } while (forbidden) + return output +}