Etherpad-Lite 服务器端钩子详解
概述
Etherpad-Lite 是一个开源的实时协作编辑器,其插件系统通过钩子(hook)机制提供了强大的扩展能力。本文将深入解析 Etherpad-Lite 的服务器端钩子,帮助开发者理解如何通过这些钩子扩展和定制 Etherpad-Lite 的功能。
核心生命周期钩子
loadSettings 钩子
调用时机:服务器启动时,在加载完基本配置后立即调用
上下文对象:
settings
- 包含所有配置项的对象
使用场景:这是插件获取全局配置的最佳时机,适合在此钩子中根据配置初始化插件功能。
exports.loadSettings = async (hookName, {settings}) => {
if (settings.myPlugin && settings.myPlugin.enabled) {
// 初始化插件功能
}
};
shutdown 钩子
调用时机:服务器关闭前
注意事项:
- 数据库此时已不可用
- 必须返回 Promise 对象
- 应避免长时间阻塞
典型用途:清理资源、关闭连接、保存状态等。
exports.shutdown = async () => {
await myDatabaseConnection.close();
await flushLogsToDisk();
};
插件管理钩子
pluginInstall/pluginUninstall 钩子
调用时机:插件安装/卸载时
上下文对象:
plugin_name
- 当前操作的插件名称
使用建议:适合处理插件间的依赖关系或清理插件特有的资源。
exports.pluginInstall = async (hookName, {plugin_name}) => {
if (plugin_name === 'ep_dependent_plugin') {
// 安装依赖插件时的初始化逻辑
}
};
init_ 钩子
调用时机:指定插件初始化完成后
上下文对象:
logger
- 日志记录器对象
特点:这是插件A监听插件B初始化完成的专用钩子。
Express 相关钩子
expressPreSession 钩子
调用时机:Express 会话中间件加载前
上下文对象:
app
- Express 应用对象
典型用途:添加无需会话的公开路由。
警告:此钩子添加的路由完全公开,不进行任何认证!
exports.expressPreSession = async (hookName, {app}) => {
app.get('/public-api', (req, res) => {
res.json({status: 'ok'});
});
};
expressConfigure/expressCreateServer 钩子
调用时机:Express 会话中间件加载后
上下文对象:
app
- Express 应用对象server
- HTTP 服务器对象(仅 expressCreateServer)
使用场景:添加需要会话支持的路由或中间件。
模板渲染钩子(eejsBlock_*)
Etherpad-Lite 使用 EJS 模板引擎,提供了丰富的模板块钩子。
常用模板块
pad.html:
htmlHead
-<head>
区域styles
- CSS 样式表scripts
- JavaScript 脚本editbarMenuLeft/editbarMenuRight
- 左右工具栏
修改示例:
exports.eejsBlock_styles = (hookName, {content}) => {
return content + '<link rel="stylesheet" href="/static/plugin/my-style.css">';
};
权限控制钩子
preAuthorize 钩子
调用时机:认证检查前
决策流程:
- 按注册顺序调用各插件的 preAuthorize
- 第一个返回 true/false 的插件决定访问结果
- 全部返回 undefined 则进入正常认证流程
典型用途:IP 白名单、静态资源放行等。
authorize 钩子
调用时机:用户认证通过后,授权检查时
上下文对象:
req/res
- Express 请求/响应对象resource
- 访问的资源路径
返回值处理:
[true]
- 完全授权['modify']
- 仅修改权限['readOnly']
- 只读权限[false]
- 拒绝访问
文档(Pad)相关钩子
padCreate 钩子
调用时机:新 Pad 创建时
上下文对象:
pad
- Pad 对象authorId
- 创建者 ID
使用场景:初始化 Pad 元数据、设置默认权限等。
padDefaultContent 钩子
调用时机:设置新 Pad 的初始内容时
上下文对象:
pad
- Pad 对象content
- 初始内容(可修改)
示例:
exports.padDefaultContent = async (hookName, {pad, content}) => {
if (pad.id.startsWith('template-')) {
content = await loadTemplateContent(pad.id);
}
};
padCopy/padRemove 钩子
调用时机:Pad 复制/删除时
上下文对象:
srcPad/dstPad
- 源/目标 Pad 对象(复制时)pad
- 被删除的 Pad 对象(删除时)
用途:维护插件特有的 Pad 相关数据。
最佳实践建议
- 异步处理:尽量使用 async/await 处理异步操作
- 错误处理:合理捕获和处理可能出现的异常
- 性能考量:避免在钩子中执行耗时操作
- 幂等性:确保钩子函数可重复执行而不产生副作用
- 文档注释:为自定义钩子添加清晰的文档说明
通过合理利用这些服务器端钩子,开发者可以深度定制 Etherpad-Lite 的行为,实现各种高级功能,如自定义认证流程、特殊文档处理逻辑、增强的管理功能等。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考