Wavelog 集成

Wavelog 集成(Wavelog Integration)

目录

Worker 运行起来之后,你需要告诉 Wavelog 到哪里去找它。本页介绍 Wavelog 这一侧的配置。

前提条件

  • Worker 已运行且可访问(见安装)
  • 你已拿到在 Worker 的 config.yaml 中设置的 worker_secret 值
  • 你知道 Worker 的内部 API URL(例如 http://localhost:9001 或 http://wavelog-worker:9001)。对于集群,这就是 worker 前面那个负载均衡器或 Kubernetes 服务的 URL,一个 URL 就够了。
  • 你知道 Worker 的公共 WebSocket URL(例如 wss://your-domain.example/worker)

Wavelog 配置

以 application/config/worker.sample.php 为基础创建新文件 application/config/worker.php,并填入所需的值:

<?php

/*
| -------------------------------------------------------------------------
| Wavelog Worker Configuration
| -------------------------------------------------------------------------
|
| Optional WebSocket gateway for real-time updates in the browser. Requires
| the separate wavelog_worker service. Set worker_enabled = true to activate.
| Wavelog falls back to the classic AJAX heartbeat when disabled.
|
*/

// Enable or disable the Worker integration entirely.
$config['worker_enabled'] = true;

// Internal URL of the Worker (PHP -> Worker, HTTP).
// Single instance: the URL of your worker.
// Cluster: the URL of your load balancer / k8s service in front of the workers.
// The cluster nodes are discovered automatically (Worker 0.3.0 or newer), so
// one URL is enough. A cluster needs a Redis / Valkey instance, see the
// wavelog_worker sample config.yaml.
$config['worker_url'] = 'http://127.0.0.1:9001';

// Shared secret — must match worker_secret in the worker's config.yaml.
// Generate with: openssl rand -hex 32
$config['worker_secret'] = '';

// Timeout for publish calls in seconds (float). Keep it short:
// a slow worker must not block QSO saves.
$config['worker_timeout'] = 1.0;

// Public WebSocket URL for the browser (Browser -> Worker).
// May differ from worker_url when behind a reverse proxy or in Docker.
// Format: ws://host:port or wss://host:port. Empty = no WebSocket in browser.
$config['worker_client_url'] = 'ws://log.example.org:9000';

提示:Docker 部署

如果 Wavelog 与 Worker 运行在同一个 Docker Compose 栈中,请把服务名用作主机名:

php $config['worker_url'] = 'http://wavelog-worker:9001';

升级到 worker_url

较早的 Wavelog 版本用两个键表示 worker 地址:worker_vip(负载均衡器 URL)和 worker_urls(每个 worker 节点一项的列表,调试页面会逐个轮询)。从 Worker 0.3.0 起,节点会在 Redis 中自我通告,任何节点都能报告整个集群,因此 Wavelog 只需要一个 URL。这个 URL 就是新键 worker_url。

在 application/config/worker.php 中要改的地方:

你的现状 设置
单个 worker,worker_urls = ['http://host:9001'] $config['worker_url'] = 'http://host:9001';
设置了 worker_vip 的集群 $config['worker_url'] = <your worker_vip>;
没有 worker_vip、但有多个 worker_urls 的集群 $config['worker_url'] = <load balancer / service URL, or any one node>;

然后把 worker_vip 和 worker_urls 删掉。

  • 什么都不改也不会出问题。 当 worker_url 为空时,仍然会读取 worker_vip 和 worker_urls,但它们已被弃用,并将在 Wavelog Worker 1.0.0 版本中移除。在那之前,调试页面会显示一条提醒。
  • 如果 Worker 低于 0.3.0,调试页面上的逐节点概览仍然依赖 worker_urls 列出每个节点。请先更新 Worker,再切换到 worker_url。
  • 调试页面仍和以前一样显示节点数和「Degraded」标记;只是现在这些信息来自 Worker,而不再轮询每个节点。「Degraded」的含义见集群 → 节点生命周期。

集成如何工作

下图展示了实时会话的完整生命周期(例如一场比赛、一个实时仪表盘,或任何使用 Worker 的功能):

sequenceDiagram
    participant PHP as Wavelog PHP
    participant W as Worker :9001
    participant B1 as Client A (Browser)
    participant B2 as Client B (Browser)

    Note over PHP,W: Session starts
    PHP->>W: POST /internal/register<br/>{topic, require_token: true}
    W-->>PHP: 200 OK

    Note over B1,W: Clients connect
    PHP-->>B1: Page load (includes auth token + WS URL)
    B1->>W: WebSocket /ws?topic=...
    B1->>W: {type: "auth", token: "..."}
    W-->>B1: {type: "auth_ok"}

    PHP-->>B2: Page load (includes auth token + WS URL)
    B2->>W: WebSocket /ws?topic=...
    B2->>W: {type: "auth", token: "..."}
    W-->>B2: {type: "auth_ok"}

    Note over B1,PHP: Client A triggers an update
    B1->>PHP: POST (action via AJAX)
    PHP->>W: POST /internal/publish<br/>{topic, payload}
    W-->>B1: {type: "push", payload: ...}
    W-->>B2: {type: "push", payload: ...}

主题

每个会话都有自己的主题——一个不透明的字符串标识,用于把已连接的浏览器归组。Wavelog 在功能被激活时创建主题,并把它注册到 Worker。加入同一会话的其他客户端在加载页面时会收到相同的主题和认证令牌。

认证

当 Worker 主题以 require_token: true 注册时,每个浏览器都必须把有效的 HMAC 令牌作为第一个 WebSocket 帧提交。该令牌由 PHP 用共享密钥生成,包含过期时间戳,并在页面加载时嵌入其中。

令牌按设计就是短时效的:如果它在连接保持打开期间过期,下一次 AJAX 心跳会返回 401,Worker 会以 auth_expired 错误关闭连接。随后页面会重新加载并自动获取新令牌。

内部 API 端点

这些端点仅供 Wavelog 的 PHP 后端使用。在正常运行中不应手工调用它们。

所有请求都必须包含 X-Worker-Secret 请求头。

POST /internal/register

在任何浏览器能够连接到某个主题之前,先注册该主题。

{
  "topic": "session:abc123",
  "meta": {
    "require_token": true
  }
}

POST /internal/unregister

会话结束时移除主题。

{
  "topic": "session:abc123"
}

POST /internal/publish

把负载广播给订阅某个主题的所有浏览器。

{
  "topic": "session:abc123",
  "payload": { ... }
}

主题未注册时返回 404。Wavelog 的处理方式是重新注册并重试。

GET /internal/status

返回一个 JSON 状态对象,包含运行时长、已连接客户端数和已注册主题。便于监控。

curl -s -H "X-Worker-Secret: your-secret" http://localhost:9001/internal/status
{
  "status": "ok",
  "version": "0.3.0",
  "uptime": "14m22s",
  "registered_topics": 2,
  "active_topics": 2,
  "connected_clients": 5,
  "connected_sockets": 6,
  "cluster_nodes": -1,
  "nodes": [
    {
      "id": "3f9c2a1b7d4e6f80",
      "name": "logbook-host",
      "version": "0.3.0",
      "started_at": "2026-09-21T08:00:00Z",
      "seen_at": "2026-09-21T08:14:22Z",
      "active_topics": 2,
      "connected_clients": 5,
      "connected_sockets": 6,
      "alive": true,
      "uptime": "14m22s",
      "uptime_seconds": 862
    }
  ]
}

加上 ?topics=1 可包含 topic_list 和 active_topic_list。nodes 列出每个集群成员(单实例模式下只有这个 worker),见集群。

故障排查

浏览器无法连接 / WebSocket 失败

  • 检查 WebSocket URL(worker_client_url)是否正确,HTTPS 站点应使用 wss://。
  • 确认你的反向代理会传递 Upgrade: websocket 请求头(见安装 → 反向代理)。

PHP 无法访问内部 API

  • 检查 worker_url 指向的是 9001 端口,而不是 9000。
  • 确认防火墙或 Docker 网络规则允许 PHP → Worker 使用 9001 端口。

topic not registered(来自 /internal/publish 的 HTTP 404)

  • Worker 可能已重启,丢失了内存中的注册表。Wavelog 会自动处理:它捕获 404,重新注册主题,然后重试发布。
  • 在 Redis 集群模式下,主题存储在 Redis 中,可以跨重启保留。

auth_expired WebSocket 错误

  • 浏览器的认证令牌已过期。页面会自动重新加载并获取新令牌。长时间空闲后这是预期行为。
Wavelog 手册(中文版) / Wavelog 集成 0 字 0 行 bg8lng
2026-10-21T12:42:36.537635302Z 2026-10-21T12:44:14.669411523Z