Files
3m-ui/scripts/3m-ui.sh
T
Z User 2fd6992574 feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
feat(scripts): add config port command to 3m-ui management scripts
Users changing the panel port from the web UI had to SSH in and run
'systemctl restart 3m-ui' manually — easy to forget and not discoverable.
Now both the 3m-ui entry script and 3m-ui.sh manager support:
3m-ui config show              — display config.yaml
3m-ui config port <1-65535>    — change port + auto-restart
The interactive menu (running '3m-ui' with no args) also gains:
9. 修改面板端口  (interactive port change with current/new display)
a. 卸载 3m-ui    (moved from slot 9 to 'a')
Flow:
1. Reads current port from config.yaml
2. Validates new port (1-65535, numeric)
3. sed replaces '  port: N' line in config.yaml
4. Restarts the service
5. Waits 1s, checks if active
6. Prints new access URL or failure message
This closes the UX gap: web UI saves port → user runs '3m-ui config
port 9000' → script restarts and confirms.
2026-08-30 09:41:36 +00:00

203 lines
5.4 KiB
Bash

#!/bin/sh
# 3m-ui unified management logic
# The command entrypoint is /usr/local/bin/3m-ui.
# The actual Go application is /usr/local/lib/3m-ui/3m-ui-bin.
set -eu
APP_NAME="3m-ui"
BASE="/usr/local/lib/3m-ui"
APP_BIN="$BASE/3m-ui-bin"
VERSION_FILE="$BASE/VERSION"
DATA_DIR="/var/lib/3m-ui"
CONFIG_DIR="/etc/3m-ui"
CONFIG_FILE="$CONFIG_DIR/config.yaml"
SERVICE="3m-ui"
say() { printf '%s\n' "$*"; }
err() { say "Error: $*" >&2; exit 1; }
need_root() {
[ "$(id -u)" = 0 ] || err "Please run as root."
}
init_system() {
if command -v systemctl >/dev/null 2>&1 && [ -d /run/systemd/system ]; then
printf '%s' systemd
elif command -v rc-service >/dev/null 2>&1; then
printf '%s' openrc
else
printf '%s' unsupported
fi
}
service_action() {
action="$1"
case "$(init_system)" in
systemd) systemctl "$action" "$SERVICE" ;;
openrc) rc-service "$SERVICE" "$action" ;;
*) err "No supported init system found." ;;
esac
}
status() {
case "$(init_system)" in
systemd) systemctl --no-pager --full status "$SERVICE" || true ;;
openrc) rc-service "$SERVICE" status || true ;;
*) say "init: unsupported" ;;
esac
say ""
if [ -x "$APP_BIN" ]; then
say "Application: $APP_BIN"
if ! "$APP_BIN" --version 2>/dev/null; then
if [ -s "$VERSION_FILE" ]; then
say "Version: $(cat "$VERSION_FILE")"
else
say "Version: unavailable (installed binary does not expose --version)"
fi
fi
else
say "Application binary not found: $APP_BIN"
fi
}
logs() {
case "$(init_system)" in
systemd) journalctl -u "$SERVICE" -n 100 --no-pager ;;
openrc) tail -n 100 "$DATA_DIR/logs/3m-ui.log" 2>/dev/null || tail -n 100 "/var/log/3m-ui/3m-ui.log" 2>/dev/null || say "No log file found." ;;
*) say "No supported log backend found." ;;
esac
}
version() {
[ -x "$APP_BIN" ] || err "3m-ui application is not installed."
if "$APP_BIN" --version 2>/dev/null; then
return 0
fi
if [ -s "$VERSION_FILE" ]; then
say "3m-ui $(cat "$VERSION_FILE")"
return 0
fi
err "Unable to determine installed version."
}
uninstall() {
service_action stop 2>/dev/null || true
case "$(init_system)" in
systemd)
systemctl disable "$SERVICE" 2>/dev/null || true
rm -f "/etc/systemd/system/$SERVICE.service"
systemctl daemon-reload
;;
openrc)
rc-update del "$SERVICE" default 2>/dev/null || true
rm -f "/etc/init.d/$SERVICE"
;;
esac
rm -f /usr/local/bin/3m-ui
rm -rf "$BASE"
say "3m-ui application and management command removed."
say "Data preserved at: $DATA_DIR"
say "Configuration preserved at: $CONFIG_DIR"
say "Mihomo was not removed."
}
config() {
action="${1:-show}"
case "$action" in
show)
if [ -f "$CONFIG_FILE" ]; then
say "Config file: $CONFIG_FILE"
say "---"
cat "$CONFIG_FILE"
else
err "Config file not found: $CONFIG_FILE"
fi
;;
port)
new_port="$2"
case "$new_port" in
''|*[!0-9]*) err "Usage: 3m-ui config port <1-65535>" ;;
esac
[ "$new_port" -ge 1 ] 2>/dev/null && [ "$new_port" -le 65535 ] 2>/dev/null || err "Port must be 1-65535."
[ -f "$CONFIG_FILE" ] || err "Config file not found: $CONFIG_FILE"
# Read current port
old_port=$(awk '/^ port:/ {print $2; exit}' "$CONFIG_FILE" 2>/dev/null || echo "8080")
if [ "$old_port" = "$new_port" ]; then
say "Port is already $new_port — no change needed."
return 0
fi
# Replace port in config.yaml
sed -i "s/^ port: .*/ port: $new_port/" "$CONFIG_FILE"
say "Port changed: $old_port → $new_port"
say "Restarting 3m-ui to apply..."
service_action restart
sleep 1
if service_is_active; then
say "✓ 3m-ui restarted. Access: http://0.0.0.0:$new_port"
else
say "✗ 3m-ui failed to start. Check logs: 3m-ui logs"
fi
;;
*)
err "Unknown config action: $action. Use 'show' or 'port <number>'."
;;
esac
}
service_is_active() {
case "$(init_system)" in
systemd) systemctl is-active --quiet "$SERVICE" ;;
openrc) rc-service "$SERVICE" status >/dev/null 2>&1 ;;
*) return 1 ;;
esac
}
usage() {
cat <<EOF
Usage: 3m-ui <command>
Commands:
status Show service and application status
start Start 3m-ui
restart Restart 3m-ui
stop Stop 3m-ui
logs Show recent service logs
version Show installed 3m-ui version
config Show or edit config (see below)
uninstall Remove 3m-ui but preserve data/config
help Show this help
Config sub-commands:
3m-ui config show Display current config.yaml
3m-ui config port <1-65535> Change panel port and restart
Run '3m-ui' without arguments to open the interactive management menu.
EOF
}
main() {
need_root
cmd=${1:-}
case "$cmd" in
status) status ;;
start) service_action start ;;
restart) service_action restart ;;
stop) service_action stop ;;
logs) logs ;;
version) version ;;
config) shift; config "$@" ;;
uninstall) uninstall ;;
help|-h|--help) usage ;;
'')
if [ -x /usr/local/bin/3m-ui ] && [ "$(readlink -f /usr/local/bin/3m-ui 2>/dev/null || true)" = "$APP_BIN" ]; then
err "Invalid installation: management entrypoint points to the application binary. Re-run the latest installer to migrate it."
fi
exec /usr/local/bin/3m-ui
;;
*) err "Unknown command: $cmd" ;;
esac
}
main "$@"