
消息总线如何打通实时通知bitcore-wallet-service 的 MessageBroker、邮件与 FCM 推送全链路解析【免费下载链接】bitcore-wallet-serviceA multisig, HD Bitcoin and Bitcoin Cash wallet service. Used by Copay.项目地址: https://gitcode.com/gh_mirrors/bi/bitcore-wallet-servicebitcore-wallet-serviceBWS是 Copay 背后的多签名 HD 比特币/比特币现金钱包服务端。它除了保管钱包数据还负责把收到一笔付款交易提案已批准等事件实时推给用户。这条链路由三个角色组成MessageBroker 消息总线负责跨进程广播事件EmailService负责多语言邮件通知PushNotificationsService负责通过 FCMFirebase 云消息把消息推送到手机。下面用 6 个小节带你把整条链路走通。1. 全链路架构一条消息的完整旅程先用一张文字流程图建立整体印象用户操作/链上事件 服务端 BWS 消息总线 通知消费者 ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ ┌────────────────┐ │ 发起交易提案 │────▶│ _notify() │────▶│ MessageBroker │───▶│ EmailService │──▶ 邮箱 │ 新加入协付人 │ │ 存库发事件 │ │ (socket.io, │ │ FCM 推送服务 │──▶ 手机 │ 链上到账/广播 │ └──────────────┘ │ 端口3380) │ └────────────────┘ └──────────────┘ └─────────────┘关键点BWS、邮件服务、推送服务、区块链监控bcmonitor是各自独立的 Node.js 进程它们之间不共享内存全靠消息总线喊话。这就是为什么需要一个 Broker。2. MessageBroker不到 50 行的消息总线组件 源码位置lib/messagebroker.js客户端封装messagebroker/messagebroker.js独立 Broker 服务MessageBroker 本质上是一个带本地/远程双模式的EventEmitter封装设计非常小巧运行模式触发条件行为本地模式配置中未设置messageBrokerServersend()直接在进程内emit(msg)零依赖远程模式配置了 Broker 地址通过socket.io-client连接 Broker事件经网络转发独立的 Broker 服务messagebroker/messagebroker.js全部逻辑只有两句话的语义收到任何msg事件就把它广播给所有已连接的客户端默认监听3380端口。这意味着扩展性强BWS 开了 4 个 cluster 实例每个实例都连 Broker 即可任一实例产生的事件所有邮件/推送进程都能收到降级简单单机小部署时把config.js中的messageBrokerServer注释掉总线自动退化为进程内事件一个进程搞定一切。配置示例位于config.js的messageBrokerOpts字段。3. 通知从哪来_notify 与 Notification 模型 源码位置lib/server.js_notify方法、lib/model/notification.jsBWS 核心服务里每个重要动作都会调用_notify(type, data)它做两件事落库构造一条Notification含type、data、walletId、creatorId、自增ticker存入 MongoDB作为可查询的历史记录广播调用messageBroker.send(notification)把同一条通知发到总线上。事件的触发点主要有三类协作事件协付人加入钱包NewCopayer、钱包组建完成WalletComplete——见lib/server.js的_addCopayerToWallet交易提案事件NewTxProposal、提案被全体拒绝TxProposalFinallyRejected等链上事件区块链监控进程lib/blockchainmonitor.js订阅节点的新块/新交易检测到钱包地址到账时发出NewIncomingTx检测到多签名交易上链广播时发出NewOutgoingTx。这里还有一个贴心的去重细节——会先查 24 小时内是否已对同一txid发过通知避免重复推送。 值得学习的设计通知先入库、再广播。即使某个消费者进程宕机事件也不会凭空消失这是分布式系统里先持久化、后分发的经典做法。4. 邮件通知7 种事件 × 4 种语言的模板体系 源码位置lib/emailservice.js 模板目录lib/templates/{en,es,fr,ja}/EmailService 启动时订阅总线消息messageBroker.onMessage(self.sendEmail)收到通知后走一条流水线匹配事件类型 → 过滤收件人 → 渲染 Mustache 模板 → 写入邮件记录 → 通过 nodemailer 发送4.1 事件类型与发给谁规则lib/emailservice.js顶部的EMAIL_TYPES表定义了 7 种邮件并用notifyDoer/notifyOthers两个布尔位精确控制收件范围事件类型模板文件通知操作者通知其他人NewCopayernew_copayer✗✓WalletCompletewallet_complete✓✓NewTxProposalnew_tx_proposal✗✓NewIncomingTxnew_incoming_tx✓✓NewOutgoingTxnew_outgoing_tx✓✓TxProposalFinallyRejectedtxp_finally_rejected✗✓TxConfirmationtx_confirmation✓✗这个矩阵非常符合多签钱包的直觉别人发起的提案不需要再发信给发起人交易确认到账则只提醒发起人本人你等的那笔钱到了。4.2 模板文件格式第一行是主题模板是纯文本文件例如lib/templates/en/new_incoming_tx.plain只有两行{{subjectPrefix}}New payment received A payment of {{amount}} has been received into your wallet._compileTemplate约定第一行为邮件主题、其余为正文再交给 Mustache 渲染。金额会按每个协付人的偏好单位BTC / bits / BCH格式化语言不支持时自动回退到defaultLanguage。4.3 防重复发送分布式锁 数据库查重多进程部署时同一条通知可能被多个 EmailService 实例同时消费。BWS 用双保险解决先查库fetchEmailByNotification发现该通知已有邮件记录则直接返回发送全程包裹在lock.runLocked(email- notification.id, ...)分布式锁内锁服务由lib/lock.jslocker/locker.js提供。发送成功/失败都会回写状态setSent/setFail方便运维排查。5. FCM 移动推送从总线消息到手机屏幕 源码位置lib/pushnotificationsservice.js、lib/model/pushnotificationsub.js、进程入口pushnotificationsservice/pushnotificationsservice.jsPushNotificationsService 与 EmailService 几乎是镜像结构同样订阅总线、同样用 7 类事件 Mustache 模板推送的TxConfirmation额外带notifyCreatorOnly: true差异集中在投递方式订阅关系每个协付人注册的 FCM token 存在PushNotificationSub模型中字段copayerId、token、packageName、platform一个协付人可以有多个设备 token推送报文priority: high、指定restricted_package_name防止其他 App 冒领通知点击行为FCM_PLUGIN_ACTIVITY隐私细节data字段里的walletId、copayerId都做了 SHA-256 哈希即使 token 泄露也难以反查身份发送通道POST 到pushServerUrl /sendconfig.js中默认指向 FCM 的fcm.googleapis.com/fcm请求头携带Authorization: keyauthorizationKey服务账号密钥。⚠️ 新手提醒config.js里的authorizationKey默认值是占位符You_have_to_put_something_here启动时会直接报错Missing authorizationKey attribute in configuration.——这是推送服务最常见的启动故障。6. 一键部署app.js 把全家桶串成一条生产线 源码位置app.js、各进程入口locker/、bcmonitor/、emailservice/、fiatrateservice/app.js用child_process.spawn依次拉起 7 个进程正好对应整条链路的全部角色#进程职责1locker/locker.js分布式锁服务2messagebroker/messagebroker.js消息总线socket.io 广播3bcmonitor/bcmonitor.js区块链监控产出链上事件4emailservice/emailservice.js邮件消费者5pushnotificationsservice/pushnotificationsservice.jsFCM 推送消费者6fiatrateservice/fiatrateservice.js法币汇率刷新7bws.jsBWS 核心 API 服务部署时只需保证config.js中各服务的端口、MongoDB 地址、邮件 SMTP、FCM 密钥配置正确然后运行node app.js或start.sh即可。7. 新手常见问题 FAQQ1本地开发要不要启动 Broker不需要。注释掉config.js中messageBrokerOpts.messageBrokerServer即可MessageBroker 自动切到进程内事件模式app.js里对应进程不启动也无影响。Q2如何新增一种通知语言在lib/templates/下新建语言目录如de/放入 7 个.plain模板文件即可服务启动时会自动扫描目录识别可用语言。Q3为什么邮件和推送共用一套模板因为两者消费的是同一条总线消息模板只负责把通知数据变成人类可读文本与投递渠道解耦——这正是消息总线带来的最大收益事件生产方完全不需要知道谁来消费、怎么消费。总结这套设计的三个可复用思想 读完全链路bitcore-wallet-service 的通知系统给新手留下三点值得抄作业的架构思想总线解耦事件生产者BWS、bcmonitor与消费者邮件、FCM通过 46 行的 MessageBroker 完全解耦增删消费者零改动生产者先持久化再分发Notification 入库后才广播配合分布式锁和数据库查重多进程下依然至少一次且仅一次地触达用户模板与渠道分离Mustache 模板 多语言目录让通知说什么和通知怎么送达各自独立演进。从一条 46 行的消息总线出发BWS 用极少的代码量搭出了一条完整、可靠、可扩展的实时通知流水线——这也是它至今仍是 Copay 生态底座的原因。【免费下载链接】bitcore-wallet-serviceA multisig, HD Bitcoin and Bitcoin Cash wallet service. Used by Copay.项目地址: https://gitcode.com/gh_mirrors/bi/bitcore-wallet-service创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考