mirror of
https://github.com/kenzok8/small-package.git
synced 2026-02-05 06:17:38 +08:00
update 2025-10-26 04:24:05
This commit is contained in:
@@ -7,8 +7,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-ddns-go
|
||||
PKG_VERSION:=1.5.4
|
||||
PKG_RELEASE:=20250601
|
||||
PKG_VERSION:=1.6.3
|
||||
PKG_RELEASE:=20251025
|
||||
|
||||
PKG_MAINTAINER:=sirpdboy <herboy2008@gmail.com>
|
||||
PKG_CONFIG_DEPENDS:=
|
||||
|
||||
@@ -6,9 +6,21 @@
|
||||
'require uci';
|
||||
'require form';
|
||||
'require poll';
|
||||
'require rpc';
|
||||
|
||||
const getDDNSGoInfo = rpc.declare({
|
||||
object: 'luci.ddns-go',
|
||||
method: 'get_ver',
|
||||
expect: { 'ver': {} }
|
||||
});
|
||||
|
||||
async function checkProcess() {
|
||||
const getUpdateInfo = rpc.declare({
|
||||
object: 'luci.ddns-go',
|
||||
method: 'last_update',
|
||||
expect: { 'update': {} }
|
||||
});
|
||||
|
||||
async function checkProcess() {
|
||||
// 先尝试用 pidof
|
||||
try {
|
||||
const pidofRes = await fs.exec('/bin/pidof', ['ddns-go']);
|
||||
@@ -21,8 +33,6 @@
|
||||
} catch (err) {
|
||||
// pidof 失败,继续尝试 ps
|
||||
}
|
||||
|
||||
// 回退到 ps
|
||||
try {
|
||||
const psRes = await fs.exec('/bin/ps', ['-C', 'ddns-go', '-o', 'pid=']);
|
||||
const pid = psRes.stdout.trim();
|
||||
@@ -33,29 +43,70 @@
|
||||
} catch (err) {
|
||||
return { running: false, pid: null };
|
||||
}
|
||||
}
|
||||
function renderStatus(isRunning, listen_port, noweb) {
|
||||
}
|
||||
|
||||
function getVersionInfo() {
|
||||
return L.resolveDefault(getDDNSGoInfo(), {}).then(function(result) {
|
||||
//console.log('getVersionInfo result:', result);
|
||||
return result || {};
|
||||
}).catch(function(error) {
|
||||
console.error('Failed to get version:', error);
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
function checkUpdateStatus() {
|
||||
return L.resolveDefault(getUpdateInfo(), {}).then(function(result) {
|
||||
//console.log('checkUpdateStatus result:', result);
|
||||
return result || {};
|
||||
}).catch(function(error) {
|
||||
console.error('Failed to get update info:', error);
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
function renderStatus(isRunning, listen_port, noweb, version) {
|
||||
var statusText = isRunning ? _('RUNNING') : _('NOT RUNNING');
|
||||
var color = isRunning ? 'green' : 'red';
|
||||
var icon = isRunning ? '✓' : '✗';
|
||||
var versionText = version ? `v${version}` : '';
|
||||
|
||||
var html = String.format(
|
||||
'<em><span style="color:%s">%s <strong>%s %s</strong></span></em>',
|
||||
color, icon, _('DDNS-Go'), statusText
|
||||
'<em><span style="color:%s">%s <strong>%s %s - %s</strong></span></em>',
|
||||
color, icon, _('DDNS-Go'), versionText, statusText
|
||||
);
|
||||
|
||||
if (isRunning && res.pid) {
|
||||
html += ' <small>(PID: ' + res.pid + ')</small>';
|
||||
if (isRunning) {
|
||||
html += String.format(' <a class="btn cbi-button" href="%s//%s:%s" target="_blank">%s</a>',
|
||||
window.location.protocol, window.location.hostname, listen_port, _('Open Web Interface'));
|
||||
}
|
||||
|
||||
if (isRunning && noweb !== '1') {
|
||||
const baseUrl = `${window.location.protocol}//${window.location.hostname}`;
|
||||
const fullUrl = `${baseUrl}:${listen_port}`;
|
||||
html += String.format(' <a class="btn cbi-button" href="%s" target="_blank">%s</a>', fullUrl, _('Open Web Interface'));
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderUpdateStatus(updateInfo) {
|
||||
if (!updateInfo || !updateInfo.status) {
|
||||
return '<span style="color:orange"> ⚠ ' + _('Update status unknown') + '</span>';
|
||||
}
|
||||
|
||||
var status = updateInfo.status;
|
||||
var message = updateInfo.message || '';
|
||||
|
||||
switch(status) {
|
||||
case 'updated':
|
||||
return String.format('<span style="color:green">✓ %s</span>', message);
|
||||
case 'update_available':
|
||||
return String.format('<span style="color:blue">↻ %s</span>', message);
|
||||
case 'latest':
|
||||
return String.format('<span style="color:green">✓ %s</span>', message);
|
||||
case 'download_failed':
|
||||
case 'check_failed':
|
||||
return String.format('<span style="color:red">✗ %s</span>', message);
|
||||
default:
|
||||
return String.format('<span style="color:orange">? %s</span>', message);
|
||||
}
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
@@ -63,6 +114,118 @@ return view.extend({
|
||||
]);
|
||||
},
|
||||
|
||||
handleResetPassword: async function () {
|
||||
try {
|
||||
ui.showModal(_('Resetting Password'), [
|
||||
E('p', { 'class': 'spinning' }, _('Resetting admin password, please wait...'))
|
||||
]);
|
||||
|
||||
const result = await fs.exec('/usr/bin/ddns-go', ['-resetPassword', 'admin12345', '-c', '/etc/ddns-go/ddns-go-config.yaml']);
|
||||
|
||||
ui.hideModal();
|
||||
|
||||
const output = (result.stdout + result.stderr).trim();
|
||||
|
||||
let success = false;
|
||||
let message = '';
|
||||
|
||||
if (result.code === 0) {
|
||||
|
||||
|
||||
message = _('Password reset successfully to admin12345');
|
||||
|
||||
ui.showModal(_('Password Reset Successful'), [
|
||||
E('p', _('Admin password has been reset to: admin12345')),
|
||||
E('p', _('You need to restart DDNS-Go service for the changes to take effect.')),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-positive',
|
||||
'click': ui.createHandlerFn(this, function() {
|
||||
ui.hideModal();
|
||||
this.handleRestartService();
|
||||
})
|
||||
}, _('Restart Service Now')),
|
||||
' ',
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-neutral',
|
||||
'click': ui.hideModal
|
||||
}, _('Restart Later'))
|
||||
])
|
||||
]);
|
||||
} else {
|
||||
alert(_('Reset may have failed:') + '\n' + output);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
ui.hideModal();
|
||||
console.error('Reset password failed:', error);
|
||||
alert(_('ERROR:') + '\n' + _('Reset password failed:') + '\n' + error.message);
|
||||
}
|
||||
},
|
||||
|
||||
handleRestartService: async function() {
|
||||
try {
|
||||
await fs.exec('/etc/init.d/ddns-go', ['stop']);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
await fs.exec('/etc/init.d/ddns-go', ['start']);
|
||||
|
||||
alert(_('SUCCESS:') + '\n' + _('DDNS-Go service restarted successfully'));
|
||||
if (window.statusPoll) {
|
||||
window.statusPoll();
|
||||
}
|
||||
} catch (error) {
|
||||
alert(_('ERROR:') + '\n' + _('Failed to restart service:') + '\n' + error.message);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
handleUpdate: async function () {
|
||||
try {
|
||||
var updateView = document.getElementById('update_status');
|
||||
if (updateView) {
|
||||
updateView.innerHTML = '<span class="spinning"></span> ' + _('Updating, please wait...');
|
||||
}
|
||||
const updateInfo = await checkUpdateStatus();
|
||||
if (updateView) {
|
||||
updateView.innerHTML = renderUpdateStatus(updateInfo);
|
||||
}
|
||||
|
||||
if (updateInfo.update_successful || updateInfo.status === 'updated') {
|
||||
if (window.statusPoll) {
|
||||
window.statusPoll();
|
||||
}
|
||||
|
||||
// 3秒后恢复显示版本信息
|
||||
setTimeout(() => {
|
||||
var updateView = document.getElementById('update_status');
|
||||
if (updateView) {
|
||||
getVersionInfo().then(function(versionInfo) {
|
||||
var version = versionInfo.version || '';
|
||||
updateView.innerHTML = String.format('<span style="color:green">✓ %s v%s</span>',
|
||||
_('Current Version:'), version);
|
||||
});
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Update failed:', error);
|
||||
var updateView = document.getElementById('update_status');
|
||||
if (updateView) {
|
||||
updateView.innerHTML = '<span style="color:red">✗ ' + _('Update failed') + '</span>';
|
||||
|
||||
// 5秒后恢复显示版本信息
|
||||
setTimeout(() => {
|
||||
getVersionInfo().then(function(versionInfo) {
|
||||
var version = versionInfo.version || '';
|
||||
updateView.innerHTML = String.format('<span>%s v%s</span>',
|
||||
_('Current Version:'), version);
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var m, s, o;
|
||||
var listen_port = (uci.get('ddns-go', 'config', 'port') || '[::]:9876').split(':').slice(-1)[0];
|
||||
@@ -74,20 +237,27 @@ return view.extend({
|
||||
// 状态显示部分
|
||||
s = m.section(form.TypedSection);
|
||||
s.anonymous = true;
|
||||
|
||||
s.render = function() {
|
||||
var statusView = E('p', { id: 'control_status' },
|
||||
'<span class="spinning"></span> ' + _('Checking status...'));
|
||||
|
||||
var pollInterval = poll.add(function() {
|
||||
return checkProcess()
|
||||
.then(function(res) {
|
||||
statusView.innerHTML = renderStatus(res.running, listen_port, noweb);
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error('Status check failed:', err);
|
||||
statusView.innerHTML = '<span style="color:orange">⚠ ' + _('Status check error') + '</span>';
|
||||
});
|
||||
}, 5); // 每5秒检查一次
|
||||
|
||||
window.statusPoll = function() {
|
||||
return Promise.all([
|
||||
checkProcess(),
|
||||
getVersionInfo()
|
||||
]).then(function(results) {
|
||||
var [processInfo, versionInfo] = results;
|
||||
var version = versionInfo.version || '';
|
||||
statusView.innerHTML = renderStatus(processInfo.running, listen_port, noweb, version);
|
||||
}).catch(function(err) {
|
||||
console.error('Status check failed:', err);
|
||||
statusView.innerHTML = '<span style="color:orange">⚠ ' + _('Status check error') + '</span>';
|
||||
});
|
||||
};
|
||||
|
||||
var pollInterval = poll.add(window.statusPoll, 5); // 每5秒检查一次
|
||||
|
||||
return E('div', { class: 'cbi-section', id: 'status_bar' }, [
|
||||
statusView,
|
||||
@@ -102,44 +272,73 @@ return view.extend({
|
||||
])
|
||||
])
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
s = m.section(form.NamedSection, 'config', 'basic');
|
||||
|
||||
s = m.section(form.NamedSection, 'config', 'basic');
|
||||
o = s.option(form.Flag, 'enabled', _('Enable'));
|
||||
o.default = o.disabled;
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Enable'));
|
||||
o.default = o.disabled;
|
||||
o.rmempty = false;
|
||||
o = s.option(form.Value, 'port', _('Listen port'));
|
||||
o.default = '[::]:9876';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Value, 'port', _('Listen port'));
|
||||
o.default = '[::]:9876';
|
||||
o.rmempty = false;
|
||||
o = s.option(form.Value, 'time', _('Update interval'));
|
||||
o.default = '300';
|
||||
|
||||
o = s.option(form.Value, 'time', _('Update interval'));
|
||||
o.default = '300';
|
||||
o = s.option(form.Value, 'ctimes', _('Compare with service provider N times intervals'));
|
||||
o.default = '5';
|
||||
|
||||
o = s.option(form.Value, 'ctimes', _('Compare with service provider N times intervals'));
|
||||
o.default = '5';
|
||||
o = s.option(form.Value, 'skipverify', _('Skip verifying certificates'));
|
||||
o.default = '0';
|
||||
|
||||
o = s.option(form.Value, 'skipverify', _('Skip verifying certificates'));
|
||||
o.default = '0';
|
||||
o = s.option(form.Value, 'dns', _('Specify DNS resolution server'));
|
||||
o.value('223.5.5.5', _('Ali DNS 223.5.5.5'));
|
||||
o.value('223.6.6.6', _('Ali DNS 223.6.6.6'));
|
||||
o.value('119.29.29.29', _('Tencent DNS 119.29.29.29'));
|
||||
o.value('1.1.1.1', _('CloudFlare DNS 1.1.1.1'));
|
||||
o.value('8.8.8.8', _('Google DNS 8.8.8.8'));
|
||||
o.value('8.8.4.4', _('Google DNS 8.8.4.4'));
|
||||
o.datatype = 'ipaddr';
|
||||
|
||||
o = s.option(form.Value, 'dns', _('Specify DNS resolution server'));
|
||||
o.value('223.5.5.5', _('Ali DNS 223.5.5.5'));
|
||||
o.value('223.6.6.6', _('Ali DNS 223.6.6.6'));
|
||||
o.value('119.29.29.29', _('Tencent DNS 119.29.29.29'));
|
||||
o.value('1.1.1.1', _('CloudFlare DNS 1.1.1.1'));
|
||||
o.value('8.8.8.8', _('Google DNS 8.8.8.8'));
|
||||
o.value('8.8.4.4', _('Google DNS 8.8.4.4'));
|
||||
o.datatype = 'ipaddr';
|
||||
o = s.option(form.Flag, 'noweb', _('Do not start web services'));
|
||||
o.default = '0';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Flag, 'noweb', _('Do not start web services'));
|
||||
o.default = '0';
|
||||
o.rmempty = false;
|
||||
o = s.option(form.Value, 'delay', _('Delayed Start (seconds)'));
|
||||
o.default = '60';
|
||||
|
||||
o = s.option(form.Value, 'delay', _('Delayed Start (seconds)'));
|
||||
o.default = '60';
|
||||
o = s.option(form.Button, '_newpassword', _('Reset account password'));
|
||||
o.inputtitle = _('ResetPassword');
|
||||
o.inputstyle = 'apply';
|
||||
o.onclick = L.bind(this.handleResetPassword, this, data);
|
||||
|
||||
return m.render();
|
||||
}
|
||||
o = s.option(form.DummyValue, '_update_status', _('Current Version'));
|
||||
o.rawhtml = true;
|
||||
var currentVersion = '';
|
||||
|
||||
getVersionInfo().then(function(versionInfo) {
|
||||
currentVersion = versionInfo.version || '';
|
||||
var updateView = document.getElementById('update_status');
|
||||
if (updateView) {
|
||||
updateView.innerHTML = String.format('<span>v%s</span>', currentVersion);
|
||||
}
|
||||
});
|
||||
|
||||
o.cfgvalue = function() {
|
||||
return E('div', { style: 'margin: 5px 0;' }, [
|
||||
E('span', { id: 'update_status' },
|
||||
currentVersion ? String.format('v%s', currentVersion) : _('Loading...'))
|
||||
]);
|
||||
};
|
||||
|
||||
o = s.option(form.Button, '_update', _('Update kernel'),
|
||||
_('Check and update DDNS-Go to the latest version'));
|
||||
o.inputtitle = _('Check Update');
|
||||
o.inputstyle = 'apply';
|
||||
o.onclick = L.bind(this.handleUpdate, this, data);
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
@@ -43,7 +43,7 @@ msgstr ""
|
||||
msgid "DDNS-GO Service Not Running"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please enable the DDNS-GO service"
|
||||
msgid "DDNS-GO Web Interface Disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open Web Interface"
|
||||
@@ -72,3 +72,51 @@ msgstr ""
|
||||
|
||||
msgid "Delayed Start (seconds)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update kernel"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check and update DDNS-Go to the latest version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check Update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Updating, please wait..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Update failed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update status unknown"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset account password"
|
||||
msgstr ""
|
||||
|
||||
msgid "ResetPassword"
|
||||
msgstr ""
|
||||
|
||||
msgid "SUCCESS:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Password reset successfully to admin12345"
|
||||
msgstr ""
|
||||
|
||||
msgid "Password Reset Successful"
|
||||
msgstr ""
|
||||
|
||||
msgid "User password has been reset to: admin12345"
|
||||
msgstr ""
|
||||
|
||||
msgid "You need to restart DDNS-Go service for the changes to take effect."
|
||||
msgstr ""
|
||||
|
||||
msgid "Restart Service Now"
|
||||
msgstr ""
|
||||
|
||||
msgid "Restart Later"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
@@ -20,7 +20,7 @@ msgid "DDNS-GO Control panel"
|
||||
msgstr "DDNS-GO操作台"
|
||||
|
||||
msgid "Open Web Interface"
|
||||
msgstr "打开 Web 界面"
|
||||
msgstr "打开Web界面"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "日志"
|
||||
@@ -72,3 +72,51 @@ msgstr "不启动web服务"
|
||||
|
||||
msgid "Delayed Start (seconds)"
|
||||
msgstr "开机延时启动(秒)"
|
||||
|
||||
msgid "Update kernel"
|
||||
msgstr "更新内核"
|
||||
|
||||
msgid "Check and update DDNS-Go to the latest version"
|
||||
msgstr "更新DDNS-Go到最新版本"
|
||||
|
||||
msgid "Check Update"
|
||||
msgstr "检查更新"
|
||||
|
||||
msgid "Updating, please wait..."
|
||||
msgstr "更新中,请稍等..."
|
||||
|
||||
msgid "Update failed"
|
||||
msgstr "更新失败"
|
||||
|
||||
msgid "Update status unknown"
|
||||
msgstr "更新状态未知"
|
||||
|
||||
msgid "Reset account password"
|
||||
msgstr "重置登录密码"
|
||||
|
||||
msgid "ResetPassword"
|
||||
msgstr "重置密码"
|
||||
|
||||
msgid "SUCCESS:"
|
||||
msgstr "完成执行:"
|
||||
|
||||
msgid "Password reset successfully to admin12345"
|
||||
msgstr "成功重置密码admin12345"
|
||||
|
||||
msgid "Password Reset Successful"
|
||||
msgstr "重置密码成功"
|
||||
|
||||
msgid "User password has been reset to: admin12345"
|
||||
msgstr "用户密码重置为admin12345"
|
||||
|
||||
msgid "You need to restart DDNS-Go service for the changes to take effect."
|
||||
msgstr "需要重启DDNS-GO服务更改才生效"
|
||||
|
||||
msgid "Restart Service Now"
|
||||
msgstr "立刻重启服务"
|
||||
|
||||
msgid "Restart Later"
|
||||
msgstr "稍后重启"
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
{
|
||||
"luci-app-ddns-go": {
|
||||
"luci-app-ddns-go": {
|
||||
"description": "Grant UCI access for luci-app-ddns-go",
|
||||
"read": {
|
||||
"file": {
|
||||
"read": {
|
||||
"uci": [ "ddns-go" ],
|
||||
"file": {
|
||||
"/etc/init.d/ddns-go": [ "exec" ],
|
||||
"/usr/libexec/ddns-go-call": [ "exec" ],
|
||||
"/usr/share/rpcd/ucode/luci.ddns-go": [ "exec" ],
|
||||
"/bin/pidof": [ "exec" ],
|
||||
"/bin/ps": [ "exec" ],
|
||||
"/bin/ash": [ "exec" ],
|
||||
"/etc/ddns-go/ddns-go-config.yaml": [ "read" ],
|
||||
"/var/log/ddns-go.log": [ "read" ]
|
||||
},
|
||||
"ubus": {
|
||||
"service": [ "list" ]
|
||||
},
|
||||
"uci": [ "ddns-go" ,"ddns-go" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "ddns-go" ,"ddns-go" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ubus": {
|
||||
"rc": [ "*" ],
|
||||
"service": ["list"],
|
||||
"luci.ddns-go": [ "*" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.ddns-go": [ "*" ]
|
||||
},
|
||||
"file": {
|
||||
"/etc/ddns-go/ddns-go-config.yaml": ["write"]
|
||||
},
|
||||
"uci": ["ddns-go"]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
135
luci-app-ddns-go/root/usr/share/rpcd/ucode/luci.ddns-go
Normal file
135
luci-app-ddns-go/root/usr/share/rpcd/ucode/luci.ddns-go
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/ucode
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2021-2025 sirpdboy <herboy2008@gmail.com> https://github.com/sirpdboy/luci-app-ddns-go
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { access, error, lstat, popen, readfile, writefile } from 'fs';
|
||||
|
||||
/* Kanged from ucode/luci */
|
||||
function shellquote(s) {
|
||||
return `'${replace(s, "'", "'\\''")}'`;
|
||||
}
|
||||
function get_current_version() {
|
||||
if (!access('/usr/bin/ddns-go'))
|
||||
return null;
|
||||
|
||||
const fd = popen('/usr/bin/ddns-go -v');
|
||||
if (fd) {
|
||||
let version_output = fd.read('all');
|
||||
fd.close();
|
||||
|
||||
if (!version_output || length(version_output) === 0)
|
||||
return null;
|
||||
|
||||
try {
|
||||
// 去除开头的 'v' 字符
|
||||
version_output = replace(trim(version_output), /^v/, '');
|
||||
return version_output;
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const methods = {
|
||||
get_ver: {
|
||||
call: function() {
|
||||
let current_version = get_current_version();
|
||||
if (!current_version)
|
||||
return { ver: {}, error: 'ddns-go not found or version check failed' };
|
||||
|
||||
return { ver: { version: current_version } };
|
||||
}
|
||||
},
|
||||
|
||||
last_update: {
|
||||
call: function() {
|
||||
if (!access('/usr/bin/ddns-go'))
|
||||
return { update: {}, error: 'ddns-go not found' };
|
||||
let version_before = get_current_version();
|
||||
|
||||
const fd = popen('/usr/bin/ddns-go -u');
|
||||
if (fd) {
|
||||
let output = fd.read('all');
|
||||
fd.close();
|
||||
|
||||
if (!output || length(output) === 0)
|
||||
return { update: {}, error: 'empty response' };
|
||||
|
||||
try {
|
||||
output = trim(output);
|
||||
let update_info = {
|
||||
raw_output: output,
|
||||
version_before: version_before,
|
||||
version_after: null,
|
||||
has_update: false,
|
||||
update_successful: false,
|
||||
current_version: '',
|
||||
latest_version: '',
|
||||
status: 'unknown',
|
||||
message: output
|
||||
};
|
||||
|
||||
update_info.version_after = get_current_version();
|
||||
|
||||
if (version_before && update_info.version_after && version_before !== update_info.version_after) {
|
||||
update_info.update_successful = true;
|
||||
update_info.has_update = false; // 已经更新完成,所以没有待更新了
|
||||
update_info.status = 'updated';
|
||||
update_info.message = `更新成功: ${version_before} → ${update_info.version_after}`;
|
||||
}
|
||||
else if (match(output, /Current version.*is the latest/)) {
|
||||
update_info.status = 'latest';
|
||||
update_info.has_update = false;
|
||||
let version_match = match(output, /v[\d.]+/);
|
||||
if (version_match) {
|
||||
update_info.current_version = replace(version_match[0], /^v/, '');
|
||||
update_info.latest_version = update_info.current_version;
|
||||
}
|
||||
update_info.message = '已是最新版本 ' + (update_info.current_version || '');
|
||||
|
||||
} else if (match(output, /new version.*available/)) {
|
||||
update_info.status = 'update_available';
|
||||
update_info.has_update = true;
|
||||
|
||||
let versions = match(output, /v[\d.]+/, 'g');
|
||||
if (versions && length(versions) >= 2) {
|
||||
update_info.current_version = replace(versions[0], /^v/, '');
|
||||
update_info.latest_version = replace(versions[1], /^v/, '');
|
||||
} else if (version_before) {
|
||||
update_info.current_version = version_before;
|
||||
}
|
||||
update_info.message = '有新版本可用: ' + (update_info.latest_version || '');
|
||||
|
||||
} else if (match(output, /download.*failed/)) {
|
||||
update_info.status = 'download_failed';
|
||||
update_info.has_update = false;
|
||||
update_info.message = '下载更新失败';
|
||||
|
||||
} else if (match(output, /check.*failed/)) {
|
||||
update_info.status = 'check_failed';
|
||||
update_info.has_update = false;
|
||||
update_info.message = '检查更新失败';
|
||||
|
||||
} else {
|
||||
update_info.status = 'unknown';
|
||||
update_info.message = output;
|
||||
}
|
||||
|
||||
return { update: update_info };
|
||||
} catch(e) {
|
||||
return { update: {}, error: 'Parse error: ' + e };
|
||||
}
|
||||
} else {
|
||||
return { update: {}, error: 'failed to execute ddns-go command' };
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { 'luci.ddns-go': methods };
|
||||
Reference in New Issue
Block a user