 下发机制)
NocoBase 通知管理 API 详解BaseNotificationChannel、registerChannelType 与 send() 下发机制【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase本文基于 NocoBase 官方文档 通知管理 API 参考结合nocobase/plugin-notification-manager插件的真实源码系统讲解通知管理系统的核心 API抽象渠道类BaseNotificationChannel、服务端插件PluginNotificationManagerServer的registerChannelType()与send()方法、接收人类型ReceiversType的取值规范以及客户端渠道注册的类型定义。读完本文你将能够独立开发并注册一个自定义通知渠道如短信、企业微信等理解通知消息的队列下发、模板编译与发送日志机制。一、模块定位与整体结构NocoBase 的通知能力由nocobase/plugin-notification-manager核心插件提供内置渠道邮件、站内信以独立插件形式扩展它。从源码目录 plugin-notification-manager 可以看到其分层服务端src/server/plugin.ts中的PluginNotificationManagerServer对外暴露注册与下发 APImanager.ts中的NotificationManager实现队列/即时下发、模板编译、日志记录base-notification-channel.ts定义所有渠道必须继承的抽象类types.ts集中定义SendOptions、ReceiversOptions等类型。客户端src/client/提供NotificationManager文档中称PluginNotificationManagerClient渠道类型注册库供各渠道插件挂载配置表单组件。数据模型src/constant.ts定义了四张集合——templates模板、notificationChannels渠道实例、messages消息资源挂载send动作、notificationSendLogs发送日志。内置渠道插件如 plugin-notification-email 与 plugin-notification-in-app-message 都只做了继承抽象类 注册这一件事这正是本文 API 的设计目标。二、服务端 API2.1BaseNotificationChannel用户渠道类型的抽象基类BaseNotificationChannel是用户渠道类型的抽象类定义了通知渠道需要的接口扩展新的通知渠道类型需要继承此类并实现其中的send方法。源码位于 base-notification-channel.tsimport { Transactionable } from nocobase/database; import { Application } from nocobase/server; import { ChannelOptions, ReceiversOptions } from ./types; export abstract class BaseNotificationChannelMessage any { constructor(protected app: Application) {} abstract send(params: { channel: ChannelOptions; message: Message; receivers?: ReceiversOptions; transaction?: Transactionable[transaction]; }): Promise{ message: Message; status: success | failure; reason?: string }; }结合 types.ts 中的ChannelOptions定义可以明确send入参各字段的含义字段类型说明channelChannelOptions渠道实例包含name: string渠道标识、options: Recordstring, any用户在管理界面填写的渠道配置如 SMTP 主机、账号、notificationType: string渠道类型标识messageMessage泛型经过模板编译后的消息对象具体结构由渠道自行约定如邮件为{ to, cc, bcc, subject, html/text }receiversReceiversOptions?接收人结构见 ReceiversType 一节transactionTransactionable[transaction]?数据库事务句柄渠道若需要写库如站内信可传入需要注意的一点官方文档示例中status写为success | fail而当前仓库源码中的实际返回类型是success | failuremanager.ts 中判定失败、写入日志时用的也是failure以源码为准。2.2PluginNotificationManagerServer注册渠道类型PluginNotificationManagerServer是通知管理服务端插件提供通知渠道类型注册方法和通知下发方法。其完整实现见 plugin.ts核心公开方法为registerChannelType()、send()、sendNow()与sendToUsers()。registerChannelType()签名与示例注册渠道类型的服务端入口签名来自 types.ts 的RegisterServerTypeFnParams为registerChannelType({ type, Channel }: { type: string, Channel: BaseNotificationChannel, useQueue?: boolean })type渠道类型标识string需与客户端注册时的type保持一致如email、in-app-messageChannel继承自BaseNotificationChannel的渠道类构造函数useQueue可选默认true控制该渠道下发时走事件队列还是同步发送。官方文档给出的完整样例如下import PluginNotificationManagerServer from nocobase/plugin-notification-manager; import { Plugin } from nocobase/server; import { ExampleSever } from ./example-server; export class PluginNotificationExampleServer extends Plugin { async load() { const notificationServer this.pm.get(PluginNotificationManagerServer) as PluginNotificationManagerServer; notificationServer.registerChannelType({ type: example-sms, Channel: ExampleSever }); } } export default PluginNotificationExampleServer;仓库内置的邮件渠道插件就是这样注册的见 plugin-notification-email/src/server/plugin.tsasync load() { const notificationServer this.pm.get(PluginNotificationManagerServer) as PluginNotificationManagerServer; notificationServer.registerChannelType({ type: channelType, Channel: MailNotificationChannel }); }其中channelType的取值为email定义于 plugin-notification-email/src/constant.ts。从源码结构看PluginNotificationManagerServer.registerChannelType()只是把参数转发给内部NotificationManager.registerType()后者将其存入一个RegistrychannelTypes键为渠道类型标识值为{ Channel, useQueue }注册后的类型在发送阶段被sendNow通过new Channel(app)实例化并调用instance.send(...)。一个值得注意的细节站内信渠道注册时显式关闭了队列见 plugin-notification-in-app-message/src/server/plugin.tsnotificationServer.registerChannelType({ type: inAppTypeName, Channel: InAppNotificationChannel, useQueue: false });这是因为站内信写入本系统数据库若与业务操作在同一事务中需要同步发送才能保证数据一致性见下文 2.3 节的transaction机制。2.3send()通知下发方法send()是通知下发的主入口调用此方法可下发通知。文档示例展示了两种典型调用站内信与邮件send(in-app-message, message:[ receivers: [1, 2, 3], receiverType: userId, content: 站内信测试, title: 站内信测试标题 ], triggerFrom: workflow) send(email, message:[ receivers: [a163.com, b163.com], receiverType: email, content: 邮箱测试, title: 邮箱测试标题 ], triggerFrom: workflow)当前仓库源码中send的规范签名是以SendOptions对象为入参plugin.ts 中async send(options: SendOptions)send({ channelName: email, message: { content: 邮箱测试, title: 邮箱测试标题 }, receivers: { value: [a163.com, b163.com], type: channel-self-defined, channelType: email }, triggerFrom: workflow, })SendOptions的完整定义types.ts为export interface SendOptions extends Transactionable { channelName: string; message: Recordstring, any; triggerFrom: string; receivers?: ReceiversOptions; data?: Recordstring, any; }即文档sendConfig表格所列字段channelName、message、receivers、triggerFrom之外源码还支持data模板变量与message中的 Handlebars 占位符配合编译以及事务相关字段transaction继承自Transactionable。sendConfig 字段说明属性类型描述channelNamestring渠道标识必须是管理界面中已创建的渠道实例的name而非渠道类型messageobject消息对象结构由目标渠道约定标题、正文等receiversReceiversType接收人见下一小节triggerFromstring触发来源如workflow、sendToUsers仅用于日志与排障data源码扩展object模板变量数据用于编译message中的 Handlebars 占位符transaction源码扩展Transactionable数据库事务传入后通知将在事务提交后afterCommit再下发除上述send()外源码还暴露两个便捷方法sendNow(options)跳过队列同步立即发送适用于需要即时结果的场景sendToUsers(options: SendUserOptions)批量给一组用户、通过一组渠道下发同一消息内部循环调用send见 manager.ts。队列、即时发送与事务提交机制send()的内部行为manager.ts 的NotificationManager.send比文档签名揭示的更复杂理解它有助于排查消息延迟送达类问题事务内调用若options.transaction带有afterCommit钩子发送动作被延迟到事务成功提交之后执行返回值中带有queued/延迟标记若事务回滚通知不会发出。队列路径useQueue为true默认时消息被发布到事件队列频道名为${插件名}.send由 plugin.ts 中订阅该频道的处理器concurrency: 1串行消费并调用sendNow。即时路径useQueue为false时直接调用sendNow同步发送并返回真实结果。sendNow内部流程先执行 compile.ts 中的compile(message, data)——基于 Handlebars 对message中所有字符串字段做深度模板编译再按channelName从渠道缓存中查找渠道实例实例化对应Channel类并调用send无论成功失败都会向notificationSendLogs集合写入一条发送日志含channelName、channelTitle、notificationType、status、reason、receivers等。慢请求告警sendNow内置SLOW_SEND_THRESHOLD_MS 500单次发送总耗时超过 500ms 会输出 warn 级日志并附带compileMs、findChannelMs、channelSendMs分段耗时便于定位瓶颈。渠道配置本身也有缓存机制PluginNotificationManagerServer在afterStart时把所有渠道实例加载进应用缓存缓存键channels并在渠道集合的afterSave/afterDestroy钩子中重新加载所以在管理界面修改渠道配置后无需重启即可生效。2.4ReceiversType接收人类型接收人receivers目前只支持两种格式NocoBase 站内用户 IDuserId和渠道特定配置channel-self-defined与源码 types.ts 中的ReceiversOptions完全一致type ReceiversType | { value: number[]; type: userId } | { value: any; type: channel-self-defined; channelType: string };userIdvalue为 NocoBase 用户 ID 数组如[1, 2, 3]平台级语义与具体渠道无关channel-self-definedvalue为渠道自定义的接收人结构如邮件地址数组channelType指明该结构属于哪个渠道类型供渠道类自行解析。2.5 REST 资源与权限除了编程式调用PluginNotificationManagerServer在beforeLoad阶段还向资源管理器注册了messages资源并定义了send动作ctx.action.params.values作为SendOptions传入因此也可以通过 API 触发下发同时注册了两段 ACL 片段pm.notification.channels对应notificationChannels:*动作与pm.notification.logs对应notificationSendLogs:*动作。渠道与日志资源的 OpenAPI 描述见 swagger/index.ts。三、客户端 API3.1 客户端渠道类型注册库客户端侧由PluginNotificationManagerClient源码中默认导出的NotificationManager类见 client/notification-manager.ts统一管理渠道类型export default class NotificationManager { channelTypes new RegistryRegisterChannelOptions(); registerChannelType(options: RegisterChannelOptions) { this.channelTypes.register(options.type, options); } }channelTypes已注册渠道类型库。签名channelTypes: RegistryRegisterChannelOptionsregisterChannelType()注册客户端渠道类型将渠道的显示标题、表单组件与元信息登记到channelTypes中供渠道管理页面动态渲染。签名registerChannelType(params: RegisterChannelOptions)文档中给出的registerTypeOptions类型源码对应 client/manager/channel/types.ts 的RegisterChannelOptions如下type registerTypeOptions { title: string; // 渠道显示标题 type: string; // 渠道标识 components: { ChannelConfigForm?: ComponentType // 渠道配置表单组件; MessageConfigForm?: ComponentType{ variableOptions: any } // 消息配置表单组件; ContentConfigForm?: ComponentType{ variableOptions: any } // 内容配置表单组件只是消息内容不包括接收人的配置; }; meta?: { // 渠道配置元信息 createable?: boolean //是否支持新增渠道; editable?: boolean //渠道配置信息是否可编辑; deletable?: boolean //渠道配置信息是否可删除; }; }; type RegisterChannelType (params: ChannelType) void;源码中components还额外支持懒加载形态ChannelConfigFormLoader、MessageConfigFormLoader、ContentConfigFormLoader类型均为() Promise{ default: ComponentTypeP }适合表单组件较重时按需加载。meta中的三个布尔值控制管理界面的按钮可见性例如某系统级唯一渠道可设置createable: false。客户端测试用例见 client/tests/registerType.test.ts。四、内置渠道示例send实现长什么样以邮件渠道的 MailNotificationChannel 为例可以看到BaseNotificationChannel子类send的典型写法它依据channel.options中的host/port/account/password构造 nodemailertransporter并按host:port:account作为键做静态缓存通过configMap比对配置是否变更host/port/secure/account/password/from任一字段不同则重建连接池避免重复创建连接。消息结构为{ to, cc?, bcc?, subject }加html或text二选一。服务端行为可用 server/tests/register.test.ts 作为参考测试通过createMockServer({ plugins: [notification-manager] })启动应用创建渠道记录后直接构造NotificationManager实例断言渠道类send收到的channel.options与管理界面配置一致。五、小结API端职责BaseNotificationChannel.send()服务端渠道必须实现的抽象方法签名({ channel, message, receivers?, transaction? }) Promise{ message, status: success \| failure, reason? }registerChannelType({ type, Channel, useQueue? })服务端注册渠道类型到channelTypes注册表默认走事件队列send(SendOptions)/sendNow()/sendToUsers()服务端下发通知支持事务后发送、队列串行消费、Handlebars 模板编译、notificationSendLogs日志落库channelTypes/registerChannelType(options)客户端注册渠道标题、表单组件与metacreateable/editable/deletable驱动管理界面渲染开发自定义通知渠道的完整链路即服务端继承BaseNotificationChannel实现send在插件load()中调用registerChannelType({ type, Channel })客户端以相同的type调用registerChannelType(options)挂载表单组件最后在管理界面创建渠道实例通过编程接口或 API 以channelName定位渠道调用send()下发全程可通过notificationSendLogs集合追踪每次发送的状态与失败原因。【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考