mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-02 03:23:56 +08:00
🍓 Sync 2026-09-15 02:13:06
This commit is contained in:
1 parent
0e5393594c
commit
1dd96ac2bb
146 files changed
+26541
-508
No files matched your search
@@ -0,0 +1,2 @@
|
||||
config frpc 'main'
|
||||
option enabled '0'
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$ACTION" = "ifup" ] || exit 0
|
||||
[ "$INTERFACE" = "loopback" ] && exit 0
|
||||
|
||||
# Skip if frpc is not enabled
|
||||
[ "$(uci -q get frpc.main.enabled)" = "1" ] || exit 0
|
||||
|
||||
# Skip if frpc process is already running
|
||||
if pidof /usr/bin/frpc >/dev/null 2>&1 || pidof frpc >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
LOCK=/tmp/frpc_hotplug.lock
|
||||
|
||||
# Debounce: avoid duplicate concurrent starts within 5 seconds
|
||||
if [ -f "$LOCK" ]; then
|
||||
ts=$(cat "$LOCK" 2>/dev/null)
|
||||
[ -n "$ts" ] && [ $(( $(date +%s) - ts )) -lt 5 ] && exit 0
|
||||
fi
|
||||
|
||||
date +%s > "$LOCK"
|
||||
|
||||
logger -t frpc-hotplug "${INTERFACE:-$DEVICE} ifup: frpc is enabled but not running, starting service"
|
||||
/etc/init.d/frpc start >/dev/null 2>&1 &
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=90
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
PROG=/usr/bin/frpc
|
||||
CONF_FILE=/etc/config/frpc.toml
|
||||
|
||||
is_enabled() {
|
||||
local enabled
|
||||
config_load frpc
|
||||
config_get_bool enabled "main" "enabled" 0
|
||||
[ "$enabled" -eq 1 ]
|
||||
}
|
||||
|
||||
start_service() {
|
||||
is_enabled || return 0
|
||||
|
||||
if [ ! -s "$CONF_FILE" ]; then
|
||||
logger -t frpc "Config file missing or empty: $CONF_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command "$PROG" -c "$CONF_FILE"
|
||||
procd_set_param respawn
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
if ! is_enabled; then
|
||||
stop
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -s "$CONF_FILE" ]; then
|
||||
logger -t frpc "Config file missing or empty: $CONF_FILE"
|
||||
stop
|
||||
return 1
|
||||
fi
|
||||
|
||||
restart
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "frpc"
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"admin/services/frpc": {
|
||||
"title": "Frp Client",
|
||||
"order": 90,
|
||||
"action": {
|
||||
"type": "firstchild"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-frpc" ],
|
||||
"uci": { "frpc": true }
|
||||
}
|
||||
},
|
||||
"admin/services/frpc/overview": {
|
||||
"title": "Overview",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "frpc/overview"
|
||||
}
|
||||
},
|
||||
"admin/services/frpc/settings": {
|
||||
"title": "Settings",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "frpc/settings"
|
||||
}
|
||||
},
|
||||
"admin/services/frpc/log": {
|
||||
"title": "Log",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "frpc/log"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"luci-app-frpc": {
|
||||
"description": "Grant access to frpc RPC methods",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"luci.frpc": [
|
||||
"get_status",
|
||||
"get_runtime_info",
|
||||
"get_log",
|
||||
"get_config"
|
||||
]
|
||||
},
|
||||
"uci": [
|
||||
"frpc"
|
||||
]
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.frpc": [
|
||||
"adopt_process",
|
||||
"validate_config",
|
||||
"set_enabled",
|
||||
"service_action",
|
||||
"save_config"
|
||||
]
|
||||
},
|
||||
"uci": [
|
||||
"frpc"
|
||||
],
|
||||
"file": {
|
||||
"/etc/config/frpc.toml": [ "read", "write" ],
|
||||
"/var/etc/frpc.toml": [ "read" ],
|
||||
"/var/log/frpc.log": [ "read" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
'use strict';
|
||||
|
||||
import { connect } from 'ubus';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const PROCD_SERVICE_NAME = 'frpc';
|
||||
const CONFIG_FILE = '/etc/config/frpc.toml';
|
||||
const RUNTIME_CONFIG_FILE = '/etc/config/frpc.toml';
|
||||
|
||||
function get_procd_status() {
|
||||
let u = connect();
|
||||
if (!u)
|
||||
return { running: false };
|
||||
|
||||
let res = u.call('service', 'list', { name: PROCD_SERVICE_NAME });
|
||||
if (res && res[PROCD_SERVICE_NAME] && res[PROCD_SERVICE_NAME].instances) {
|
||||
let inst = res[PROCD_SERVICE_NAME].instances.instance1;
|
||||
if (inst && inst.running)
|
||||
return { running: true, pid: inst.pid };
|
||||
}
|
||||
|
||||
return { running: false };
|
||||
}
|
||||
|
||||
function get_rogue_pid(managed_pid) {
|
||||
let p = fs.popen('pgrep -x frpc', 'r');
|
||||
if (!p)
|
||||
return null;
|
||||
|
||||
let pid_str = p.read('all');
|
||||
p.close();
|
||||
|
||||
if (!pid_str)
|
||||
return null;
|
||||
|
||||
let pids = pid_str.trim().split('\n');
|
||||
for (let i = 0; i < length(pids); i++) {
|
||||
let pid = pids[i];
|
||||
if (pid != '' && (managed_pid == null || pid != (managed_pid + '')))
|
||||
return pid;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function count_proxies(config) {
|
||||
if (!config)
|
||||
return 0;
|
||||
|
||||
let parts = split(config, '[[proxies]]');
|
||||
return (parts && length(parts) > 0) ? (length(parts) - 1) : 0;
|
||||
}
|
||||
|
||||
function verify_config(config) {
|
||||
fs.writefile('/tmp/frpc_test.toml', config || '');
|
||||
let p = fs.popen("/usr/bin/frpc verify -c /tmp/frpc_test.toml 2>&1", 'r');
|
||||
if (!p) {
|
||||
fs.unlink('/tmp/frpc_test.toml');
|
||||
return { success: false, error: 'failed to validate config' };
|
||||
}
|
||||
|
||||
let output = p.read('all') || '';
|
||||
let code = p.close();
|
||||
fs.unlink('/tmp/frpc_test.toml');
|
||||
|
||||
if (code !== 0)
|
||||
return { success: false, error: output || 'verify failed' };
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
function get_frpc_version() {
|
||||
system("/bin/sh -c '/usr/bin/frpc --version >/tmp/frpc_version.out 2>&1 || /usr/bin/frpc -v >/tmp/frpc_version.out 2>&1'");
|
||||
let out = fs.readfile('/tmp/frpc_version.out') || '';
|
||||
fs.unlink('/tmp/frpc_version.out');
|
||||
|
||||
if (!out)
|
||||
return '';
|
||||
|
||||
let line = split(out, '\n')[0] || '';
|
||||
if (!line)
|
||||
return '';
|
||||
line = replace(line, /^[ \t\r\n]+/, '');
|
||||
line = replace(line, /[ \t\r\n]+$/, '');
|
||||
return line;
|
||||
}
|
||||
|
||||
function get_enabled() {
|
||||
let p = fs.popen("/bin/sh -c \"uci -q get frpc.main.enabled 2>/dev/null || echo 0\"", 'r');
|
||||
if (!p)
|
||||
return 0;
|
||||
let out = p.read('all') || '0';
|
||||
p.close();
|
||||
out = replace(out, /^[ \t\r\n]+/, '');
|
||||
out = replace(out, /[ \t\r\n]+$/, '');
|
||||
return (out === '1') ? 1 : 0;
|
||||
}
|
||||
|
||||
function toml_get(key, defv) {
|
||||
let p = fs.popen("/bin/sh -c \"grep -F '" + key + "' " + CONFIG_FILE + " 2>/dev/null | head -n1 | cut -d= -f2-\"", 'r');
|
||||
if (!p)
|
||||
return defv;
|
||||
|
||||
let out = p.read('all') || '';
|
||||
p.close();
|
||||
out = replace(out, /^[ \t\r\n]+/, '');
|
||||
out = replace(out, /[ \t\r\n]+$/, '');
|
||||
out = replace(out, /^\"/, '');
|
||||
out = replace(out, /\"$/, '');
|
||||
return out ? out : defv;
|
||||
}
|
||||
|
||||
function get_runtime_info() {
|
||||
let status = get_procd_status();
|
||||
if (!status.running)
|
||||
return { running: false };
|
||||
|
||||
let addr = toml_get('webServer.addr', '127.0.0.1');
|
||||
let port = toml_get('webServer.port', '7400');
|
||||
let user = toml_get('webServer.user', '');
|
||||
let pass = toml_get('webServer.password', '');
|
||||
let auth = (user && pass) ? ("-u '" + user + ":" + pass + "' ") : '';
|
||||
|
||||
system("/bin/sh -c \"curl -s " + auth + "http://" + addr + ":" + port + "/api/status >/tmp/frpc_web_status.json 2>/tmp/frpc_web_err\"");
|
||||
system("/bin/sh -c \"curl -s " + auth + "http://" + addr + ":" + port + "/api/config >/tmp/frpc_web_config.txt 2>>/tmp/frpc_web_err\"");
|
||||
|
||||
let raw_status = fs.readfile('/tmp/frpc_web_status.json') || '';
|
||||
let raw_config = fs.readfile('/tmp/frpc_web_config.txt') || '';
|
||||
let raw_err = fs.readfile('/tmp/frpc_web_err') || '';
|
||||
fs.unlink('/tmp/frpc_web_status.json');
|
||||
fs.unlink('/tmp/frpc_web_config.txt');
|
||||
fs.unlink('/tmp/frpc_web_err');
|
||||
|
||||
let status_obj = {};
|
||||
if (raw_status) {
|
||||
try { status_obj = json(raw_status); } catch (e) {}
|
||||
}
|
||||
|
||||
let server_addr = '';
|
||||
let server_port = '';
|
||||
if (raw_config) {
|
||||
let m1 = match(raw_config, /serverAddr[ \t]*=[ \t]*\"([^\"]+)\"/);
|
||||
let m2 = match(raw_config, /serverPort[ \t]*=[ \t]*([0-9]+)/);
|
||||
if (m1 && length(m1) > 1) server_addr = m1[1];
|
||||
if (m2 && length(m2) > 1) server_port = m2[1];
|
||||
}
|
||||
|
||||
let lan_ip = '';
|
||||
let u = connect();
|
||||
if (u) {
|
||||
let lan_st = u.call('network.interface.lan', 'status', {});
|
||||
if (lan_st && lan_st['ipv4-address'] && length(lan_st['ipv4-address']) > 0)
|
||||
lan_ip = lan_st['ipv4-address'][0].address || '';
|
||||
}
|
||||
|
||||
let web_host = addr;
|
||||
if (addr == '0.0.0.0' || addr == '127.0.0.1' || addr == '::')
|
||||
web_host = lan_ip || '127.0.0.1';
|
||||
let web_url = 'http://' + web_host + ':' + port;
|
||||
|
||||
return {
|
||||
running: true,
|
||||
web_addr: addr,
|
||||
web_port: int(port),
|
||||
web_url: web_url,
|
||||
server_addr: server_addr,
|
||||
server_port: server_port ? int(server_port) : 0,
|
||||
raw_status: raw_status,
|
||||
status: status_obj,
|
||||
error: raw_err
|
||||
};
|
||||
}
|
||||
|
||||
const methods = {
|
||||
get_status: {
|
||||
call: function() {
|
||||
let procd_st = get_procd_status();
|
||||
let rogue_pid = get_rogue_pid(procd_st.pid);
|
||||
|
||||
let state = 'stopped';
|
||||
if (procd_st.running)
|
||||
state = 'managed';
|
||||
else if (rogue_pid)
|
||||
state = 'unmanaged';
|
||||
|
||||
let config = fs.readfile(CONFIG_FILE) || '';
|
||||
|
||||
return {
|
||||
state: state,
|
||||
pid: procd_st.pid || rogue_pid,
|
||||
config_exists: !!fs.stat(CONFIG_FILE),
|
||||
runtime_config: RUNTIME_CONFIG_FILE,
|
||||
proxy_count: count_proxies(config),
|
||||
version: get_frpc_version(),
|
||||
enabled: get_enabled()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
adopt_process: {
|
||||
call: function() {
|
||||
fs.popen('killall -9 frpc', 'r').close();
|
||||
let rc = system('/etc/init.d/frpc start >/dev/null 2>&1');
|
||||
return { success: (rc === 0) };
|
||||
}
|
||||
},
|
||||
|
||||
get_log: {
|
||||
call: function() {
|
||||
let p = fs.popen('logread -e frpc | tail -n 100', 'r');
|
||||
if (!p)
|
||||
return { log: '' };
|
||||
let log = p.read('all');
|
||||
p.close();
|
||||
return { log: log || '' };
|
||||
}
|
||||
},
|
||||
|
||||
get_runtime_info: {
|
||||
call: function() {
|
||||
return get_runtime_info();
|
||||
}
|
||||
},
|
||||
|
||||
get_config: {
|
||||
call: function() {
|
||||
if (!fs.stat(CONFIG_FILE))
|
||||
return { config: '' };
|
||||
return { config: fs.readfile(CONFIG_FILE) || '' };
|
||||
}
|
||||
},
|
||||
|
||||
validate_config: {
|
||||
args: { config: '' },
|
||||
call: function(req) {
|
||||
let config = req.args?.config ?? '';
|
||||
return verify_config(config);
|
||||
}
|
||||
},
|
||||
|
||||
set_enabled: {
|
||||
args: { enabled: 0 },
|
||||
call: function(req) {
|
||||
let enabled = (int(req.args?.enabled ?? 0) === 1) ? '1' : '0';
|
||||
let cmd = "/bin/sh -c \"uci -q set frpc.main.enabled=" + enabled + " && uci -q commit frpc\"";
|
||||
let rc = system(cmd);
|
||||
return { success: (rc === 0), enabled: int(enabled) };
|
||||
}
|
||||
},
|
||||
|
||||
service_action: {
|
||||
args: { action: '' },
|
||||
call: function(req) {
|
||||
let action = req.args?.action ?? '';
|
||||
if (action != 'start' && action != 'stop' && action != 'restart' && action != 'reload')
|
||||
return { success: false, error: 'invalid action' };
|
||||
let rc = system('/etc/init.d/frpc ' + action + ' >/dev/null 2>&1');
|
||||
return { success: (rc === 0), applied: (rc === 0) };
|
||||
}
|
||||
},
|
||||
|
||||
save_config: {
|
||||
args: { config: '' },
|
||||
call: function(req) {
|
||||
let config = req.args?.config ?? '';
|
||||
let vr = verify_config(config);
|
||||
if (!vr.success)
|
||||
return vr;
|
||||
|
||||
if (!fs.writefile(CONFIG_FILE, config))
|
||||
return { success: false, error: 'unable to write config file (/etc/config/frpc.toml)' };
|
||||
|
||||
let rc = system('/etc/init.d/frpc reload >/dev/null 2>&1');
|
||||
return {
|
||||
success: true,
|
||||
saved: true,
|
||||
applied: (rc === 0)
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { 'luci.frpc': methods };
|
||||
Reference in new issue
Block a user