配置 Hocuspocus 服务器

介绍

目前只需传入少量设置。大多数功能通过 hooks 控制。

设置

设置描述默认值
name实例的名称,用于日志记录。
port服务器应监听的端口。80
timeout连接健康检查的时间间隔,单位为毫秒。在 v4 中已从 30s 增加到 60s。60000 (= 60s)
debounce对 onStoreDocument 钩子的调用进行去抖,时间单位为 ms。否则每次更新都会被持久化。2000 (= 2s)
maxDebounce确保至少在给定的时间(ms)内调用一次 onStoreDocument。10000 (= 10s)
quiet默认情况下,服务器会显示启动界面。如果传入 false,服务器将安静启动。false
websocketOptions传递给底层 WebSocket 服务器的选项(例如 { maxPayload: 1024 * 1024 })。在 v4 中已移到 config 对象内部。{}
maxUnauthenticatedQueueSize在单个连接尚未通过身份验证时,缓冲的最大字节数(跨所有文档)。超过后连接将被关闭。参见 预认证资源限制5242880 (= 5 MiB)
maxUnauthenticatedQueueMessages在单个连接尚未通过身份验证时,缓冲的最大消息数(跨所有文档)。超过后连接将被关闭。1000
maxPendingDocuments在任何文档完成身份验证之前,单个连接最多可打开的不同文档数量。超过后连接将被关闭。100

使用示例

import { Server } from '@hocuspocus/server'

const server = new Server({
  name: 'hocuspocus-fra1-01',
  port: 1234,
  timeout: 60000,
  debounce: 5000,
  maxDebounce: 30000,
  quiet: true,
  websocketOptions: { maxPayload: 1024 * 1024 },
})

server.listen()

通用 Context 类型

从 v4 开始,服务器接受一个通用的 Context 类型参数,以便在所有 hooks 中实现端到端的类型安全:

import { Server } from '@hocuspocus/server'

interface MyContext {
  userId: string
  permissions: string[]
}

const server = new Server<MyContext>({
  async onAuthenticate({ token }) {
    // 返回值的类型为 MyContext
    return { userId: '123', permissions: ['read', 'write'] }
  },
  async onChange({ context }) {
    // context.userId 的类型为 string
    console.log(context.userId)
  },
})

该泛型的默认值为 any,因此未显式指定类型的现有代码仍可继续正常工作。

认证前资源限制

在认证完成之前收到的消息会按连接缓存在内存中。若没有上限,未认证客户端可能会耗尽服务器内存(参见 GHSA-xwhh-v746-pj9m)。以下三个设置用于限制这种缓存,一旦超过任一限制,连接就会立即关闭:

  • maxUnauthenticatedQueueSize(默认 5 MiB)— 每个连接缓冲的总字节数。
  • maxUnauthenticatedQueueMessages(默认 1000)— 每个连接缓冲的总消息数。
  • maxPendingDocuments(默认 100)— 单个连接在任一时刻可打开的、尚未通过认证的不同文档数量。每个待处理文档都有自己的队列和 hook 负载,因此这可以阻止客户端在保持每连接队列限制之内的同时,向多个文档名分散连接。

此外,空闲 timeout 会在认证前被强制作为一个绝对的认证截止时间(从连接建立时开始计算,不会因入站流量而刷新),直到连接对其首个文档完成认证。首次认证成功后,timeout 会恢复为该 socket 在其余生命周期中的正常空闲行为。

import { Server } from '@hocuspocus/server'

const server = new Server({
  maxUnauthenticatedQueueSize: 5 * 1024 * 1024, // 5 MiB
  maxUnauthenticatedQueueMessages: 1000,
  maxPendingDocuments: 100,
})

server.listen()