chore: v0.1.1 — 版本号收拢进 internal/version + 发布脚本校验和覆盖安装包

- 新增 internal/version 包作为版本号唯一来源,release.sh 通过
  -ldflags -X 注入真实 tag。此前 /api/manager/status 与集群 JoinInfo
  里各自硬编码 "0.1.0",产物报告的版本与 tag 无关。
- release.sh:SHA256SUMS 移到原生安装包构建之后统一重算,覆盖
  deb/rpm/setup.exe/pkg。此前只算 tar.gz/zip,用户校验安装包会得到
  "no file was verified"(v0.1.0 发布时实际踩到)。
- rpm spec / build_installers.sh 默认版本与 changelog、README 安装
  示例文件名同步到 0.1.1。

验证:go test ./internal/cluster/... ./internal/httpapi/... 通过;
6 平台产物架构逐个 file 校验正确;linux-amd64 实跑 /status 报告
version=0.1.1(确认 ldflags 注入生效)。
This commit is contained in:
JianFeeeee
2026-09-03 07:28:13 +08:00
parent f935cad33f
commit f9f18ae13c
8 changed files with 109 additions and 18 deletions

View File

@ -79,7 +79,7 @@ cd web && npm run build && rm -rf internal/httpapi/dist && cp -r web/dist intern
### Linux (Debian / Ubuntu) ### Linux (Debian / Ubuntu)
```bash ```bash
sudo dpkg -i webui4frpc-0.1.0-linux-amd64.deb # 或 linux-arm64.deb sudo dpkg -i webui4frpc-0.1.1-linux-amd64.deb # 或 linux-arm64.deb
sudo nano /etc/webui4frpc/webui4frpc.env # 改掉默认密码 sudo nano /etc/webui4frpc/webui4frpc.env # 改掉默认密码
sudo systemctl restart webui4frpc sudo systemctl restart webui4frpc
``` ```
@ -87,7 +87,7 @@ sudo systemctl restart webui4frpc
### Linux (RHEL / Fedora / openEuler / 默认 / 龙蜥) ### Linux (RHEL / Fedora / openEuler / 默认 / 龙蜥)
```bash ```bash
sudo rpm -i webui4frpc-0.1.0-linux-x86_64.rpm sudo rpm -i webui4frpc-0.1.1-linux-x86_64.rpm
sudo vi /etc/webui4frpc/webui4frpc.env sudo vi /etc/webui4frpc/webui4frpc.env
sudo systemctl enable --now webui4frpc sudo systemctl enable --now webui4frpc
``` ```
@ -97,7 +97,7 @@ sudo systemctl enable --now webui4frpc
### Windows ### Windows
双击 `webui4frpc-0.1.0-windows-amd64-setup.exe`ARM 设备用 `windows-arm64-setup.exe`)。 双击 `webui4frpc-0.1.1-windows-amd64-setup.exe`ARM 设备用 `windows-arm64-setup.exe`)。
安装向导会询问监听地址与管理员凭据,完成后: 安装向导会询问监听地址与管理员凭据,完成后:
- 程序装到 `C:\Program Files\webui4frpc` - 程序装到 `C:\Program Files\webui4frpc`
@ -107,8 +107,8 @@ sudo systemctl enable --now webui4frpc
### macOS ### macOS
```bash ```bash
sudo installer -pkg webui4frpc-0.1.0-darwin-arm64.pkg -target / # Apple Silicon sudo installer -pkg webui4frpc-0.1.1-darwin-arm64.pkg -target / # Apple Silicon
sudo installer -pkg webui4frpc-0.1.0-darwin-amd64.pkg -target / # Intel sudo installer -pkg webui4frpc-0.1.1-darwin-amd64.pkg -target / # Intel
``` ```
或直接双击 `.pkg` 走图形安装器。安装后 launchd 开机自启,配置在 或直接双击 `.pkg` 走图形安装器。安装后 launchd 开机自启,配置在
@ -126,7 +126,7 @@ sudo launchctl kickstart -k system/com.jianfeeeee.webui4frpc
不想装服务只想跑一下,用对应的 `.tar.gz` / `.zip`,解压即用: 不想装服务只想跑一下,用对应的 `.tar.gz` / `.zip`,解压即用:
```bash ```bash
tar xzf webui4frpc-0.1.0-linux-amd64.tar.gz tar xzf webui4frpc-0.1.1-linux-amd64.tar.gz
./webui4frpc -addr 127.0.0.1:7500 -user admin -password 你的密码 -workdir ./data ./webui4frpc -addr 127.0.0.1:7500 -user admin -password 你的密码 -workdir ./data
``` ```

View File

@ -25,6 +25,7 @@ import (
"webui4frpc/internal/process" "webui4frpc/internal/process"
"webui4frpc/internal/render" "webui4frpc/internal/render"
"webui4frpc/internal/store" "webui4frpc/internal/store"
"webui4frpc/internal/version"
) )
func main() { func main() {
@ -132,7 +133,7 @@ func main() {
} }
var ring *cluster.Engine var ring *cluster.Engine
ring = cluster.NewEngine( ring = cluster.NewEngine(
selfID, selfID, *user, *pass, "0.1.0", nil, selfID, selfID, *user, *pass, version.Version, nil,
&cluster.AppHandler{ &cluster.AppHandler{
LoadFn: func() (float64, float64) { LoadFn: func() (float64, float64) {
// NetPct: real NIC saturation from /proc/net/dev deltas vs // NetPct: real NIC saturation from /proc/net/dev deltas vs
@ -533,7 +534,7 @@ func main() {
// CreateCluster so the node is at least functional as standalone. // CreateCluster so the node is at least functional as standalone.
func retryJoinCluster(ctx context.Context, ring *cluster.Engine, targetAddr, joinKey string) { func retryJoinCluster(ctx context.Context, ring *cluster.Engine, targetAddr, joinKey string) {
selfNode := ring.State().Nodes[0] selfNode := ring.State().Nodes[0]
ji := cluster.JoinInfo{ID: selfNode.ID, Addr: selfNode.Addr, Version: "0.1.0", JoinKey: joinKey} ji := cluster.JoinInfo{ID: selfNode.ID, Addr: selfNode.Addr, Version: version.Version, JoinKey: joinKey}
deadline := time.NewTimer(5 * time.Minute) deadline := time.NewTimer(5 * time.Minute)
defer deadline.Stop() defer deadline.Stop()
ticker := time.NewTicker(10 * time.Second) ticker := time.NewTicker(10 * time.Second)
@ -593,7 +594,7 @@ func retryRejoinCached(ctx context.Context, ring *cluster.Engine, peersJSON stri
return return
} }
for _, p := range peers { for _, p := range peers {
ji := cluster.JoinInfo{ID: selfNode.ID, Addr: selfNode.Addr, Version: "0.1.0", JoinKey: p.Key} ji := cluster.JoinInfo{ID: selfNode.ID, Addr: selfNode.Addr, Version: version.Version, JoinKey: p.Key}
jc, cancel := context.WithTimeout(ctx, 8*time.Second) jc, cancel := context.WithTimeout(ctx, 8*time.Second)
err := ring.JoinRing(jc, p.Addr, ji) err := ring.JoinRing(jc, p.Addr, ji)
cancel() cancel()

View File

@ -20,6 +20,7 @@ import (
"webui4frpc/internal/cluster" "webui4frpc/internal/cluster"
"webui4frpc/internal/process" "webui4frpc/internal/process"
"webui4frpc/internal/store" "webui4frpc/internal/store"
"webui4frpc/internal/version"
) )
//go:embed all:dist //go:embed all:dist
@ -413,7 +414,7 @@ func (h *Handler) handleStatus(w http.ResponseWriter, r *http.Request) {
} }
resp := map[string]any{ resp := map[string]any{
"version": "0.1.0", "version": version.Version,
"workDir": h.WorkDir, "workDir": h.WorkDir,
"settings": settings, "settings": settings,
"services": locals, "services": locals,

View File

@ -0,0 +1,12 @@
// Package version holds the single source of truth for the build version.
//
// Value is overridable at build time so release artifacts carry the real tag:
//
// go build -ldflags="-X webui4frpc/internal/version.Version=0.1.1" ./cmd/webui4frpc
//
// Kept in its own package because both cmd/ and internal/httpapi report it
// (main can't be imported, and httpapi must not depend on cmd).
package version
// Version is the running build's semantic version, without a leading "v".
var Version = "0.1.1"

View File

@ -1,5 +1,5 @@
Name: webui4frpc Name: webui4frpc
Version: %{?_w4f_version}%{!?_w4f_version:0.1.0} Version: %{?_w4f_version}%{!?_w4f_version:0.1.1}
Release: 1%{?dist} Release: 1%{?dist}
Summary: Visual frpc controller with token-ring cluster Summary: Visual frpc controller with token-ring cluster
License: MIT License: MIT
@ -67,6 +67,11 @@ fi
%doc %{_docdir}/webui4frpc/README.md %doc %{_docdir}/webui4frpc/README.md
%changelog %changelog
* Wed Sep 02 2026 JianFeeeee <jianfeeeee@gitcode> - 0.1.1-1
- 修复令牌环冻结:心跳到达时复活被误判 offline 的前驱;
全环无可达后继时保留 inflight leader 超时重发令牌。
- WebUI 窄屏适配:侧栅转底部 tab bar各页响应式重排。
* Fri Aug 28 2026 JianFeeeee <jianfeeeee@gitcode> - 0.1.0-1 * Fri Aug 28 2026 JianFeeeee <jianfeeeee@gitcode> - 0.1.0-1
- 首次发布per-forward worker 模型、NIC 负载采样、审计 CSV 导出、 - 首次发布per-forward worker 模型、NIC 负载采样、审计 CSV 导出、
session 登录与三级角色。 session 登录与三级角色。

View File

@ -72,8 +72,74 @@ rm -rf internal/httpapi/dist && cp -r web/dist internal/httpapi/dist
cd web && npm run build && rm -rf internal/httpapi/dist && cp -r web/dist internal/httpapi/dist && go build -o webui4frpc ./cmd/webui4frpc cd web && npm run build && rm -rf internal/httpapi/dist && cp -r web/dist internal/httpapi/dist && go build -o webui4frpc ./cmd/webui4frpc
``` ```
## 安装
从 [Release 页](https://gitcode.com/JianFeeeee/webui4frpc/releases/latest) 下载对应平台的安装包。
### Linux (Debian / Ubuntu)
```bash
sudo dpkg -i webui4frpc-0.1.1-linux-amd64.deb # 或 linux-arm64.deb
sudo nano /etc/webui4frpc/webui4frpc.env # 改掉默认密码
sudo systemctl restart webui4frpc
```
### Linux (RHEL / Fedora / openEuler / 默认 / 龙蜥)
```bash
sudo rpm -i webui4frpc-0.1.1-linux-x86_64.rpm
sudo vi /etc/webui4frpc/webui4frpc.env
sudo systemctl enable --now webui4frpc
```
安装后自动建 `webui4frpc` 系统账号、注册 systemd 单元,数据目录在 `/var/lib/webui4frpc`
服务以非 root 运行,并启用 `ProtectSystem=full` / `NoNewPrivileges` 等加固项。
### Windows
双击 `webui4frpc-0.1.1-windows-amd64-setup.exe`ARM 设备用 `windows-arm64-setup.exe`)。
安装向导会询问监听地址与管理员凭据,完成后:
- 程序装到 `C:\Program Files\webui4frpc`
- 开始菜单生成启动快捷方式与卸载项
- 自动添加防火墙入站规则
### macOS
```bash
sudo installer -pkg webui4frpc-0.1.1-darwin-arm64.pkg -target / # Apple Silicon
sudo installer -pkg webui4frpc-0.1.1-darwin-amd64.pkg -target / # Intel
```
或直接双击 `.pkg` 走图形安装器。安装后 launchd 开机自启,配置在
`/usr/local/etc/webui4frpc/webui4frpc.env`,改完执行:
```bash
sudo launchctl kickstart -k system/com.jianfeeeee.webui4frpc
```
> 该 `.pkg` 未经 Apple 公证notarization。首次打开若被 Gatekeeper 拦下,
> 在「系统设置 → 隐私与安全」选择仍要打开。
### 免安装tar.gz / zip
不想装服务只想跑一下,用对应的 `.tar.gz` / `.zip`,解压即用:
```bash
tar xzf webui4frpc-0.1.1-linux-amd64.tar.gz
./webui4frpc -addr 127.0.0.1:7500 -user admin -password 你的密码 -workdir ./data
```
下载后可用 `SHA256SUMS` 校验完整性:
```bash
sha256sum -c SHA256SUMS --ignore-missing
```
## 运行 ## 运行
从源码构建后直接跑:
```bash ```bash
./webui4frpc -addr 127.0.0.1:7500 -user admin -password admin123 -workdir ./data ./webui4frpc -addr 127.0.0.1:7500 -user admin -password admin123 -workdir ./data
``` ```

View File

@ -12,7 +12,7 @@
# 在 release.sh 流程内被调用;依赖 dist/artifacts/<version>/bin/<os>-<arch>/ 下的二进制。 # 在 release.sh 流程内被调用;依赖 dist/artifacts/<version>/bin/<os>-<arch>/ 下的二进制。
set -euo pipefail set -euo pipefail
VERSION="${1:-0.1.0}" VERSION="${1:-0.1.1}"
VERSION="${VERSION#v}" VERSION="${VERSION#v}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)" ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="$ROOT/dist/artifacts/$VERSION" OUT="$ROOT/dist/artifacts/$VERSION"

View File

@ -3,7 +3,7 @@
# webui4frpc 多平台发布脚本 # webui4frpc 多平台发布脚本
# #
# 用法: # 用法:
# ./scripts/release.sh [version] # 默认 version=0.1.0 # ./scripts/release.sh [version] # 默认 version=0.1.1
# #
# 行为: # 行为:
# 1. 构建前端 (web/dist) 并同步到 internal/httpapi/dist (go:embed 用) # 1. 构建前端 (web/dist) 并同步到 internal/httpapi/dist (go:embed 用)
@ -19,7 +19,7 @@
# NO_BUILD_FRONTEND 设为 1 跳过前端构建 (用现有 dist) # NO_BUILD_FRONTEND 设为 1 跳过前端构建 (用现有 dist)
set -euo pipefail set -euo pipefail
VERSION="${1:-0.1.0}" VERSION="${1:-0.1.1}"
VERSION="${VERSION#v}" # 去掉可能的前导 v VERSION="${VERSION#v}" # 去掉可能的前导 v
ROOT="$(cd "$(dirname "$0")/.." && pwd)" ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="$ROOT/dist/artifacts/$VERSION" OUT="$ROOT/dist/artifacts/$VERSION"
@ -77,7 +77,8 @@ for target in "${TARGETS[@]}"; do
mkdir -p "$bindir" mkdir -p "$bindir"
echo "==> 编译 $os/$arch" echo "==> 编译 $os/$arch"
env $GOFLAGS_ENV CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \ env $GOFLAGS_ENV CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \
go build -trimpath -ldflags="-s -w" \ go build -trimpath \
-ldflags="-s -w -X webui4frpc/internal/version.Version=$VERSION" \
-o "$bindir/$bin" "$ROOT/cmd/webui4frpc" -o "$bindir/$bin" "$ROOT/cmd/webui4frpc"
done done
@ -126,16 +127,21 @@ done
rm -rf "$OUT/.stage" rm -rf "$OUT/.stage"
# ---- 4. 校验和 ---- # ---- 4. 校验和 ----
echo "==> 生成 SHA256SUMS" # 先生成免安装包的校验和;原生安装包构建完后在 4.6 统一重算,
( cd "$OUT" && sha256sum *.tar.gz *.zip 2>/dev/null | tee SHA256SUMS ) # 保证 SHA256SUMS 覆盖 deb/rpm/setup.exe/pkg否则用户校验会 "no file was verified")。
# ---- 4.5 原生安装包 (deb/rpm/setup.exe/pkg) ---- # ---- 4.5 原生安装包 (deb/rpm/setup.exe/pkg) ----
if [ "${NO_INSTALLERS:-0}" != "1" ]; then if [ "${NO_INSTALLERS:-0}" != "1" ]; then
echo "" echo ""
echo "==> 构建原生安装包" echo "==> 构建原生安装包"
"$ROOT/scripts/build_installers.sh" "$VERSION" "$ROOT/scripts/build_installers.sh" "$VERSION"
fi fi
# ---- 4.6 校验和(覆盖全部产物)----
echo ""
echo "==> 生成 SHA256SUMS"
( cd "$OUT" && sha256sum *.tar.gz *.zip *.deb *.rpm *-setup.exe *.pkg 2>/dev/null | tee SHA256SUMS )
# ---- 5. 汇总 ---- # ---- 5. 汇总 ----
echo "" echo ""
echo "==> 发布产物位于: $OUT" echo "==> 发布产物位于: $OUT"