Merge pull request #237 from Erdnusschokolade/fix/config-persistence

Fix config persistence: missing commands, delete handling, multipart upload
This commit is contained in:
logicog
2026-06-01 06:46:11 +02:00
committed by GitHub
2 changed files with 91 additions and 37 deletions
+61 -12
View File
@@ -1,32 +1,81 @@
var configInterval = Number(); var configInterval = Number();
var configuration = []; var configuration = [];
const conf_cmds = [ const conf_cmds = [
/ip\s+(\d{1,3}\.){3}\d{1,3}/, /gw\s+(\d{1,3}\.){3}\d{1,3}/, /netmask\s+(\d{1,3}\.){3}\d{1,3}/, /^ip\s+(\d{1,3}\.){3}\d{1,3}$/,
/eee(\s+\d)?\s+(on|off)/, /mirror(\s+(\d|10))(\s+(\d|10)(t|r)?)+/, /vlan\s+(\d{1,4})(\s+(\d|10)(t|u)?)+/ /^ip\s+dhcp$/,
/^gw\s+(\d{1,3}\.){3}\d{1,3}$/,
/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
/^syslog\s+(on|off)$/,
/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,
/^passwd\s+\S+$/,
/^vlan\s+\d{1,4}\s+d$/,
/^vlan\s+\d{1,4}\s+mgmt$/,
/^vlan\s+\d{1,4}(\s+[a-zA-Z]\w*)?(\s+\d{1,2}[tu]?)+$/,
/^pvid\s+\d{1,2}\s+\d{1,4}$/,
/^ingress(\s+\d{1,2}[tua])+$/,
/^ingress\s+[tua]$/,
/^port\s+\d{1,2}\s+name\s+\S+$/,
/^eee(\s+\d{1,2})?\s+(on|off)$/,
/^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,
/^lag\s+\d(\s+\d{1,2})+$/,
/^laghash\s+\d(\s+\w+)+$/,
/^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/,
/^stp\s+(on|off)$/,
/^igmp\s+(on|off)$/,
/^mtu\s+\d{1,2}\s+\d+$/,
/^bw\s+(in|out)\s+\d{1,2}\s+\S+$/,
]; ];
const conf_overwrite = [ const conf_overwrite = [
/ip/, /gw/, /netmask/, /eee\s+\w+/, /eee(\s+\w)/, /mirror/, /vlan\s+(\d{1,4})/ /^ip\b/,
/^gw\b/,
/^netmask\b/,
/^syslog\s+ip\b/,
/^syslog\b/,
/^passwd\b/,
/^vlan\s+\d{1,4}\s+mgmt$/,
/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
/^pvid\s+\d{1,2}\b/,
/^ingress\b/,
/^port\s+\d{1,2}\s+name\b/,
/^eee\s+\d{1,2}\b/,
/^eee\b/,
/^mirror\b/,
/^lag\s+\d+\b/,
/^laghash\b/,
/^isolate\s+\d{1,2}\b/,
/^stp\b/,
/^igmp\b/,
/^mtu\s+\d{1,2}\b/,
/^bw\s+(in|out)\s+\d{1,2}\b/,
]; ];
function parseConf(s){ function parseConf(s){
var a = s.split(/\r\n|\n/); var a = s.split(/\r\n|\n/);
for (var l = 0; l < a.length; l++) { for (var l = 0; l < a.length; l++) {
if (!a[l].length || a[l] == "\n" || a[l] == "\r\n") var line = a[l].trim().replace(/\s+/g, ' ');
if (!line.length) continue;
const deleteMatch = line.match(/^vlan\s+(\d{1,4})\s+d$/);
if (deleteMatch) {
const prefix = "vlan " + deleteMatch[1] + " ";
configuration = configuration.filter(c =>
c !== "vlan " + deleteMatch[1] && !c.startsWith(prefix));
continue; continue;
console.log(l + ' --> ' + a[l]); }
console.log(l + ' --> ' + line);
var ignore = true; var ignore = true;
for (const x of conf_cmds) for (const x of conf_cmds)
if (x.test(a[l])) ignore = false; if (x.test(line)) { ignore = false; break; }
if (ignore) continue; if (ignore) continue;
for (const x of conf_overwrite) { for (const x of conf_overwrite) {
if (x.test(a[l])) { if (x.test(line)) {
console.log("Match ", x, " to ", a[l]); let m = line.match(x);
m = a[l].match(x); let matchStr = m[0];
console.log("Starts with ", m[0]); configuration = configuration.filter(item =>
configuration = configuration.filter(item => !(item.startsWith(m[0]))); !(item === matchStr || item.startsWith(matchStr + " ")));
break;
} }
} }
configuration.push(a[l]); configuration.push(line);
} }
console.log("Configuration now:"); console.log("Configuration now:");
for (const x of configuration) { console.log(x); } for (const x of configuration) { console.log(x); }
+18 -13
View File
@@ -1,4 +1,5 @@
var systemInterval = Number(); var systemInterval = Number();
var isSaving = false;
const ips = ["ip", "netmask", "gw"]; const ips = ["ip", "netmask", "gw"];
function checkIp(ip) { function checkIp(ip) {
@@ -43,35 +44,39 @@ async function cmdSub() {
async function sendConfig(c) { async function sendConfig(c) {
if (isSaving) return;
isSaving = true;
clearInterval(systemInterval);
const form = new FormData(); const form = new FormData();
form.append("MAX_FILE_SIZE", "4096"); form.append("MAX_FILE_SIZE", "4096");
form.append("configuration", new Blob([c], {type: "application/octet-stream"})); form.append("configuration", new Blob([c], {type: "application/octet-stream"}), "config.txt");
try { try {
const response = await fetch('/config', { const response = await fetch('/config', {
method: 'POST', method: 'POST',
body: form body: form
}); });
console.log('Completed!', response); console.log('Completed!', response);
try {
await fetch('/cmd_log_clear', { method: 'GET' });
} catch(e) {}
} catch(err) { } catch(err) {
console.error(`Error: ${err}`); console.error(`Error: ${err}`);
} finally {
isSaving = false;
systemInterval = setInterval(fetchIP, 1000);
} }
} }
async function flashSave() { async function flashSave() {
fetchConfig().then((s) => { configuration = [];
parseConf(s); const savedConfig = await fetchConfig();
fetchCmdLog().then((s) => { const cmdLog = await fetchCmdLog();
parseConf(s); if (savedConfig) parseConf(savedConfig);
var body = ""; if (cmdLog) parseConf(cmdLog);
for (const x of configuration) { body = body + x + "\n"; } const body = configuration.join('\n') + '\n';
console.log("CONFIGURATION to save: ", body); console.log("CONFIGURATION to save: ", body);
sendConfig(body); await sendConfig(body);
});
});
setTimeout(() => {
fetchIP();
}, 500);
} }
async function flashStartupSave() { async function flashStartupSave() {