ESP3D/embedded/config/server.js
Luc ea1eb83a28 Add Script to parse all c/cpp/h/ino files and format them using clang-format with Google style
Update style to some files with clang-format using Google style
Add Script to parse all embedded  js/css files and format them using prettier based on .prettierrc config file
Update style to embedded js/css files with prettier
2024-05-29 15:10:47 +08:00

687 lines
22 KiB
JavaScript

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<br/>' +
'CPU Temp: 58.3 C<br/>' +
'free mem: 212.36 KB<br/>' +
'SDK: v3.2.3-14-gd3e562907<br/>' +
'flash size: 4.00 MB<br/>' +
'size for update: 1.87 MB<br/>' +
'FS type: LittleFS<br/>' +
'FS usage: 104.00 KB/192.00 KB<br/>' +
'baud: 115200<br/>' +
'sleep mode: none<br/>' +
'wifi: ON<br/>' +
'hostname: esp3d<br/>' +
'HTTP port: 80<br/>' +
'Telnet port: 23<br/>' +
'WebDav port: 8383<br/>' +
'sta: ON<br/>' +
'mac: 80:7D:3A:C4:4E:DC<br/>' +
'SSID: WIFI_OFFICE_A2G<br/>' +
'signal: 100 %<br/>' +
'phy mode: 11n<br/>' +
'channel: 11<br/>' +
'ip mode: dhcp<br/>' +
'ip: 192.168.1.61<br/>' +
'gw: 192.168.1.1<br/>' +
'msk: 255.255.255.0<br/>' +
'DNS: 192.168.1.1<br/>' +
'ap: OFF<br/>' +
'mac: 80:7D:3A:C4:4E:DD<br/>' +
'serial: ON<br/>' +
'notification: OFF<br/>' +
'Target Fw: repetier<br/>' +
'FW ver: 3.0.0.a91<br/>' +
'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&#39;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));
});