mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-10-26 20:22:51 +08:00
update 2026-10-07 18:47:42
This commit is contained in:
1 parent
617f7ca2a6
commit
bd061545ed
4832 files changed
+1693456
No files matched your search
@@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#
|
||||
# Copyright (C) 2021-2026 sirpdboy <herboy2008@gmail.com> https://github.com/sirpdboy/luci-app-lucky
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-lucky
|
||||
PKG_VERSION:=3.0.3
|
||||
PKG_RELEASE:=15
|
||||
|
||||
LUCI_TITLE:=LuCI Support for Dynamic lucky Client
|
||||
LUCI_DEPENDS:=+lucky
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@@ -0,0 +1,192 @@
|
||||
// Copyright (C) 2021-2026 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-lucky
|
||||
|
||||
'use strict';
|
||||
'require form';
|
||||
'require poll';
|
||||
'require rpc';
|
||||
'require uci';
|
||||
'require ui';
|
||||
'require view';
|
||||
'require fs';
|
||||
|
||||
async function checkProcess() {
|
||||
try {
|
||||
const pidofRes = await fs.exec('/bin/pidof', ['lucky']);
|
||||
if (pidofRes.code === 0) {
|
||||
return {
|
||||
running: true,
|
||||
pid: pidofRes.stdout.trim()
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
try {
|
||||
const psRes = await fs.exec('/bin/ps', ['-C', 'lucky', '-o', 'pid=']);
|
||||
const pid = psRes.stdout.trim();
|
||||
return {
|
||||
running: pid !== '',
|
||||
pid: pid || null
|
||||
};
|
||||
} catch (err) {
|
||||
return { running: false, pid: null };
|
||||
}
|
||||
}
|
||||
|
||||
const getLuckyConfig = rpc.declare({
|
||||
object: 'luci.lucky',
|
||||
method: 'get_Info',
|
||||
expect: { 'Info': {} }
|
||||
});
|
||||
|
||||
function getServiceStatus() {
|
||||
return L.resolveDefault(checkProcess(), {}).then(function(res) {
|
||||
let isRunning = false;
|
||||
try {
|
||||
if (res && res.running) {
|
||||
isRunning = true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Service status error:', e);
|
||||
}
|
||||
return isRunning;
|
||||
}).catch(function(error) {
|
||||
console.error('Service status check failed:', error);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function loadLuckyVer() {
|
||||
return L.resolveDefault(getLuckyConfig(), {}).then(function(result) {
|
||||
// console.debug('loadLuckyVer');
|
||||
return result.Version || 'Unknown';
|
||||
});
|
||||
}
|
||||
|
||||
function renderStatus(isRunning, webport, safe_url, protocol, version) {
|
||||
let statusText = isRunning ? _('RUNNING') : _('NOT RUNNING');
|
||||
let color = isRunning ? 'green' : 'red';
|
||||
let icon = isRunning ? '✓' : '✗';
|
||||
let html = String.format(
|
||||
'<em><span style="color:%s">%s <strong>%s %s - %s</strong></span></em>',
|
||||
color, icon, _('Lucky'), version, statusText
|
||||
);
|
||||
|
||||
if (isRunning) {
|
||||
let buttonUrl = String.format('%s//%s:%s/', protocol, window.location.hostname, webport);
|
||||
|
||||
if (safe_url && safe_url.trim() !== '') {
|
||||
buttonUrl = String.format('%s%s/', buttonUrl, safe_url);
|
||||
}
|
||||
|
||||
html += String.format(
|
||||
'<input class="cbi-button cbi-button-reload" type="button" style="margin-left: 20px" value="%s" onclick="window.open(\'%s\')">',
|
||||
_('Open Web Interface'),
|
||||
buttonUrl
|
||||
);
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
uci.load('lucky')
|
||||
]);
|
||||
},
|
||||
|
||||
handleResetUser: async function () {
|
||||
try {
|
||||
// 检查文件权限
|
||||
const stat = await fs.stat('/usr/bin/lucky');
|
||||
const result = await fs.exec('/usr/bin/lucky', ['-rResetUser', '-cd', '/etc/lucky']);
|
||||
if (result.code === 0) {
|
||||
alert(_('SUCCESS:') + '\n' + _('Username and password reset successfully to 666'));
|
||||
}
|
||||
} catch (error) { }
|
||||
},
|
||||
render: function(data) {
|
||||
let m, s, o;
|
||||
let webport = uci.get('lucky', 'lucky', 'port') || '16601';
|
||||
let safeurl = uci.get('lucky', 'lucky', 'safe') || '';
|
||||
let uci_ssl = uci.get('lucky', 'lucky', 'ssl') || '0';
|
||||
let protocol = uci_ssl === '1' ? 'https:' : 'http:';
|
||||
|
||||
m = new form.Map('lucky', _('Lucky'),
|
||||
_('ipv4/ipv6 portforward,ddns,reverseproxy proxy,wake on lan,IOT and more,Default username and password 666'));
|
||||
|
||||
// 状态显示部分
|
||||
s = m.section(form.TypedSection);
|
||||
s.anonymous = true;
|
||||
s.addremove = false;
|
||||
|
||||
s.render = function() {
|
||||
poll.add(function() {
|
||||
return Promise.all([
|
||||
L.resolveDefault(getServiceStatus()),
|
||||
L.resolveDefault(loadLuckyVer())
|
||||
]).then(function(results) {
|
||||
const [isRunning, version] = results;
|
||||
var view = document.getElementById('service_status');
|
||||
if (view) {
|
||||
view.innerHTML = renderStatus(isRunning, webport, safeurl, protocol, version);
|
||||
}
|
||||
}).catch(function(error) {
|
||||
console.error('Poll error:', error);
|
||||
});
|
||||
}, 5); // 添加轮询间隔5秒
|
||||
|
||||
return E('div', { class: 'cbi-section', id: 'status_bar' }, [
|
||||
E('div', { id: 'service_status' },
|
||||
E('p', {}, _('Collecting data...'))
|
||||
),
|
||||
E('div', { 'style': 'text-align: right; font-style: italic;' }, [
|
||||
E('span', {}, [
|
||||
_('© github '),
|
||||
E('a', {
|
||||
'href': 'https://github.com/sirpdboy',
|
||||
'target': '_blank',
|
||||
'style': 'text-decoration: none;'
|
||||
}, 'by sirpdboy')
|
||||
])
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
s = m.section(form.NamedSection, 'lucky', 'lucky');
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Enable'));
|
||||
o.default = o.disabled;
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Value, 'port', _('Set the Lucky access port'));
|
||||
o.default = '16601';
|
||||
o.rmempty = false;
|
||||
o.datatype = 'port';
|
||||
o.validate = function(section_id, value) {
|
||||
if (value < 1 || value > 65535) {
|
||||
return _('Port must be between 1 and 65535');
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
o = s.option(form.Value, 'safe', _('Safe entrance'),_('Set an installation access path, eg:sirpdboy'));
|
||||
o.default = '';
|
||||
o.datatype = 'string';
|
||||
|
||||
o = s.option(form.Flag, 'ssl', _('Enable SSL'),_('Encrypt access using HTTPS'));
|
||||
o.default = '0';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Value, 'delay', _('Delayed Start (seconds)'));
|
||||
o.default = '60';
|
||||
|
||||
o = s.option(form.Button, '_newpassword', _('ResetUser'),
|
||||
_('Reset account and password to initial values'));
|
||||
o.inputtitle = _('ResetUser');
|
||||
o.inputstyle = 'apply';
|
||||
o.onclick = L.bind(this.handleResetUser, this, data);
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
// 版权 Copyright (C) 2021-2026 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-lucky
|
||||
|
||||
'use strict';
|
||||
'require view';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require uci';
|
||||
'require form';
|
||||
'require poll';
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return uci.load('lucky');
|
||||
},
|
||||
|
||||
checkRunning: function() {
|
||||
return fs.exec('/bin/pidof', ['lucky']).then(function(pidRes) {
|
||||
if (pidRes.code === 0) return { isRunning: true };
|
||||
return fs.exec('/bin/ash', ['-c', 'ps | grep -q "[l]ucky"']).then(function(grepRes) {
|
||||
return { isRunning: grepRes.code === 0 };
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
|
||||
return this.checkRunning().then(function(checkResult) {
|
||||
var isRunning = checkResult.isRunning;
|
||||
let webport = uci.get('lucky', 'lucky', 'port') || '16601';
|
||||
let safe_url = uci.get('lucky', 'lucky', 'safe') || '';
|
||||
let uci_ssl = uci.get('lucky', 'lucky', 'ssl') || '0';
|
||||
let protocol = uci_ssl === '1' ? 'https:' : 'http:';
|
||||
let buttonUrl = String.format('%s//%s:%s/', protocol, window.location.hostname, webport);
|
||||
if (safe_url && safe_url.trim() !== '') {
|
||||
buttonUrl = String.format('%s%s/', buttonUrl, safe_url);
|
||||
}
|
||||
var container = E('div');
|
||||
if (!isRunning ) {
|
||||
var message = _('Lucky Service Not Running');
|
||||
|
||||
|
||||
container.appendChild(E('div', {
|
||||
style: 'text-align: center; padding: 2em;'
|
||||
}, [
|
||||
E('img', {
|
||||
src: 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMjQiIGhlaWdodD0iMTAyNCIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCI+PHBhdGggZmlsbD0iI2RmMDAwMCIgZD0iTTk0Mi40MjEgMjM0LjYyNGw4MC44MTEtODAuODExLTE1My4wNDUtMTUzLjA0NS04MC44MTEgODAuODExYy03OS45NTctNTEuNjI3LTE3NS4xNDctODEuNTc5LTI3Ny4zNzYtODEuNTc5LTI4Mi43NTIgMC01MTIgMjI5LjI0OC01MTIgNTEyIDAgMTAyLjIyOSAyOS45NTIgMTk3LjQxOSA4MS41NzkgMjc3LjM3NmwtODAuODExIDgwLjgxMSAxNTMuMDQ1IDE1My4wNDUgODAuODExLTgwLjgxMWM3OS45NTcgNTEuNjI3IDE3NS4xNDcgODEuNTc5IDI3Ny4zNzYgODEuNTc5IDI4Mi43NTIgMCA1MTItMjI5LjI0OCA1MTItNTEyIDAtMTAyLjIyOS0yOS45NTItMTk3LjQxOS04MS41NzktMjc3LjM3NnpNMTk0Ljk0NCA1MTJjMC0xNzUuMTA0IDE0MS45NTItMzE3LjA1NiAzMTcuMDU2LTMxNy4wNTYgNDggMCA5My40ODMgMTAuNjY3IDEzNC4yMjkgMjkuNzgxbC00MjEuNTQ3IDQyMS41NDdjLTE5LjA3Mi00MC43ODktMjkuNzM5LTg2LjI3Mi0yOS43MzktMTM0LjI3MnpNNTEyIDgyOS4wNTZjLTQ4IDAtOTMuNDgzLTEwLjY2Ny0xMzQuMjI5LTI5Ljc4MWw0MjEuNTQ3LTQyMS41NDdjMTkuMDcyIDQwLjc4OSAyOS43ODEgODYuMjcyIDI5Ljc4MSAxMzQuMjI5LTAuMDQzIDE3NS4xNDctMTQxLjk5NSAzMTcuMDk5LTMxNy4wOTkgMzE3LjA5OXoiLz48L3N2Zz4=',
|
||||
style: 'width: 100px; height: 100px; margin-bottom: 1em;'
|
||||
}),
|
||||
E('h2', {}, message)
|
||||
]));
|
||||
} else {
|
||||
var iframe = E('iframe', {
|
||||
src: buttonUrl,
|
||||
style: 'width: 100%; min-height: 100vh; border: none;'
|
||||
});
|
||||
container.appendChild(iframe);
|
||||
}
|
||||
|
||||
poll.add(function() {
|
||||
return self.checkRunning().then(function(checkResult) {
|
||||
var newStatus = checkResult.isRunning;
|
||||
if (newStatus !== isRunning) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}, 5);
|
||||
|
||||
poll.start();
|
||||
|
||||
return container;
|
||||
});
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Lucky"
|
||||
msgstr "Lucky大吉"
|
||||
|
||||
msgid "Lucky Control panel"
|
||||
msgstr "Lucky操作台"
|
||||
|
||||
msgid "ipv4/ipv6 portforward,ddns,reverseproxy proxy,wake on lan,IOT and more,Default username and password 666"
|
||||
msgstr "IPv4/IPv6端口转发,动态域名服务,http/https反向代理,默认用户名密码666.."
|
||||
|
||||
msgid "Enable SSL"
|
||||
msgstr "开启SSL"
|
||||
|
||||
msgid "Collecting data..."
|
||||
msgstr "收集数据..."
|
||||
|
||||
msgid "Set the Lucky access port"
|
||||
msgstr "设置访问端口"
|
||||
|
||||
msgid "Base Setting"
|
||||
msgstr "基本设置"
|
||||
|
||||
msgid "Safe entrance"
|
||||
msgstr "安全入口"
|
||||
|
||||
msgid "Port must be between 1 and 65535"
|
||||
msgstr "端口范围1-65535之间"
|
||||
|
||||
msgid "Open Web Interface"
|
||||
msgstr "打开WEB界面"
|
||||
|
||||
msgid "RUNNING"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "NOT RUNNING"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Delayed Start (seconds)"
|
||||
msgstr "开机延时启动(秒)"
|
||||
|
||||
msgid "Username and password reset successfully to 666"
|
||||
msgstr "重置用户名和密码为666"
|
||||
|
||||
msgid "SUCCESS:"
|
||||
msgstr "执行完成:"
|
||||
|
||||
msgid "ResetUser"
|
||||
msgstr "重置用户密码"
|
||||
|
||||
msgid "Reset account and password to initial values"
|
||||
msgstr "重置帐号和密码为初始值"
|
||||
|
||||
msgid "Encrypt access using HTTPS"
|
||||
msgstr "使用https加密访问"
|
||||
|
||||
msgid "Set an installation access path, eg:sirpdboy"
|
||||
msgstr "设置一个安装访问路径,如:sirpdboy"
|
||||
|
||||
msgid "Lucky Service Not Running"
|
||||
msgstr "Lucky服务未启用"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -f "/etc/config/ucitrack" ] && {
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@lucky[-1]
|
||||
add ucitrack lucky
|
||||
set ucitrack.@lucky[-1].init=lucky
|
||||
commit ucitrack
|
||||
EOF
|
||||
}
|
||||
|
||||
rm -rf /tmp/luci-*
|
||||
exit 0
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"admin/services/lucky": {
|
||||
"title": "Lucky",
|
||||
"order": 59,
|
||||
"action": {
|
||||
"type": "firstchild"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-lucky" ],
|
||||
"uci": { "lucky": true }
|
||||
}
|
||||
},
|
||||
"admin/services/lucky/lucky": {
|
||||
"title": "Lucky Control panel",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "lucky/lucky"
|
||||
}
|
||||
},
|
||||
"admin/services/lucky/config": {
|
||||
"title": "Base Setting",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "lucky/config"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"luci-app-lucky": {
|
||||
"description": "Grant UCI access for luci-app-lucky",
|
||||
"read": {
|
||||
"uci": [ "lucky" ],
|
||||
"file": {
|
||||
"/etc/init.d/lucky": [ "exec" ],
|
||||
"/usr/bin/lucky": [ "exec" ],
|
||||
"/bin/pidof": [ "exec" ],
|
||||
"/bin/ps": [ "exec" ],
|
||||
"/bin/ash": [ "exec" ]
|
||||
},
|
||||
"ubus": {
|
||||
"rc": [ "*" ],
|
||||
"service": ["list"],
|
||||
"luci.lucky": [ "*" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.lucky": [ "*" ]
|
||||
},
|
||||
"file": {
|
||||
"/etc/lucky/*.lkcf": ["write"]
|
||||
},
|
||||
"uci": ["lucky"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/ucode
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2021-2026 sirpdboy <herboy2008@gmail.com> https://github.com/sirpdboy/luci-app-lucky
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { access, error, lstat, popen, readfile, writefile } from 'fs';
|
||||
|
||||
/* Kanged from ucode/luci */
|
||||
function shellquote(s) {
|
||||
return `'${replace(s, "'", "'\\''")}'`;
|
||||
}
|
||||
const methods = {
|
||||
set_ConfInfo: {
|
||||
args: { key: 'key', value: 'value' },
|
||||
call: function(req) {
|
||||
if (!access('/usr/bin/lucky'))
|
||||
return { status: 255, error: 'lucky not found' };
|
||||
|
||||
if (!req.args?.key)
|
||||
return { status: 255, error: 'missing key parameter' };
|
||||
|
||||
const key = shellquote(req.args.key);
|
||||
const configPath = '/etc/lucky';
|
||||
let exit_code = 255;
|
||||
|
||||
if (req.args.value !== null && req.args.value !== undefined) {
|
||||
const value = shellquote(req.args.value);
|
||||
exit_code = system(`/usr/bin/lucky -setconf -key ${key} -value ${value} -cd ${configPath}`);
|
||||
} else {
|
||||
// Èç¹ûûÓÐÌṩvalue£¬Ö»ÉèÖÃkey
|
||||
exit_code = system(`/usr/bin/lucky -setconf -key ${key} -cd ${configPath}`);
|
||||
}
|
||||
|
||||
return { status: exit_code };
|
||||
}
|
||||
},
|
||||
|
||||
get_baseInfo: {
|
||||
call: function() {
|
||||
if (!access('/usr/bin/lucky'))
|
||||
return { ConfInfo: {}, error: 'lucky not found' };
|
||||
|
||||
const configPath = '/etc/lucky';
|
||||
const fd = popen('/usr/bin/lucky -baseConfInfo -cd /etc/lucky');
|
||||
if (fd) {
|
||||
let config = fd.read('all');
|
||||
fd.close();
|
||||
|
||||
if (!config || length(config) === 0)
|
||||
return { ConfInfo: {}, error: 'empty response' };
|
||||
|
||||
try {
|
||||
config = json(config);
|
||||
return { ConfInfo: config };
|
||||
} catch(e) {
|
||||
return { ConfInfo: {}, error: 'JSON parse error: ' + e };
|
||||
}
|
||||
} else {
|
||||
return { ConfInfo: {}, error: 'failed to execute lucky command' };
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
get_Info: {
|
||||
call: function() {
|
||||
if (!access('/usr/bin/lucky'))
|
||||
return { Info: {}, error: 'lucky not found' };
|
||||
const configPath = '/etc/lucky';
|
||||
const fd = popen('/usr/bin/lucky -info -cd /etc/lucky');
|
||||
if (fd) {
|
||||
let config = fd.read('all');
|
||||
fd.close();
|
||||
|
||||
if (!config || length(config) === 0)
|
||||
return { Info: {}, error: 'empty response' };
|
||||
|
||||
try {
|
||||
config = json(config);
|
||||
return { Info: config };
|
||||
} catch(e) {
|
||||
return { Info: {}, error: 'JSON parse error: ' + e };
|
||||
}
|
||||
} else {
|
||||
return { Info: {}, error: 'failed to execute lucky command' };
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { 'luci.lucky': methods };
|
||||
Reference in new issue
Block a user