跳转至

01. 部署与配置

1. 环境要求

依赖 建议版本 必需性 说明
Go 见根目录 go.mod 必需 当前 toolchain 为 1.26.8;后端构建使用该版本。
Node.js 20+ 前端构建必需 www 使用 Vite 7 和 React 19。
MySQL/MariaDB MySQL 5.7+ / MariaDB 10.3+ 必需 主业务数据库。
Redis 6.0+ release 构建必需 refresh token、登录失败和注册/验证码保护存储;development/test 构建不可用时可降级到内存。
MinIO 兼容 minio-go/v7 可选 对象存储;也可改用本地磁盘(Storage.Driver=local)。
Keycloak 可选 可选 SSO 登录。

Docker Compose 快速部署(Linux)

仓库根目录的 compose.yaml 提供 DraARL、MySQL、Redis 和 MinIO 的完整 单机部署。DraARL 镜像使用多阶段构建,最终镜像包含静态 Go 二进制、证书、 时区数据、配置生成工具及固定版本的 ffmpeg/ffprobe,并以非 root 用户运行。

cp .env.example .env

部署前必须修改 .env 中的 MySQL、Redis、MinIO 密码,并核对:

  • DRAARL_PUBLIC_URL:浏览器访问 DraARL 的 Origin,例如 https://radio.example.com。
  • DRAARL_MINIO_ENDPOINT:DraARL 容器和浏览器都可以直接访问的 MinIO 已发布地址 host:port 或反代域名;不要填写 Compose 内部服务名 minio:9000。
  • DRAARL_MINIO_USE_SSL:上述已发布地址是否使用 HTTPS。
  • DRAARL_HTTP_PORT、DRAARL_UDP_PORT:宿主机发布端口。
  • DRAARL_BROADCAST_ENABLED:自动播报部署级硬开关,默认 false;由负责接入射频 设备的台站管理员按其设备管理责任显式启用。
  • DRAARL_GO_PROXY:仅影响镜像构建时的 Go 模块下载;默认使用官方代理,所在 网络无法访问时可改为可信的兼容代理。

启动并检查健康状态:

docker compose up -d --build
docker compose ps
curl -fsS http://127.0.0.1:${DRAARL_HTTP_PORT:-9000}/healthz
docker compose logs draarl

首次启动过程如下:

  1. MySQL、Redis、MinIO 分别通过健康检查。
  2. DraARL 入口脚本在 draarl-config 命名卷中生成一次 /var/lib/draarl/config.yaml;未显式提供的 JWT/AES 密钥使用系统随机源生成。
  3. 默认携带 -auto-migrate 初始化或升级结构;旧版 minio 驱动会在桶不存在时 创建 MinIO bucket,并输出首次管理员凭据。
  4. 后续重启复用同一配置和全部数据卷,不会重新生成密钥。

DraARL 容器使用只读根文件系统,临时转码只允许写入 64 MiB、noexec/nosuid 的 /tmp。Docker 健康检查除请求 /healthz 外,还会用 60ms 的 16kHz 单声道 PCM 实际编码 Opus 并通过 ffprobe 校验输出;因此容器显示 healthy 时也证明自动 播报转码工具链可用。

Compose 默认将 MinIO 设为 MINIO_BROWSER=off,只发布 9000 S3 API 端口, 不启动或发布 9001 Web Console。DraARL 不会修改 bucket policy;安装包、固件和 其他对象都通过短期预签名 URL 访问,桶应始终保持私有。前端静态资源由 DraARL 主程序直接提供,不写入对象存储。

DRAARL_AUTO_MIGRATE=false 可关闭后续容器启动时的显式迁移;完全空库仍会按 DraARL 的空库规则自动初始化。Compose 环境变量只负责首次生成配置,已有配置 不会被重写,包括 DRAARL_BROADCAST_ENABLED。需要修改完整配置时可导出、编辑 并放回命名卷:

docker compose cp draarl:/var/lib/draarl/config.yaml ./config.yaml
# 编辑 config.yaml
docker compose cp ./config.yaml draarl:/var/lib/draarl/config.yaml
docker compose restart draarl

docker compose down 保留数据;docker compose down -v 会删除数据库、Redis、 MinIO 和 DraARL 配置卷,仅限明确需要清空部署时使用。生产升级前应备份命名卷, 并在宿主机按需要提高 UDP rmem_max/wmem_max,容器不能突破宿主机内核上限。

2. 创建数据库

CREATE DATABASE draarl CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

建议为 DraARL 单独创建数据库账号,并只授予该数据库所需权限。

3. 配置文件

默认配置文件为 config.yaml。如果命令行未指定 -c,程序会在可执行文件所在目录查找 config.yaml。

复制模板:

cp config.yaml.example config.yaml

Windows:

Copy-Item config.yaml.example config.yaml

4. 核心配置说明

4.1 System

字段 说明
Host UDP 监听地址,空字符串表示所有网卡。
Port UDP 服务端口,示例为 60050。
LogPath 日志文件路径,空字符串表示不输出到文件。
IPfile IP 地址库路径,默认 ./ipinfo.ipdb。
ProxyProtocol 可配置 v2,用于从 frp 等代理获取真实客户端 IP。

4.2 UDP 实时转发

字段 默认值 说明
SendWorkers 0 并发发送 worker 数;0 按 CPU 自动选择,模板说明的自动上限为 8,手动范围 1-32。
IngressWorkers 0 按设备身份分片的入站处理 worker;0 按 CPU 自动选择,模板说明的自动上限为 16。
FrameQueueSize 64 fan-out 队列按完整帧计数;队列满时淘汰最旧实时帧。
MaxFrameAgeMS 500 超过该本地排队时间的实时帧不再发送;默认覆盖约 4 个 120ms 播报包的短暂抖动。
ReadBufferBytes / WriteBufferBytes 4194304 请求的 UDP socket 缓冲;系统实际值以启动日志和 /api/udp/metrics 为准。

自动 worker 值适合通用部署;只有经过目标机器压测后才应手工放大。队列和帧龄是实时 保护机制,不是可靠消息队列,过载时允许丢弃过期媒体以避免延迟无限累积。

4.3 幽灵 Session 与频道消息

GhostSessions 在单机、中心和边缘均参与校验。中心和所有边缘应保持相同上限, 避免同一账号迁移入口后出现不同的接纳结果。幽灵多端/多收始终启用,没有旧协议降级开关。

字段 默认值 有效范围 说明
GhostSessions.MaxSessionsPerOwner 8 1-64 同一账号可同时在线的 UDP/WS 幽灵 Session 总数。
GhostSessions.MaxSubscriptionsPerSession 16 1-256 每个 Session 的接收频道上限;发送频道也计入并必须属于接收集合。

MessageAPI 保护频道历史列表与详情查询:

字段 默认值 有效范围 说明
DefaultPageSize 50 1 至 MaxPageSize 未传 limit 时的列表条数。
MaxPageSize 100 1-1000 单次消息列表最大条数。
RequestsPerMinutePerUser 120 1-1000000 每账号共享的列表/详情请求窗口。
RequestsPerMinutePerIP 300 1-1000000 每来源 IP 共享的列表/详情请求窗口。
MaxConcurrentQueries 32 1-4096 全局同时执行的消息数据库查询数。

账号/IP 超限返回 429 和 Retry-After;查询槽满返回 503 message_api_busy。 提高上限前应使用真实 MySQL 数据量检查游标索引与查询延迟。

4.4 Database

字段 说明
Host / Port MySQL 地址。
User / Password 数据库账号。
DBName 数据库名。
Charset / Collate 默认 utf8mb4 / utf8mb4_unicode_ci。
Timezone 数据库时间解释。默认 Local 保持旧行为;显式填写 IANA 时区(如 UTC 或 Asia/Shanghai)会同时设置 Go 解码位置、GORM NowFunc 和 MySQL session time_zone。
MaxOpenConns 最大打开连接数,默认 25。
MaxIdleConns 最大空闲连接数,默认 5。
MaxLifetime 连接最大存活时间,单位秒,默认 300。

4.5 Redis

Redis 用于 refresh token、登录失败和注册/验证码保护。release 构建启动时必须连接 Redis,连接失败会拒绝启动;development/test 构建连接失败时可降级到内存。内存模式只适合开发测试,服务重启后 refresh token 和共享限速状态会丢失。

字段 说明
Host / Port Redis 地址。
Password Redis 密码。
DB Redis 数据库编号。
Prefix Key 前缀,默认 draarl。
DialTimeoutSec / ReadTimeoutSec / WriteTimeoutSec 连接和读写超时。
PoolSize 连接池大小。

4.6 Web

字段 说明
Host HTTP 监听地址,空字符串表示所有网卡。
Port HTTP/API/WebSocket 服务端口。
FrontendURL 前端对外地址,用于 SSO 回调重定向,也会加入 Origin 白名单。
AllowedOrigins 允许访问 API 和 WebSocket 的页面来源。生产环境必须正确配置。

生产环境注意:

  • 后端会校验 Origin/Referer。
  • release 构建下如果没有可解析的 FrontendURL 或 AllowedOrigins,程序会启动失败。
  • API 网关会拒绝 URL query 中出现 token 类参数,例如 token、access_token、refresh_token、jwt。

4.7 Keycloak

Keycloak 为可选 SSO 配置。启用后,登录页会显示 SSO 登录入口。

字段 说明
Enabled 是否启用 SSO。
Name 前端显示名称。
BaseURL Keycloak 服务器地址。
Realm Realm 名称。
ClientID / ClientSecret 客户端配置。
RedirectURI 后端 /api/sso/callback 回调地址。

4.8 存储(Storage / S3 兼容对象存储)

系统通过统一存储抽象支持 local、MinIO、Cloudflare R2、腾讯云 COS 和阿里云 OSS。除 local 外,所有实现都通过同一个 S3 V4 驱动工作,不会为每个厂商复制上传、校验或发布流程:

Storage.Driver 说明
minio 使用 Storage.MinIO 连接对象存储;支持 S3 预签名直传。
s3 / r2 / cos / oss 使用 Storage.S3;r2、cos、oss 是 S3 兼容别名。
local 文件写入 Storage.Local.RootPath;明确允许公开的站点图片可走 /files/*,其他对象使用签名 GET。
空 若 Storage.MinIO.Endpoint 非空则选 minio,否则 local。
字段 说明
Storage.Local.RootPath 本地存储根目录,默认 ./data/storage。
Storage.Local.BaseURL 公开 URL 前缀,空则使用 /files。
Storage.UseCDN 默认 false;启用后,对象 GET 链接统一使用 EdgeOne TypeA 签名。适用于当前 active profile 或旧配置。
Storage.CDNBaseURL CDN 的完整 http(s):// 访问前缀,可包含路径;仅在 UseCDN=true 时生效。
Storage.CDNSignParam 鉴权参数名称,默认 sign;支持 1-100 位英文字母、数字或下划线。
Storage.CDNExpirySeconds CDN 链接有效秒数,默认 3600(1 小时),范围 1-630720000;必须与 EdgeOne 鉴权规则一致。
Storage.CDNKey EdgeOne 鉴权密钥,支持精确的 ${ENV_NAME} 引用。
Storage.UploadLimits.ClientResourceBytes 通用客户端资源直传上限,默认 536870912(512 MiB)。固件继续使用独立的 16 MiB 限制。
Storage.MinIO.Endpoint 后端连接 MinIO 的地址,可以使用容器网络或内网地址。
Storage.MinIO.PublicEndpoint 可选的对外 host:port;预签名 URL 使用此地址,留空回退到 Endpoint。
Storage.MinIO.AccessKey / SecretKey 凭据。
Storage.MinIO.UseSSL 是否使用 HTTPS。
Storage.MinIO.PublicUseSSL PublicEndpoint 是否使用 HTTPS。
Storage.MinIO.Bucket 默认桶名。
Storage.MinIO.DownloadURLPrefix 可选,仅替换预签名 GET 的访问前缀;预签名 PUT 不使用它。
Storage.ActiveProfile 当前运行的命名 profile。设置后优先于旧的 Driver/MinIO 配置。
Storage.Profiles.<name>.Driver local、s3、minio、r2、cos 或 oss。
Storage.Profiles.<name>.S3.Endpoint 后端连接的 S3 API 地址,可写 host:port 或完整 http(s):// URL;显式 scheme 优先于 UseSSL。
Storage.Profiles.<name>.S3.PresignEndpoint 浏览器实际访问的 S3 API 地址,只用于生成 PUT/GET 签名;显式 scheme 优先于 PresignUseSSL。
Storage.Profiles.<name>.S3.DownloadURLPrefix 高级选项:替换预签名 GET 的 URL 前缀,供用户自行配置的反向代理使用;不代表对象公开。
Storage.Profiles.<name>.S3.Region / BucketLookup region 和桶寻址方式(auto、path、dns)。
Storage.Profiles.<name>.S3.SessionToken 可选 STS 会话令牌。
Storage.Profiles.<name>.S3.AutoCreateBucket 仅开发 MinIO 建议设为 true;公有云保持 false,由部署侧预创建 bucket。

未显式填写 BucketLookup 时,r2 和 minio 默认使用 path,cos 和 oss 默认使用 dns,通用 s3 使用 auto;其他值会在启动时直接报错,不会静默回退。推荐端点格式:R2 使用 <account-id>.r2.cloudflarestorage.com,Region 留空时自动设为 auto;COS 使用 cos.<region>.myqcloud.com、真实 Region 及包含 AppID 的 bucket 名;OSS 使用 oss-<region>.aliyuncs.com 和真实 Region。COS、OSS 缺少 Region 时会拒绝启动。完整 profile 示例见 config.yaml.example。

运行凭据至少需要检查 bucket、列举指定前缀、读取对象、写入对象和删除对象的权限;Promote 还需要读取 staging 源对象并在 final key 执行服务端复制。建议把权限限制到业务 bucket,并尽可能限制到 staging/、client-resources/、firmware/、assets/ 等应用前缀。应用不会修改 bucket policy;若启用存储迁移,还需覆盖迁移源和目标所需权限。

AccessKey、SecretKey 和 SessionToken 支持精确的 ${ENV_NAME} 引用。变量在创建存储客户端时解析,解析值不会回写配置文件;变量缺失或为空会使存储初始化失败并明确指出字段。也可以通过容器 Secret 生成未跟踪的生产配置。

旧版本顶层 MinIO: 配置会在启动时自动迁移到 Storage.MinIO;显式设置 Storage.Driver: local 时不会迁移旧 MinIO 配置。旧 BasePath 和 PublicBaseURL 会打印弃用提示并迁移为 DownloadURLPrefix,不再产生匿名、无签名 URL。

上传策略固定为:

  • 代理上传(需服务端图像处理):头像、Logo、Favicon
  • 浏览器直传(presign → PUT → complete):资源中心、固件、操作证、通用客户端资源(含安装包、模型和字库)

直传对象先写入按用户隔离的 staging 路径,complete 校验签名授权和实际大小后才提升为不可变对象。超过 24 小时未完成的 staging 对象会自动清理;管理员可在资源页重新识别自己的已完成 staging 上传并重签 complete 凭证。客户端资源和固件通过短时下载 URL 返回;local 驱动也使用 /api/storage/get 的短时签名 URL,client-resources/、firmware/ 和 staging/ 不能由 /files/* 永久访问。

资源中心、头像、站点图片、操作证和通联录音的历史响应字段也通过统一读取 URL 策略生成。未启用 CDN 时,local 仅对明确允许的头像、Logo 和 Favicon 返回稳定 /files/* 地址,其他对象使用签名 GET;S3 兼容存储返回预签名 GET URL。启用 CDN 后,这些对象读取链接和固件、客户端资源下载链接统一使用 CDN TypeA 签名。前端不应持久化签名 URL,页面长时间打开后应重新请求相应业务接口。

EdgeOne CDN 配置示例(与现有存储配置合并):

Storage:
  UseCDN: true
  CDNBaseURL: "https://cdn.example.com"
  CDNSignParam: "sign"
  CDNExpirySeconds: 3600
  CDNKey: "${EDGEONE_CDN_KEY}"

在 EdgeOne 控制台启用 TypeA 鉴权,把鉴权参数名、密钥和有效时长设为与上面相同的值。签名格式为 ?sign=timestamp-rand-0-md5hash,其中 md5hash=MD5(Path-timestamp-rand-0-key);Path 为 URL 编码后的完整访问路径,包含 CDNBaseURL 的路径前缀,不含查询参数。程序按 CDNBaseURL + / + object_key 拼接,不自动添加 bucket 名;若 CDN 访问路径需要 bucket 或其他前缀,应将它写入 CDNBaseURL。

TypeA 的 timestamp 是签发时间,EdgeOne 按 timestamp + 有效时长 判断过期。启用 CDN 后以 CDNExpirySeconds 为所有 CDN 链接的有效期,覆盖业务接口原有的 15 分钟或 1 小时设定;客户端资源的 url_expires_at 也按该配置返回。调整有效期时需同步修改 EdgeOne 规则。鉴权在缓存命中前执行,EdgeOne 鉴权通过后会忽略鉴权参数进行缓存。

CDN 需配置能访问私有源站的回源鉴权,bucket 可继续保持私有。上传、对象校验、复制和删除仍使用原存储驱动;S3 预签名 PUT 使用原 PresignEndpoint,CDN GET 不使用 DownloadURLPrefix 或 X-Amz-* 参数。历史绝对 URL 按原值返回。配置后重启服务生效。

S3 兼容直传 CORS 要求:

  • 允许前端 Origin 的 PUT、GET、HEAD(以及预检 OPTIONS)
  • 允许请求头 Content-Type 以及供应商签名流程需要的 x-amz-* 请求头
  • 暴露响应头 ETag
  • 生产建议 HTTPS 反代 MinIO,并保证签名 URL 中的 host 浏览器可达
  • 预签名依赖服务端与对象存储时间一致;生产环境应启用 NTP 时间同步
  • 应通过 Secret、环境变量或未跟踪配置提供 AccessKey/SecretKey,示例文件不得填写生产密钥

未启用 UseCDN 时,DownloadURLPrefix 继续用于 S3 预签名 GET 的反向代理。程序先针对 PresignEndpoint 生成完整 S3 V4 预签名 GET,再把浏览器访问前缀替换为该值,并保留对象路径和全部 X-Amz-* 查询参数。代理必须在回源时恢复签名使用的 Host 和原始 S3 路径,否则会返回 SignatureDoesNotMatch。DraARL 不配置或检测 CDN 缓存键、回源 Header、方法限制 和边缘鉴权;未充分理解 S3 V4 canonical request 时应保持该字段为空。

对私有对象使用缓存时,不要简单从缓存键中忽略全部签名参数。否则合法请求预热后, 伪造、缺失或过期签名也可能直接命中缓存并绕过源站鉴权。缓存 TTL 也不应超过预签名 URL 有效期。此类高级代理配置由部署方自行验证,项目只保证未配置前缀时的标准 S3 预签名行为。

可使用同一套可选契约测试验证 MinIO、R2、COS 或 OSS;当前 MinIO 已通过含 CORS 的契约,R2、COS 和 OSS 已通过除部署 Origin CORS 外的存储契约和完整客户端资源 HTTP 生命周期。测试会在指定桶的 contract-tests/ 和 staging/contract-tests/ 前缀创建并清理临时对象,覆盖 Put、Stat、Open、Walk、Delete、预签名 PUT/GET、服务端复制、不可覆盖 final key 和 CORS:

DRAARL_S3_TEST_PROVIDER=minio \
DRAARL_S3_TEST_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_PRESIGN_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_ACCESS_KEY=test-access-key \
DRAARL_S3_TEST_SECRET_KEY=test-secret-key \
DRAARL_S3_TEST_BUCKET=draarl-contract \
DRAARL_S3_TEST_BUCKET_LOOKUP=path \
DRAARL_S3_TEST_CORS_ORIGIN=https://admin.example.com \
go test ./pkg/storage -run '^TestS3CompatibleContract$' -count=1 -v

设置 DRAARL_S3_TEST_CORS_ORIGIN 后还会对预签名 PUT URL 发起浏览器等价的 OPTIONS 预检,并验证 Origin、PUT 和 Content-Type。只有使用无并发上传的专用测试桶时, 才可设置 DRAARL_S3_TEST_DESTRUCTIVE_CLEANUP=true 验证过期 staging 删除;默认 模式不会删除桶内其他 staging 对象。

R2 使用 <account-id>.r2.cloudflarestorage.com、Region=auto、BucketLookup=path,并启用 API 和预签名地址的 SSL。COS 使用 cos.<region>.myqcloud.com、真实 Region、包含 AppID 的 bucket 名和 BucketLookup=dns;OSS 使用 oss-<region>.aliyuncs.com、真实 Region 和 BucketLookup=dns。仓库不为存储契约保留常驻 GitHub Actions;此类测试使用专用测试环境按需手动执行,测试凭据不得写入仓库。GitHub Actions 只保留 Release 和 MkDocs Pages。

客户端资源的完整 HTTP 生命周期测试还需要名称以 draarl_test_ 开头的专用 MySQL 数据库。它会先使用临时 local 目录,再在提供 DRAARL_S3_TEST_* 时使用 同一 S3 目标,覆盖 JWT 管理员鉴权、多目标直传、服务端 SHA-256、complete、 发布、manifest、按需签名下载、Range、ETag、撤回和固件隔离:

DRAARL_CLIENT_RESOURCE_E2E=true \
DRAARL_TEST_MYSQL_DSN='user:password@tcp(127.0.0.1:3306)/draarl_test_client_resource_http?charset=utf8mb4&parseTime=true&loc=Local' \
DRAARL_S3_TEST_PROVIDER=minio \
DRAARL_S3_TEST_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_PRESIGN_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_ACCESS_KEY=test-access-key \
DRAARL_S3_TEST_SECRET_KEY=test-secret-key \
DRAARL_S3_TEST_BUCKET=draarl-contract \
DRAARL_S3_TEST_BUCKET_LOOKUP=path \
go test ./internal/handler -run '^TestClientResourceHTTPE2E$' -count=1 -v

4.9 JWT 与设备认证

字段 说明
JWT.Secret JWT 签名密钥,最少 32 字符。不符合要求时程序会自动生成并写入配置文件。
DeviceAuth.AESKey 设备密码加密密钥,必须为 16、24 或 32 字节。不符合要求时程序会自动生成并写入配置文件。

4.10 中心间群组互联

dev 的中心互联只使用两个现有端口:HTTP/HTTPS 服务承载低频邀请准入,System.Port 承载普通设备和互联音频。不存在第三个中心互联 TLS 端口。

管理员在“群组管理 → 中心互联”生成邀请。A 选择本地群组和收发控制后得到一次性 Token; B 填入 Token、A 的 HTTP/HTTPS 地址、B 的本地群组和 B 侧收发控制。B 服务端用 Token secret 生成 HMAC 准入证明,A 校验后创建 AES-GCM UDP 会话;响应中的会话、端点、群组和 策略摘要也带有 HMAC,B 校验后才落库。HTTP 响应不会返回会话密钥,两端用 Token verifier 和 session ID 独立派生密钥,随后在主 UDP 端口交换经过认证的 CPUD 音频数据。两端的用户、 设备和权限保持独立,远端音频在本地显示为 Server-* 虚拟设备。

邀请按 Interconnect.RegistrationTokenTTL 自动过期;过期后需要重新生成邀请。

启用中心互联所需的配置如下:

Interconnect:
  Enabled: false
  CenterID: "center-a"
  RegistrationTokenTTL: 86400
  CredentialRotationGraceSeconds: 600
  SessionRecoveryWindowSeconds: 180

生产部署应让管理 HTTP 经过 HTTPS。准入接口有请求体、超时、响应大小和源 IP 限速;UDP 会话有地址绑定、重放窗口、包速率和队列上限。详细的接口、数据面和故障处理见 多中心群组互联。

旧无数据库边缘运行时只保留在 edge 分支。dev 不读取边缘配置,也不启动旧 Type 0 控制面;需要维护旧边缘部署时应在 edge 分支查看对应文档。

4.11 设备接入点发现

设备接入点发现在管理员后台的“站点配置 → 接入点”中管理,不再读取 config.yaml。当前列表只发布本主站的中心入口;管理员可以调整发现凭证和客户端 缓存时长,保存后立即生效。平台只返回入口列表;网络延迟由客户端自行 ICMP 测量, 不由服务器代测。

中心位于 NAT 或 FRP 后方时,“公网 UDP 地址”和“公网 UDP 端口”应填写设备实际 访问的外部地址和映射端口,而不是中心的内网监听地址。列表不会返回控制地址、凭据 或运维指标。多收发器和多个中心入口暂不加入该接口。

4.12 群组自动播报

自动播报只在中心完整模式执行。Broadcast.Enabled 是部署级硬开关,默认关闭;Compose 首次生成配置时由 DRAARL_BROADCAST_ENABLED 写入,已有配置卷不会因修改环境变量而 自动重写。启用后还需保证统一对象存储可用,并安装可执行的 ffmpeg/ffprobe;官方镜像 已经固定版本并通过容器健康检查验证 16kHz 单声道 Opus 编码链路。

字段 默认值 有效范围/说明
Enabled false 部署级开关;修改配置后重启
QuietWindowSeconds 5 1-30 秒,触发前活动通信域必须持续静默
MaxAudioDurationSeconds 30 1-60 秒,服务端硬上限 60 秒
MaxUploadBytes 20971520 1 KiB-100 MiB,原始文件上限
TranscodeTimeoutSeconds 90 5-300 秒,探测与转码总超时
TranscodeMemoryLimitMB 512 512-1024 MiB,Linux 子进程地址空间上限
TranscodeCPULimitSeconds 60 1-300 秒,Linux 子进程累计 CPU 时间上限
ScanIntervalMS 1000 250-5000ms,到期计划扫描间隔
RecoveryWindowSeconds 10 1-300 秒,只恢复重启附近的短暂到期轮次
ClaimBatchSize 20 1-100,每轮最大认领数
FFmpegPath / FFprobePath 程序名 可执行文件路径

站点管理员可用 PUT /api/broadcast/runtime 持久化日常运行开关,或用 POST /api/broadcast/emergency-stop 取消当前任务。这两项不修改部署级配置;运行态重新 开启时不会补发停用期间错过的轮次。监控使用 /api/broadcast/health 和 /api/broadcast/metrics。完整计划、互联、状态和记录契约见 群组自动播报 API。

射频台站设备由相应台站管理员自行接入、配置并对其射频运行负责。平台只向已经审核的 用户提供服务;自动播报音频和计划仅允许平台管理员或实体组群主管理,并由相应管理员 维护和审查播报内容。

5. 后端运行

go mod download
go build -o draarl ./cmd/draarl
./draarl -c config.yaml

常用启动参数:

参数 说明
-c <path> 指定配置文件。
--edge / --interconnect 仅 edge 分支提供的无中心依赖边缘启动参数;dev 分支不包含该入口。
-v 打印版本信息。
-p json 打印关键配置。
-auto-migrate 显式创建或升级数据库结构;目标数据库完全没有表时,省略该参数也会自动初始化。
-reset-admin-pass <password> 重置管理员密码。
-migrate-storage <from:to> 跨存储驱动或 profile 迁移对象(如 minio:local 或 minio-prod:r2-prod),纯命令行,不启动主服务。
-migrate-dry-run 配合 -migrate-storage,仅统计迁移计划,不实际写入。
-migrate-delete-source 配合 -migrate-storage,迁移并校验成功后删除源端对象(默认保留)。
-migrate-max-bytes-per-second 配合 -migrate-storage,限制所有迁移 worker 合计读取源端的速率(字节/秒;默认 0 不限速)。

6. 存储引擎迁移

在不同存储引擎之间迁移文件对象(例如从 MinIO 迁到本地磁盘,或反向)。该命令为纯命令行工具,不启动主服务,也不修改数据库——因为数据库中保存的是 object key,两种引擎通用,迁移只是按 key 把对象从源端拷贝到目标端。

# 预览:只统计不写入
./draarl -c config.yaml -migrate-storage minio:local -migrate-dry-run

# 通过命名 profile 从 MinIO 迁移到 R2
./draarl -c config.yaml -migrate-storage minio-prod:r2-prod -migrate-dry-run

# 正式迁移(保留源端,便于验证)
./draarl -c config.yaml -migrate-storage minio:local

# 验证无误后,迁移并删除源端对象
./draarl -c config.yaml -migrate-storage minio:local -migrate-delete-source

要点:

  • 源与目标从同一份配置读取:minio:local 使用旧的 Storage.MinIO 与 Storage.Local;minio-prod:r2-prod 使用 Storage.Profiles 中两个独立 profile。迁移完成后,把 Storage.ActiveProfile 或 Storage.Driver 改成目标再启动服务。
  • 仅支持跨引擎:local:local、minio:minio 会被拒绝。同引擎换桶/换路径属高级场景,请用专用工具(如 mc mirror、rsync)。
  • 断点续传:目标端已存在同 key 且大小一致的对象会被跳过,因此进程意外退出后直接重跑即可,不会重复传输。写入为原子操作,崩溃不会残留半个对象。
  • 非破坏:默认只拷贝不删除源端。确认迁移结果无误后,再用 -migrate-delete-source 清理源端。
  • 跳过范围:staging/(未完成的临时上传)和 frontend/(CDN 同步产物)不迁移。
  • 历史绝对 URL:早期以完整 URL 存储的 logo/favicon 不在迁移范围内,如更换引擎后断链需重新上传。

7. 数据库迁移

当目标数据库完全没有表时,普通启动会自动执行 GORM 迁移并初始化表结构:

./draarl -c config.yaml

只要数据库中已经存在任意一张表,普通启动就不会修改数据库结构。创建缺失表、升级已有结构或清理遗留字段时,必须显式传入 -auto-migrate:

./draarl -c config.yaml -auto-migrate

群组自身呼号和设备准入白名单停用后,普通启动会直接忽略历史 public_groups.call_sign、public_groups.allow_callsign_ssid 列;显式执行 -auto-migrate 时会删除遗留列。表或列已经不存在时会安全跳过。 如果准入白名单列仍有非空配置,迁移会中止并要求先人工确认清理,避免静默丢失数据。

自动迁移会:

  • 清理部分重复或孤儿数据。
  • 自动创建/更新核心表结构。
  • 建立级联外键约束。
  • 确保 users.callsign、devices(owner_id, ssid) 等唯一索引。
  • 删除 group_members 历史设备级字段。

生产环境首次升级前建议备份数据库。

历史 v1.1.5-alpha1 的 Type 0 首次上线资料见历史升级说明。 从更早版本升级到 v2.0.0-alpha3 时,幽灵多端、频道消息和投递快照迁移见历史升级说明。

8. 管理员初始化

首次启动时,如果数据库中不存在名为 admin 的用户,程序会创建默认管理员并在日志输出随机密码。该用户:

  • 用户名:admin
  • 角色:admin
  • 审核状态:已通过

重置管理员密码:

./draarl -c config.yaml -reset-admin-pass "NewPassword123"

9. 前端开发运行

cd www
npm install
npm run dev

当前 vite.config.ts 中开发服务器端口为 9001,并将 /api 代理到 http://localhost:9002。如果后端 Web 端口不是 9002,需要调整开发环境的 API 地址或代理配置。

10. 发布构建

Unix/macOS/Linux:

./build.sh v1.2.3

Windows:

.\build.bat v1.2.3

发布脚本流程:

  1. 清理旧产物。
  2. 构建 www/dist。
  3. 将前端产物复制到 internal/server/web/dist。
  4. 使用 -tags=embed 构建后端,将前端嵌入二进制。
  5. 清理临时嵌入目录。

发布模式下,Go 二进制可同时提供 API 和前端页面。非 embed 构建只提供 API,访问前端路由会返回 frontend not embedded, build with -tags=embed。

11. 相关 API

Method Path Auth 说明
GET /api/platform/info Public 平台信息。
GET /api/platform/totalstats Public 平台统计。
GET /api/config/public Public 公开站点配置。
GET /api/config/category/:category JWT 分类配置读取。
GET /api/config/all Admin 全部配置。