mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-09-14 04:14:40 +08:00
update 2026-09-07 05:54:25
This commit is contained in:
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-daede
|
||||
PKG_VERSION:=1.15
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=kenzok8
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
@@ -23,9 +23,7 @@ const BACKENDS = {
|
||||
pkg: 'daed',
|
||||
hasWebUI: true,
|
||||
useNetns: true,
|
||||
defaultListen: '0.0.0.0:2023',
|
||||
readyState: '/var/run/daede-daed.ready',
|
||||
readyPattern: /Reload: Finished/
|
||||
defaultListen: '0.0.0.0:2023'
|
||||
},
|
||||
dae: {
|
||||
name: 'dae',
|
||||
@@ -36,9 +34,7 @@ const BACKENDS = {
|
||||
pkg: 'dae',
|
||||
config: '/etc/dae/config.dae',
|
||||
hasWebUI: false,
|
||||
useNetns: false,
|
||||
readyState: '/var/run/daede-dae.ready',
|
||||
readyPattern: /Total startup time:/
|
||||
useNetns: false
|
||||
}
|
||||
};
|
||||
|
||||
@@ -68,56 +64,6 @@ function serviceStatus(name) {
|
||||
});
|
||||
}
|
||||
|
||||
function serviceLogOffset(be) {
|
||||
if (!be || !be.log)
|
||||
return Promise.resolve(0);
|
||||
|
||||
return L.resolveDefault(fs.read_direct(be.log, 'text'), '').then(function(content) {
|
||||
return String(content || '').length;
|
||||
});
|
||||
}
|
||||
|
||||
function serviceReady(be, afterOffset, pid) {
|
||||
if (!be || !be.log || !be.readyPattern)
|
||||
return Promise.resolve(false);
|
||||
|
||||
const expectedPid = Number(pid) || 0;
|
||||
const notFound = function(error) {
|
||||
const code = String(error && (error.code || error.errno || error.name) || '').toUpperCase();
|
||||
const message = String(error && (error.message || error) || '').toUpperCase();
|
||||
return code === 'ENOENT' || code === '-2' || code === 'NOTFOUNDERROR' ||
|
||||
/ENOENT|NO SUCH FILE|RESOURCE NOT FOUND/.test(message);
|
||||
};
|
||||
const readState = be.readyState
|
||||
? fs.stat(be.readyState).then(function(stat) {
|
||||
// A successful stat makes the state file authoritative. A subsequent
|
||||
// read error must fail closed instead of falling back to an old log line.
|
||||
if (!stat)
|
||||
return { present: true, error: true };
|
||||
return fs.read_direct(be.readyState, 'text').then(function(value) {
|
||||
return { present: true, value: String(value || '').trim() };
|
||||
}, function() {
|
||||
return { present: true, error: true };
|
||||
});
|
||||
}, function(error) {
|
||||
return notFound(error) ? { present: false } : { present: true, error: true };
|
||||
})
|
||||
: Promise.resolve({ present: true, error: true });
|
||||
|
||||
return readState.then(function(result) {
|
||||
if (result.present)
|
||||
return !result.error && expectedPid > 0 && result.value === expectedPid + ' ready';
|
||||
|
||||
// Compatibility fallback for a luci-app upgrade before the matching dae or
|
||||
// daed package. It is allowed only when stat explicitly reported ENOENT.
|
||||
return L.resolveDefault(fs.read_direct(be.log, 'text'), '').then(function(content) {
|
||||
const text = String(content || '');
|
||||
const offset = Number(afterOffset) || 0;
|
||||
return be.readyPattern.test(text.slice(text.length < offset ? 0 : offset));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function detectInstalledBackends() {
|
||||
return Promise.all([
|
||||
exists(BACKENDS.dae.initd),
|
||||
@@ -190,7 +136,5 @@ return baseclass.extend({
|
||||
detectRunning: detectRunning,
|
||||
detectBackend: detectBackend,
|
||||
setActiveBackend: setActiveBackend,
|
||||
serviceStatus: serviceStatus,
|
||||
serviceLogOffset: serviceLogOffset,
|
||||
serviceReady: serviceReady
|
||||
serviceStatus: serviceStatus
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ const CSS = [
|
||||
'.dd-status-row .dd-grow{flex:1 1 auto}',
|
||||
'.dd-badge{display:inline-flex;align-items:center;gap:5px;padding:2px 10px;border-radius:999px;font-size:10.5px;font-weight:700;letter-spacing:.3px;border:1px solid transparent;line-height:1.3}',
|
||||
'.dd-badge-run{color:#3da66a;border-color:rgba(61,166,106,.5)}',
|
||||
'.dd-badge-wait{color:#d6a23d;border-color:rgba(214,162,61,.55)}',
|
||||
'.dd-badge-stop{color:#d96d6d;border-color:rgba(217,109,109,.55)}',
|
||||
'.dd-badge-dot{width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block}',
|
||||
'.dd-meta{font-size:11.5px;opacity:.7;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace}',
|
||||
|
||||
@@ -23,7 +23,8 @@ function execInit(be, action) {
|
||||
}
|
||||
|
||||
function restartService(be) {
|
||||
return execChecked(be.initd, ['restart']);
|
||||
return execChecked(be.initd, ['restart'])
|
||||
.then(function() { return waitForService(be, true, 80); });
|
||||
}
|
||||
|
||||
function rejectIfOtherRunning(be, running) {
|
||||
@@ -59,26 +60,14 @@ function toggleService(be, turnOn) {
|
||||
.then(function() { return execChecked(be.initd, [action]); });
|
||||
}
|
||||
|
||||
function waitForService(be, turnOn, attempts, readyAfter) {
|
||||
function waitForService(be, turnOn, attempts) {
|
||||
return backend.serviceStatus(be.name).then(function(state) {
|
||||
if (!turnOn && !state.running)
|
||||
return state;
|
||||
if (turnOn && state.running)
|
||||
return backend.serviceReady(be, readyAfter, state.pid).then(function(ready) {
|
||||
if (ready) {
|
||||
state.ready = true;
|
||||
return state;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
}).then(function(state) {
|
||||
if (state)
|
||||
if (!!state.running === turnOn)
|
||||
return state;
|
||||
if (attempts <= 0)
|
||||
throw new Error(turnOn ? _('Service did not start in time.') : _('Service did not stop in time.'));
|
||||
return new Promise(function(resolve) { setTimeout(resolve, 250); })
|
||||
.then(function() { return waitForService(be, turnOn, attempts - 1, readyAfter); });
|
||||
.then(function() { return waitForService(be, turnOn, attempts - 1); });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -167,21 +156,6 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
let busy = false;
|
||||
let lastError = '';
|
||||
let refreshGeneration = 0;
|
||||
const boundaryKey = 'daede.ready-boundary.' + window.location.host + '.' + be.name;
|
||||
let readyBoundary = null;
|
||||
try {
|
||||
const savedBoundary = window.localStorage.getItem(boundaryKey);
|
||||
if (savedBoundary !== null && /^\d+$/.test(savedBoundary))
|
||||
readyBoundary = Number(savedBoundary);
|
||||
} catch (e) {}
|
||||
const rememberBoundary = function(offset) {
|
||||
readyBoundary = Number(offset) || 0;
|
||||
try { window.localStorage.setItem(boundaryKey, String(readyBoundary)); } catch (e) {}
|
||||
};
|
||||
const clearBoundary = function() {
|
||||
readyBoundary = null;
|
||||
try { window.localStorage.removeItem(boundaryKey); } catch (e) {}
|
||||
};
|
||||
const body = E('div', { 'id': 'dd-status-body' }, E('em', {}, _('Collecting data…')));
|
||||
const card = E('div', { 'class': 'dd-card dd-status-card' }, [
|
||||
E('h4', { 'class': 'dd-card-title' }, _('Service Status')),
|
||||
@@ -191,10 +165,7 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
const render = function(state) {
|
||||
while (body.firstChild) body.removeChild(body.firstChild);
|
||||
|
||||
const starting = !!state.starting;
|
||||
const badge = starting
|
||||
? E('span', { 'class': 'dd-badge dd-badge-wait' }, [ E('span', { 'class': 'dd-badge-dot' }), _('Starting…') ])
|
||||
: state.running
|
||||
const badge = state.running
|
||||
? E('span', { 'class': 'dd-badge dd-badge-run' }, [ E('span', { 'class': 'dd-badge-dot' }), _('RUNNING') ])
|
||||
: E('span', { 'class': 'dd-badge dd-badge-stop' }, [ E('span', { 'class': 'dd-badge-dot' }), _('STOPPED') ]);
|
||||
|
||||
@@ -206,12 +177,7 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
meta.push(E('span', { 'class': 'dd-meta' }, [ E('span', { 'class': 'dd-meta-label' }, 'PID'), state.pid ]));
|
||||
|
||||
const swErr = E('span', { 'class': 'dd-meta dd-err', 'style': lastError ? '' : 'display:none' }, lastError);
|
||||
const sw = E('button', {
|
||||
'class': 'dd-switch' + (state.running ? ' is-on' : ''),
|
||||
'type': 'button',
|
||||
'aria-label': _('Toggle service'),
|
||||
'disabled': busy ? '' : null
|
||||
}, [
|
||||
const sw = E('button', { 'class': 'dd-switch' + (state.running ? ' is-on' : ''), 'type': 'button', 'aria-label': _('Toggle service') }, [
|
||||
E('span', { 'class': 'dd-switch-knob' })
|
||||
]);
|
||||
sw.addEventListener('click', function(ev) {
|
||||
@@ -219,25 +185,21 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
if (busy) return;
|
||||
refreshGeneration++;
|
||||
busy = true;
|
||||
sw.disabled = true;
|
||||
lastError = '';
|
||||
swErr.style.display = 'none';
|
||||
const turnOn = !state.running;
|
||||
/* Keep process liveness separate from data-plane readiness. The process
|
||||
appears in procd before dae has attached its rules, so show the real
|
||||
transition until the backend's final startup marker is logged. */
|
||||
render({ running: turnOn, pid: 0, starting: turnOn });
|
||||
if (!turnOn)
|
||||
clearBoundary();
|
||||
const boundary = turnOn ? backend.serviceLogOffset(be) : Promise.resolve(0);
|
||||
boundary.then(function(offset) {
|
||||
if (turnOn)
|
||||
rememberBoundary(offset);
|
||||
return toggleService(be, turnOn)
|
||||
.then(function() { return waitForService(be, turnOn, turnOn ? 240 : 40, offset); });
|
||||
})
|
||||
.then(function() {
|
||||
busy = false;
|
||||
clearBoundary();
|
||||
return refresh(true);
|
||||
/* instant optimistic feedback — the start/stop chain (esp. dae's eBPF
|
||||
load) takes a few seconds; flip the switch and show a pending label
|
||||
right away instead of looking frozen */
|
||||
sw.classList.toggle('is-on', turnOn);
|
||||
const lbl = sw.parentNode && sw.parentNode.querySelector('.dd-switch-label');
|
||||
if (lbl) lbl.textContent = '…';
|
||||
toggleService(be, turnOn)
|
||||
.then(function() { return waitForService(be, turnOn, 40); })
|
||||
.then(function() {
|
||||
busy = false;
|
||||
return refresh(true);
|
||||
})
|
||||
.catch(function(e) {
|
||||
busy = false;
|
||||
@@ -252,7 +214,7 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
E('span', { 'class': 'dd-grow' }),
|
||||
swErr,
|
||||
E('span', { 'class': 'dd-switch-wrap' }, [
|
||||
E('span', { 'class': 'dd-switch-label' }, starting ? _('Starting…') : (state.running ? 'ON' : 'OFF')),
|
||||
E('span', { 'class': 'dd-switch-label' }, state.running ? 'ON' : 'OFF'),
|
||||
sw
|
||||
])
|
||||
]);
|
||||
@@ -261,7 +223,7 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
body.appendChild(E('div', { 'class': 'dd-status-meta' }, meta));
|
||||
|
||||
const actions = [];
|
||||
if (be.hasWebUI && state.running && !starting) {
|
||||
if (be.hasWebUI && state.running) {
|
||||
const port = (listenAddr || be.defaultListen).split(':').slice(-1)[0];
|
||||
actions.push(E('a', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
@@ -270,23 +232,19 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
'rel': 'noreferrer noopener'
|
||||
}, _('Open WebUI')));
|
||||
}
|
||||
if (state.running && !starting) {
|
||||
if (state.running) {
|
||||
const restart = E('button', { 'class': 'cbi-button cbi-button-positive' }, _('Restart'));
|
||||
restart.addEventListener('click', function(ev) {
|
||||
ev.preventDefault();
|
||||
if (busy) return;
|
||||
busy = true;
|
||||
restart.disabled = true;
|
||||
lastError = '';
|
||||
render({ running: true, pid: 0, starting: true });
|
||||
backend.serviceLogOffset(be).then(function(offset) {
|
||||
rememberBoundary(offset);
|
||||
return restartService(be)
|
||||
.then(function() { return waitForService(be, true, 240, offset); });
|
||||
})
|
||||
.then(function() {
|
||||
busy = false;
|
||||
clearBoundary();
|
||||
return refresh(true);
|
||||
swErr.style.display = 'none';
|
||||
restartService(be)
|
||||
.then(function() {
|
||||
busy = false;
|
||||
return refresh(true);
|
||||
})
|
||||
.catch(function(e) {
|
||||
busy = false;
|
||||
@@ -296,7 +254,7 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
});
|
||||
actions.push(restart);
|
||||
}
|
||||
if (state.running && !starting && be.name === 'dae') {
|
||||
if (state.running && be.name === 'dae') {
|
||||
const hot = E('button', { 'class': 'cbi-button cbi-button-action' }, _('Hot Reload'));
|
||||
hot.addEventListener('click', function(ev) {
|
||||
ev.preventDefault();
|
||||
@@ -305,7 +263,7 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
});
|
||||
actions.push(hot);
|
||||
}
|
||||
if (state.running && !starting && be.name === 'dae') {
|
||||
if (state.running && be.name === 'dae') {
|
||||
const ckBtn = E('button', { 'class': 'cbi-button cbi-button-action' }, _('Test YouTube'));
|
||||
const ckRes = E('span', { 'class': 'dd-meta', style: 'margin-left:8px;display:none' }, '');
|
||||
ckBtn.addEventListener('click', function(ev) {
|
||||
@@ -350,18 +308,7 @@ function renderStatusCard(ctx, listenAddr) {
|
||||
const generation = refreshGeneration;
|
||||
return backend.serviceStatus(be.name).then(function(state) {
|
||||
if (generation !== refreshGeneration || (busy && !force)) return;
|
||||
if (!state.running) {
|
||||
clearBoundary();
|
||||
render(state);
|
||||
return;
|
||||
}
|
||||
return backend.serviceReady(be, readyBoundary, state.pid).then(function(ready) {
|
||||
if (generation !== refreshGeneration || (busy && !force)) return;
|
||||
state.starting = !ready;
|
||||
if (ready)
|
||||
clearBoundary();
|
||||
render(state);
|
||||
});
|
||||
render(state);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
"/etc/dae/example.dae": [ "read" ],
|
||||
"/var/log/dae/dae.log": [ "read" ],
|
||||
"/var/log/daed/daed.log": [ "read" ],
|
||||
"/var/run/daede-dae.ready": [ "read" ],
|
||||
"/var/run/daede-daed.ready": [ "read" ],
|
||||
"/usr/share/v2ray/geoip.dat": [ "read" ],
|
||||
"/usr/share/v2ray/geosite.dat": [ "read" ],
|
||||
"/sys/kernel/btf/vmlinux": [ "read" ],
|
||||
|
||||
Reference in New Issue
Block a user