const express = require("express"); const chalk = require("chalk"); let path = require("path"); const fs = require("fs"); const port = 8080; /* * Web Server for development * Web Socket server for development */ const wscolor = chalk.cyan; const expresscolor = chalk.green; const commandcolor = chalk.white; const WebSocket = require("ws"); let currentID = 0; const app = express(); const fileUpload = require("express-fileupload"); let serverpath = path.normalize(__dirname + "/../server/public/"); let sdpath = path.normalize(__dirname + "/../server/sd/"); let WebSocketServer = require("ws").Server, wss = new WebSocketServer({ port: 81, handleProtocols: function (protocol) { console.log("protocol received from client " + protocol); return "webui-v3"; return null; }, }); app.use(fileUpload({ preserveExtension: true, debug: false })); app.listen(port, () => console.log(expresscolor(`[express] Listening on port ${port}!`)) ); //app.use(express.urlencoded({ extended: false })); function SendBinary(text) { const array = new Uint8Array(text.length); for (let i = 0; i < array.length; ++i) { array[i] = text.charCodeAt(i); } wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { client.send(array); } }); } app.post("/login", function (req, res) { res.send(""); return; }); app.get("/config", function (req, res) { res.send( "chip id: 56398\nCPU Freq: 240 Mhz
" + "CPU Temp: 58.3 C
" + "free mem: 212.36 KB
" + "SDK: v3.2.3-14-gd3e562907
" + "flash size: 4.00 MB
" + "size for update: 1.87 MB
" + "FS type: LittleFS
" + "FS usage: 104.00 KB/192.00 KB
" + "baud: 115200
" + "sleep mode: none
" + "wifi: ON
" + "hostname: esp3d
" + "HTTP port: 80
" + "Telnet port: 23
" + "WebDav port: 8383
" + "sta: ON
" + "mac: 80:7D:3A:C4:4E:DC
" + "SSID: WIFI_OFFICE_A2G
" + "signal: 100 %
" + "phy mode: 11n
" + "channel: 11
" + "ip mode: dhcp
" + "ip: 192.168.1.61
" + "gw: 192.168.1.1
" + "msk: 255.255.255.0
" + "DNS: 192.168.1.1
" + "ap: OFF
" + "mac: 80:7D:3A:C4:4E:DD
" + "serial: ON
" + "notification: OFF
" + "Target Fw: repetier
" + "FW ver: 3.0.0.a91
" + "FW arch: ESP32 " ); return; }); app.get("/command", function (req, res) { console.log(commandcolor(`[server]/command params: ${req.query.cmd}`)); let url = req.query.cmd; if (url.startsWith("[ESP800]json")) { res.json({ cmd: "800", status: "ok", data: { FWVersion: "3.0.0.a28", FWTarget: 40, SDConnection: "none", Authentication: "Disabled", WebCommunication: "Synchronous", WebSocketIP: "localhost", WebSocketPort: "81", Hostname: "esp3d", WiFiMode: "STA", WebUpdate: "Enabled", FlashFileSystem: "LittleFs", HostPath: "/", Time: "none", Cam_ID: "4", Cam_name: "ESP32 Cam", }, }); return; } if (url.indexOf("ESP111") != -1) { res.send("192.168.1.111"); return; } if (url.indexOf("ESP420") != -1) { res.json({ Status: [ { id: "chip id", value: "38078" }, { id: "CPU Freq", value: "240 Mhz" }, { id: "CPU Temp", value: "50.6 C" }, { id: "free mem", value: "217.50 KB" }, { id: "SDK", value: "v3.3.1-61-g367c3c09c" }, { id: "flash size", value: "4.00 MB" }, { id: "size for update", value: "1.87 MB" }, { id: "FS type", value: "SPIFFS" }, { id: "FS usage", value: "39.95 KB/169.38 KB" }, { id: "baud", value: "115200" }, { id: "sleep mode", value: "none" }, { id: "wifi", value: "ON" }, { id: "hostname", value: "esp3d" }, { id: "HTTP port", value: "80" }, { id: "Telnet port", value: "23" }, { id: "Ftp ports", value: "21, 20, 55600" }, { id: "sta", value: "ON" }, { id: "mac", value: "30:AE:A4:21:BE:94" }, { id: "SSID", value: "WIFI_OFFICE_B2G" }, { id: "signal", value: "100 %" }, { id: "phy mode", value: "11n" }, { id: "channel", value: "2" }, { id: "ip mode", value: "dhcp" }, { id: "ip", value: "192.168.1.43" }, { id: "gw", value: "192.168.1.1" }, { id: "msk", value: "255.255.255.0" }, { id: "DNS", value: "192.168.1.1" }, { id: "ap", value: "OFF" }, { id: "mac", value: "30:AE:A4:21:BE:95" }, { id: "serial", value: "ON" }, { id: "notification", value: "OFF" }, { id: "FW ver", value: "3.0.0.a28" }, { id: "FW arch", value: "ESP32" }, ], }); return; } if (url.indexOf("ESP410") != -1) { res.json({ AP_LIST: [ { SSID: "HP-Setup>71-M277 LaserJet", SIGNAL: "92", IS_PROTECTED: "0", }, { SSID: "WIFI_OFFICE_B2G", SIGNAL: "88", IS_PROTECTED: "1" }, { SSID: "NETGEAR70", SIGNAL: "66", IS_PROTECTED: "1" }, { SSID: "ZenFone6'luc", SIGNAL: "48", IS_PROTECTED: "1" }, { SSID: "Livebox-EF01", SIGNAL: "20", IS_PROTECTED: "1" }, { SSID: "orange", SIGNAL: "20", IS_PROTECTED: "0" }, ], }); return; } if (url.indexOf("ESP400") != -1) { res.json({ Settings: [ { F: "network/network", P: "130", T: "S", V: "esp3d", H: "hostname", S: "32", M: "1", }, { F: "network/network", P: "0", T: "B", V: "1", H: "radio mode", O: [{ none: "0" }, { sta: "1" }, { ap: "2" }], }, { F: "network/sta", P: "1", T: "S", V: "WIFI_OFFICE_B2G", S: "32", H: "SSID", M: "1", }, { F: "network/sta", P: "34", T: "S", N: "1", V: "********", S: "64", H: "pwd", M: "8", }, { F: "network/sta", P: "99", T: "B", V: "1", H: "ip mode", O: [{ dhcp: "1" }, { static: "0" }], }, { F: "network/sta", P: "100", T: "A", V: "192.168.0.1", H: "ip", }, { F: "network/sta", P: "108", T: "A", V: "192.168.0.1", H: "gw", }, { F: "network/sta", P: "104", T: "A", V: "255.255.255.0", H: "msk", }, { F: "network/ap", P: "218", T: "S", V: "ESP3D", S: "32", H: "SSID", M: "1", }, { F: "network/ap", P: "251", T: "S", N: "1", V: "********", S: "64", H: "pwd", M: "8", }, { F: "network/ap", P: "316", T: "A", V: "192.168.0.1", H: "ip", }, { F: "network/ap", P: "118", T: "B", V: "11", H: "channel", O: [ { 1: "1" }, { 2: "2" }, { 3: "3" }, { 4: "4" }, { 5: "5" }, { 6: "6" }, { 7: "7" }, { 8: "8" }, { 9: "9" }, { 10: "10" }, { 11: "11" }, { 12: "12" }, { 13: "13" }, { 14: "14" }, ], }, { F: "service/http", P: "328", T: "B", V: "1", H: "enable", O: [{ no: "0" }, { yes: "1" }], }, { F: "service/http", P: "121", T: "I", V: "80", H: "port", S: "65001", M: "1", }, { F: "service/telnetp", P: "329", T: "B", V: "1", H: "enable", O: [{ no: "0" }, { yes: "1" }], }, { F: "service/telnetp", P: "125", T: "I", V: "23", H: "port", S: "65001", M: "1", }, { F: "service/ftp", P: "1208", T: "B", V: "1", H: "enable", O: [{ no: "0" }, { yes: "1" }], }, { F: "service/ftp", P: "1196", T: "I", V: "21", H: "control port", S: "65001", M: "1", }, { F: "service/ftp", P: "1200", T: "I", V: "20", H: "active port", S: "65001", M: "1", }, { F: "service/ftp", P: "1204", T: "I", V: "55600", H: "passive port", S: "65001", M: "1", }, { F: "service/notification", P: "1191", T: "B", V: "1", H: "auto notif", O: [{ no: "0" }, { yes: "1" }], }, { F: "service/notification", P: "116", T: "B", V: "0", H: "notification", O: [ { none: "0" }, { pushover: "1" }, { email: "2" }, { line: "3" }, ], }, { F: "service/notification", P: "332", T: "S", V: "********", S: "63", H: "t1", M: "0", }, { F: "service/notification", P: "583", T: "S", V: "********", S: "63", H: "t2", M: "0", }, { F: "service/notification", P: "1042", T: "S", V: " ", S: "127", H: "ts", M: "0", }, { F: "system/system", P: "648", T: "B", V: "40", H: "targetfw", O: [ { repetier: "50" }, { marlin: "20" }, { marlinkimbra: "35" }, { smoothieware: "40" }, { grbl: "10" }, { unknown: "0" }, ], }, { F: "system/system", P: "112", T: "I", V: "115200", H: "baud", O: [ { 9600: "9600" }, { 19200: "19200" }, { 38400: "38400" }, { 57600: "57600" }, { 74880: "74880" }, { 115200: "115200" }, { 230400: "230400" }, { 250000: "250000" }, { 500000: "500000" }, { 921600: "921600" }, ], }, { F: "system/system", P: "320", T: "I", V: "10000", H: "bootdelay", S: "40000", M: "0", }, { F: "system/system", P: "129", T: "F", V: "255", H: "outputmsg", O: [{ M117: "16" }, { serial: "1" }, { telnet: "2" }], }, ], }); return; } SendBinary("ok\n"); res.send(""); }); function fileSizeString(size) { let s; if (size < 1024) return size + " B"; if (size < 1024 * 1024) return (size / 1024).toFixed(2) + " KB"; if (size < 1024 * 1024 * 1024) return (size / (1024 * 1024)).toFixed(2) + " MB"; if (size < 1024 * 1024 * 1024 * 1024) return (size / (1024 * 1024 * 1024)).toFixed(2) + " GB"; return "X B"; } function filesList(mypath, mainpath) { let res = '{"files":['; let nb = 0; let total = sdpath == mainpath ? 4096 * 1024 * 1024 : 1.2 * 1024 * 1024; let totalused = getTotalSize(mainpath); let currentpath = path.normalize(mainpath + mypath); console.log("[path]" + currentpath); fs.readdirSync(currentpath).forEach((fileelement) => { let fullpath = path.normalize(currentpath + "/" + fileelement); let fst = fs.statSync(fullpath); let fsize = -1; if (fst.isFile()) { fsize = fileSizeString(fst.size); } if (nb > 0) res += ","; res += '{"name":"' + fileelement + '","size":"' + fsize + '"}'; nb++; }); res += '],"path":"' + mypath + '","occupation":"' + ((100 * totalused) / total).toFixed(0) + '","status":"ok","total":"' + fileSizeString(total) + '","used":"' + fileSizeString(totalused) + '"}'; return res; } const getAllFiles = function (dirPath, arrayOfFiles) { let files = fs.readdirSync(dirPath); arrayOfFiles = arrayOfFiles || []; files.forEach(function (file) { if (fs.statSync(dirPath + "/" + file).isDirectory()) { arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles); } else { arrayOfFiles.push(dirPath + "/" + file); } }); return arrayOfFiles; }; const getTotalSize = function (directoryPath) { const arrayOfFiles = getAllFiles(directoryPath); let totalSize = 0; arrayOfFiles.forEach(function (filePath) { totalSize += fs.statSync(filePath).size; }); return totalSize; }; function deleteFolderRecursive(path) { if (fs.existsSync(path) && fs.lstatSync(path).isDirectory()) { fs.readdirSync(path).forEach(function (file, index) { let curPath = path + "/" + file; if (fs.lstatSync(curPath).isDirectory()) { // recurse deleteFolderRecursive(curPath); } else { // delete file fs.unlinkSync(curPath); } }); console.log(`[server]Deleting directory "${path}"...`); if (fs.existsSync(path)) fs.rmdirSync(path); } else console.log(`[server]No directory "${path}"...`); } app.all("/updatefw", function (req, res) { res.send("ok"); }); app.all("/sdfiles", function (req, res) { let mypath = req.query.path; let url = req.originalUrl; let filepath = path.normalize(sdpath + mypath + "/" + req.query.filename); if (url.indexOf("action=deletedir") != -1) { console.log("[server]delete directory " + filepath); deleteFolderRecursive(filepath); fs.readdirSync(mypath); } else if (url.indexOf("action=delete") != -1) { fs.unlinkSync(filepath); console.log("[server]delete file " + filepath); } if (url.indexOf("action=createdir") != -1) { fs.mkdirSync(filepath); console.log("[server]new directory " + filepath); } if (typeof mypath == "undefined") { if (typeof req.body.path == "undefined") { console.log("[server]path is not defined"); mypath = "/"; } else { mypath = (req.body.path == "/" ? "" : req.body.path) + "/"; } } console.log("[server]path is " + mypath); if (!req.files || Object.keys(req.files).length === 0) { return res.send(filesList(mypath, sdpath)); } let myFile = req.files.myfiles; if (typeof myFile.length == "undefined") { let fullpath = path.normalize(sdpath + mypath + myFile.name); console.log("[server]one file:" + fullpath); myFile.mv(fullpath, function (err) { if (err) return res.status(500).send(err); res.send(filesList(mypath, sdpath)); }); return; } else { console.log(myFile.length + " files"); for (let i = 0; i < myFile.length; i++) { let fullpath = path.normalize(sdpath + mypath + myFile[i].name); console.log(fullpath); myFile[i].mv(fullpath).then(() => { if (i == myFile.length - 1) res.send(filesList(mypath, sdpath)); }); } } }); app.all("/files", function (req, res) { let mypath = req.query.path; let url = req.originalUrl; let filepath = path.normalize( serverpath + mypath + "/" + req.query.filename ); if (url.indexOf("action=deletedir") != -1) { console.log("[server]delete directory " + filepath); deleteFolderRecursive(filepath); fs.readdirSync(mypath); } else if (url.indexOf("action=delete") != -1) { fs.unlinkSync(filepath); console.log("[server]delete file " + filepath); } if (url.indexOf("action=createdir") != -1) { fs.mkdirSync(filepath); console.log("[server]new directory " + filepath); } if (typeof mypath == "undefined") { if (typeof req.body.path == "undefined") { console.log("[server]path is not defined"); mypath = "/"; } else { mypath = (req.body.path == "/" ? "" : req.body.path) + "/"; } } console.log("[server]path is " + mypath); if (!req.files || Object.keys(req.files).length === 0) { return res.send(filesList(mypath, serverpath)); } let myFile = req.files.myfiles; if (typeof myFile.length == "undefined") { let fullpath = path.normalize(serverpath + mypath + myFile.name); console.log("[server]one file:" + fullpath); myFile.mv(fullpath, function (err) { if (err) return res.status(500).send(err); res.send(filesList(mypath, serverpath)); }); return; } else { console.log(myFile.length + " files"); for (let i = 0; i < myFile.length; i++) { let fullpath = path.normalize(serverpath + mypath + myFile[i].name); console.log(fullpath); myFile[i].mv(fullpath).then(() => { if (i == myFile.length - 1) res.send(filesList(mypath, serverpath)); }); } } }); wss.on("connection", (socket, request) => { console.log(wscolor("[ws] New connection")); console.log(wscolor(`[ws] currentID:${currentID}`)); socket.send(`currentID:${currentID}`); wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { client.send(`activeID:${currentID}`); } }); currentID++; socket.on("message", (message) => { console.log(wscolor("[ws] received: %s", message)); }); }); wss.on("error", (error) => { console.log(wscolor("[ws] Error: %s", error)); });