feat: 重写为 GPUI 原生桌面应用并接入 Gitea 软件包发布

- gpui-kit 0.6 原生 UI:连接管理、消息流/日志、发布预设、全局变量、
  设置、阿里云连接预设、原生 Logo
- MQTT 5.0/3.1.1 引擎(rumqttc,TCP/TLS/WS/WSS),独立 tokio runtime
  + 事件泵,真实 broker 端到端测试
- 连接表单:保存前可一键测试连接(宽松校验,自动生成临时 Client ID),
  高级属性(认证/MQTT 5 属性/遗嘱)按需折叠显示,WS 路径仅 WS/WSS 显示
- bug 修复:Hex 奇数长度显式报错、测试连接唯一 Client ID、Base64/Hex
  发布发送真实字节、v5 发布记录携带 Content-Type/用户属性、预设应用
  清除旧 Content-Type、模板时间基准统一;补 8 个单元测试
- Gitea 发布:Generic Package 上传脚本(bash/PowerShell)+ Actions
  release 工作流(tag 触发,双平台构建),README 使用说明
This commit is contained in:
2026-09-28 11:39:47 +08:00
parent 0152a10ee6
commit bf6937b776
25 changed files with 15287 additions and 120 deletions
+143
View File
@@ -0,0 +1,143 @@
<#
.SYNOPSIS
发布构建产物到 Gitea Package Registry(Generic 包)。
.DESCRIPTION
用 Gitea Generic Package API 上传文件:
PUT {GITEA_URL}/api/packages/{owner}/generic/{pkg}/{version}/{filename}
认证:Authorization: token <GITEA_TOKEN>
同名版本重复上传会得到 409,脚本按"已存在"处理。
上传成功后附加 .sha256 校验文件。
.EXAMPLE
$env:GITEA_URL = "https://gitea.example.com"
$env:GITEA_TOKEN = "xxxxxxxx"
.\scripts\publish-gitea.ps1 # 上传默认产物,版本自动推断
.\scripts\publish-gitea.ps1 -Version v1.0.1 # 指定版本
.\scripts\publish-gitea.ps1 -Files a.exe, b.zip # 指定文件
.PARAMETER Files
待上传文件列表。缺省时自动探测 target/release/mqttx(.exe)。
.PARAMETER Version
软件包版本。缺省时依次尝试 git describe --tags、gpui-app/Cargo.toml。
.PARAMETER Owner
覆盖 GITEA_OWNER(缺省时从 git remote origin 推断)。
.PARAMETER PackageName
覆盖 GITEA_PKG(默认 mqttx)。
#>
[CmdletBinding()]
param(
[string[]]$Files = @(),
[string]$Version = "",
[string]$Owner = "",
[string]$PackageName = ""
)
$ErrorActionPreference = "Stop"
# Windows PowerShell 5.1 默认可能协商 TLS1.0,现代 Gitea 实例要求 TLS1.2+
try {
[Net.ServicePointManager]::SecurityProtocol = `
[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
} catch { }
function Die($msg) { Write-Error "错误: $msg"; exit 1 }
# ── 必填配置 ────────────────────────────────────────────────────────────────
$GiteaUrl = $env:GITEA_URL
$Token = $env:GITEA_TOKEN
if (-not $GiteaUrl) { Die "缺少环境变量 GITEA_URL(如 https://gitea.example.com)" }
if (-not $Token) { Die "缺少环境变量 GITEA_TOKEN(需 package 写权限)" }
$GiteaUrl = $GiteaUrl.TrimEnd("/")
$Root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
$Pkg = if ($PackageName) { $PackageName } elseif ($env:GITEA_PKG) { $env:GITEA_PKG } else { "mqttx" }
# ── owner:参数 > GITEA_OWNER > git remote origin 推断 ──────────────────────
if (-not $Owner) { $Owner = $env:GITEA_OWNER }
if (-not $Owner) {
$remote = git -C $Root remote get-url origin 2>$null
if ($remote) {
# 兼容 git@host:owner/repo.git 与 https://host/owner/repo.git
if ($remote -match "://") {
# URL 形式:取 host 之后的路径段
$path = ($remote -split "/", 4)[-1]
}
else {
# SCP 形式 git@host:owner/repo
$path = ($remote -split ":", 2)[-1]
}
$path = $path -replace "\.git$", ""
$seg = @($path -split "/" | Where-Object { $_ })
if ($seg.Count -ge 2) { $Owner = $seg[0] }
}
}
if (-not $Owner) { Die "无法推断 owner,请用 -Owner 或 GITEA_OWNER 指定" }
# ── 版本:参数 > git describe > Cargo.toml ──────────────────────────────────
if (-not $Version) {
$Version = (git -C $Root describe --tags --always 2>$null)
}
if (-not $Version) {
$m = Select-String -Path (Join-Path $Root "gpui-app\Cargo.toml") -Pattern '^version = "(.+)"' | Select-Object -First 1
if ($m) { $Version = $m.Matches[0].Groups[1].Value }
}
if (-not $Version) { Die "无法确定版本号" }
$Version = $Version -replace "/", "-" # Gitea 版本段不允许 "/"
# ── 默认产物 ────────────────────────────────────────────────────────────────
if (-not $Files -or $Files.Count -eq 0) {
$exe = Join-Path $Root "target\release\mqttx.exe"
$bin = Join-Path $Root "target\release\mqttx"
if (Test-Path $exe) { $Files = @($exe) }
elseif (Test-Path $bin) { $Files = @($bin) }
else { Die "未找到产物,请先 cargo build --release,或用 -Files 指定" }
}
Write-Host "→ Gitea: $GiteaUrl"
Write-Host "→ 软件包: $Owner/$Pkg@$Version"
Write-Host "→ 产物: $($Files -join ', ')"
foreach ($f in $Files) {
if (-not (Test-Path $f)) { Die "文件不存在: $f" }
$name = Split-Path -Leaf $f
$size = "{0:N1} MB" -f ((Get-Item $f).Length / 1MB)
Write-Host "→ 上传 $name ($size)"
$url = "$GiteaUrl/api/packages/$Owner/generic/$Pkg/$Version/$name"
# Windows PowerShell 5.1 无 -InFile 的 token 认证上传也走 Invoke-WebRequest
try {
Invoke-RestMethod -Method Put `
-Headers @{ Authorization = "token $Token" } `
-InFile $f `
-ContentType "application/octet-stream" `
-Uri $url | Out-Null
Write-Host " ✓ 已发布 $name" -ForegroundColor Green
}
catch {
$status = $null
if ($_.Exception.Response) { $status = [int]$_.Exception.Response.StatusCode }
if ($status -eq 409) {
Write-Host " ! 已存在同名版本(409),跳过:$name" -ForegroundColor Yellow
continue
}
Die "上传失败: $($_.Exception.Message)"
}
# 附带 sha256 校验文件
$sum = (Get-FileHash -Algorithm SHA256 $f).Hash.ToLower()
$sidecar = "$f.sha256"
"$sum $name" | Set-Content -NoNewline -Encoding ascii $sidecar
try {
Invoke-RestMethod -Method Put `
-Headers @{ Authorization = "token $Token" } `
-InFile $sidecar `
-ContentType "text/plain" `
-Uri "$url.sha256" | Out-Null
Write-Host " ✓ 已发布 $name.sha256" -ForegroundColor Green
}
catch {
Write-Host " ! sha256 文件上传失败" -ForegroundColor Yellow
}
}
Write-Host "完成。软件包页面: $GiteaUrl/$Owner?tab=packages" -ForegroundColor Cyan
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env bash
# 发布构建产物到 Gitea Package Registry(Generic 包)。
#
# 用法:
# GITEA_URL=https://gitea.example.com GITEA_TOKEN=xxx \
# ./scripts/publish-gitea.sh [文件...] [版本]
#
# 环境变量:
# GITEA_URL 实例地址,如 https://gitea.example.com(必填)
# GITEA_TOKEN 访问令牌,需 package 写权限(必填)
# GITEA_OWNER 软件包所属用户/组织(默认:由 git remote 推断,失败则报错)
# GITEA_PKG 软件包名(默认 mqttx)
#
# 版本推断顺序:参数 > git describe --tags > gpui-app/Cargo.toml。
set -euo pipefail
die() { echo "错误: $*" >&2; exit 1; }
[ -n "${GITEA_URL:-}" ] || die "缺少 GITEA_URL"
[ -n "${GITEA_TOKEN:-}" ] || die "缺少 GITEA_TOKEN"
GITEA_URL="${GITEA_URL%/}"
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PKG="${GITEA_PKG:-mqttx}"
# ── owner:优先环境变量,其次从 git remote 推断 ──────────────────────────────
owner_of_remote() {
local url path
url="$(git -C "$ROOT" remote get-url origin 2>/dev/null)" || return 1
case "$url" in
*://*) path="${url#*://}"; path="${path#*/}" ;; # https://host/owner/repo.git
*:*) path="${url#*:}" ;; # git@host:owner/repo.git
*) return 1 ;;
esac
path="${path%.git}"
printf '%s\n' "${path%%/*}"
}
OWNER="${GITEA_OWNER:-$(owner_of_remote || true)}"
[ -n "${OWNER:-}" ] || die "无法推断 GITEA_OWNER,请显式设置"
# ── 版本:参数 > git describe > Cargo.toml ───────────────────────────────────
FILES=()
for arg in "$@"; do
if [ -f "$arg" ]; then FILES+=("$arg"); else VERSION="$arg"; fi
done
if [ -z "${VERSION:-}" ]; then
VERSION="$(git -C "$ROOT" describe --tags --always 2>/dev/null || true)"
fi
if [ -z "${VERSION:-}" ]; then
VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' "$ROOT/gpui-app/Cargo.toml" | head -1)"
fi
[ -n "${VERSION:-}" ] || die "无法确定版本号"
# Gitea 版本段不允许 "/",tag 形如 v1.0.0-3-gabc123 时规范化
VERSION="${VERSION//\//-}"
# ── 默认产物 ────────────────────────────────────────────────────────────────
if [ "${#FILES[@]}" -eq 0 ]; then
if [ -x "$ROOT/target/release/mqttx.exe" ]; then
FILES=("$ROOT/target/release/mqttx.exe")
elif [ -x "$ROOT/target/release/mqttx" ]; then
FILES=("$ROOT/target/release/mqttx")
else
die "未找到产物,请先 cargo build --release,或显式传入文件"
fi
fi
echo "→ Gitea: $GITEA_URL"
echo "→ 软件包: $OWNER/$PKG@$VERSION"
echo "→ 产物: ${FILES[*]}"
sha256() {
if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1
else shasum -a 256 "$1" | cut -d' ' -f1; fi
}
for f in "${FILES[@]}"; do
[ -f "$f" ] || die "文件不存在: $f"
name="$(basename "$f")"
echo "→ 上传 $name ($(du -h "$f" | cut -f1))"
code="$(curl -sS -o /tmp/gitea-pkg-resp.txt -w '%{http_code}' \
-X PUT \
-H "Authorization: token ${GITEA_TOKEN}" \
--upload-file "$f" \
"${GITEA_URL}/api/packages/${OWNER}/generic/${PKG}/${VERSION}/${name}")"
case "$code" in
201|200|409) # 409 = 同名版本已存在,Gitea 拒绝覆盖
if [ "$code" = "409" ]; then
echo " ! 已存在同名版本(409),跳过:$name"
else
echo " ✓ 已发布 $name (HTTP $code)"
# 附带 sha256 校验文件,便于下游验证
sum="$(sha256 "$f")"
echo "$sum $name" > "${f}.sha256"
code2="$(curl -sS -o /dev/null -w '%{http_code}' \
-X PUT \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: text/plain" \
--data-binary "@${f}.sha256" \
"${GITEA_URL}/api/packages/${OWNER}/generic/${PKG}/${VERSION}/${name}.sha256")"
[ "$code2" = "201" ] || echo " ! sha256 文件上传失败 (HTTP $code2)"
fi
;;
*)
echo " ✗ 上传失败 (HTTP $code)" >&2
cat /tmp/gitea-pkg-resp.txt >&2 || true
exit 1
;;
esac
done
echo "完成。软件包页面: ${GITEA_URL}/${OWNER}?tab=packages"