ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Sandstorm Activity Events 平台 API 深度解析:活动指示、通知分发与订阅机制

Sandstorm Activity Events 平台 API 深度解析:活动指示、通知分发与订阅机制 后端容器运行时安全云原生【免费下载链接】sandstormSandstorm is a self-hostable web productivity suite. Its implemented as a security-hardened web app package manager. | Actively sponsored by our friends at TestMu AI项目地址https://gitcode.com/gh_mirrors/sa/sandstorm点击查看免费下载导读Sandstorm 是一套可自托管的 Web 生产力套件其本质是一个安全加固的 Web 应用包管理器security-hardened web app package manager。本篇技术指南围绕项目路线图中规划的 Activity Events活动事件平台 API 展开应用可以通过它向 Sandstorm 汇报“值得记录或通知用户”的事件Sandstorm 则负责把事件沉淀为未读指示、分发为多种形式的通知并规划面向用户的通知订阅与组织级审计日志。读完本文你将掌握ActivityEvent与ActivityTypeDef的完整字段语义、通知生成规则的实现原理、订阅/静默机制以及这些能力在仓库源码中的真实落地位置。什么是 Activity Event按路线图文档 roadmap/platform/activity/README.md 的定义activity event活动事件指任何值得被记录log和/或通知用户notify的事件。典型例子如 Etherpad每当用户进行编辑或留下评论时Etherpad 就会上报一个活动事件。活动事件承载两个核心目标被动提示让用户无需反复打开各个 grain 翻看就能在列表中察觉“有新变化”。主动吸引通过通知把用户的注意力拉到具体事件上甚至直接引导回事件发生的页面。在接口层面Sandstorm 向应用暴露了两类上报入口见 src/sandstorm/grain.capnpSessionContext.activity()grain.capnp#L610由某个具体用户发起的活动事件会被归属attributed到发起该会话的用户头上SandstormApi.backgroundActivity()grain.capnp#L119非任何特定用户发起的事件例如后台任务、定时任务产生的状态变化对应地在 supervisor 侧也实现了同名方法supervisor.capnp#L156。此外事件的类型定义由应用通过UiView.ViewInfo.eventTypes向平台声明grain.capnp#L352平台据此知道每个 grain 可能产生哪些类型的事件从而支持类型化过滤与紧凑的活动摘要。活动指示器未读高亮路线图文档描述了第一个用户可见能力——活动指示器activity indicator有用户尚未查看过的新活动的 grain会在用户的grain 列表中被高亮若该 grain 当前正打开着则会在侧边栏中出现同样的高亮。从 shell 前端代码可以看到它的落地方式。在 shell/imports/client/grain/grainlist-client.js#L38 中grain 列表项直接由数据层的“是否已看完全部活动”字段驱动unread: !grain.ownerSeenAllActivity,对于通过 API Token 共享访问的用户grainlist-client.js#L79 则读取 token 属主元数据中的ownerData.seenAllActivityunread: !ownerData.seenAllActivity,这个seenAllActivity位也在底层 Capn Proto 协议中被正式定义在 src/sandstorm/supervisor.capnp#L378 的UserInfo中seenAllActivity 16 :Bool; # True if the user has viewed the grain since the last activity event occurred.也就是说“未读”的本质是自用户上次查看 grain 之后是否又产生了新活动。用户访问事件对应的页面路径ActivityEvent.path会隐式地把事件标记为已读见下文字段说明。ActivityEvent 数据结构事件的核心载荷活动事件的完整结构定义在 src/sandstorm/activity.capnp#L24 的ActivityEvent中。这是应用上报事件时必须填写的核心载荷字段类型语义pathText用户可以在 grain 内查看该活动的路径URL。用户点开事件时会被链接到此位置访问该路径会隐式将事件标记为“已读”。注意不能以/开头空字符串默认值表示跳到 grain 根路径threadThreadInfo若该事件属于某个“线程”则提供线程信息。例如问题跟踪应用里同一个 issue 下的所有评论属于同一线程。线程对“通知给谁”和“通知如何归组”很重要notificationNotificationDisplayInfo渲染通知的可选元数据例如通知邮件的正文或铃铛菜单中的展示内容。该元数据不会长期保存在活动日志中通知被忽略/关闭后即被丢弃简单事件可以留空typeUInt16事件类型是UiView.ViewInfo.eventTypes数组的索引。用户可以选择哪些类型的事件应通知自己usersList(User)与该事件关联的用户身份列表其中thread的ThreadInfo结构activity.capnp#L44包含path线程本身的路径用于订阅时唯一标识一个线程与ActivityEvent.path类似但不带前导/title线程标题例如用于通知邮件的主题行。注意若线程标题发生变化可能使与之相关的邮件通知形成新的邮件线程——因为邮件客户端普遍按主题行来归组邮件线程。而users列表中的每个Useractivity.capnp#L70描述某用户与事件的三种关系至少应有一个非默认字段否则列出来没有意义identity用户身份Identity.Identitymentioned该用户被事件显式“提及”类似 Twitter/GitHub 的 提及。被提及的用户即使未显式订阅该事件也可能收到通知。判断经验如果要回答“你收到这条通知是因为 ____”答案若是“你被提到了”就设mentioned truesubscribed应用自己管理“订阅”概念而不是交给 Sandstorm时若按内部计算该用户已订阅此事件则置位。效果是即使事件没有“提及”该用户他也会收到通知。注意如果应用使用了autoSubscribeToThread、autoSubscribeToGrain或 Sandstorm 的通知订阅 API一般不应使用本字段只有应用实现了自己的订阅模型时才用它canView即使该用户不满足类型定义中的requiredPermission也可以查看此事件但若用户对 grain 完全没有访问权仍然看不到。此标志适用于应用自己做了内部访问控制、不完全依赖 Sandstorm 权限的场景。事件类型定义ActivityTypeDef 与“噪音”控制路线图文档提到“应用可以标明某些事件类型应比其他类型更‘吵’noisier”这一机制在ActivityTypeDef中落地src/sandstorm/activity.capnp#L106。每个 grain 通过UiView.ViewInfo.eventTypes声明自己可能产生的事件类型字段如下字段类型语义nameText类型名称在偏好字符串 ID 的场景下使用例如 HTTP/JSON 翻译必须是字母开头、仅含字母数字的合法标识符且在同一UiView的所有类型中唯一verbPhraseLocalizedText描述行为者做了什么动词短语例如 “edited document”“created new comment”“replied to comment”。活动日志展示时可能会把同类型事件聚合计数例如Kenton Varda - 3 hours ago下列出edited document x13、created new comment、replied to comment x2descriptionLocalizedText描述该活动类型含义的散文适合作为 tooltip 或帮助文本可选requiredPermissionunion谁被允许观察此类事件everyone任何对 grain 有访问权的用户、permissionIndex拥有指定权限的用户、explicitList仅显式列出的用户obsoleteBool默认 false若为 true表示该类型在旧版应用中有用但已不再使用会从通知设置中隐藏此类事件也不再生成通知notifySubscribersBool订阅者含事件线程订阅者与 grain 订阅者默认是否应收到此类事件的通知。主要作用于两类场景一是autoSubscribeToThread/autoSubscribeToGrain创建的自动订阅二是应用更新后新增了事件类型时已订阅其他通知的用户是否默认订阅新类型autoSubscribeToThreadBool事件作者是否自动订阅其所属线程事件无threadPath时无效果。自动订阅只订阅notifySubscribers true的事件autoSubscribeToGrainBool事件作者是否自动订阅该 grain。同上只订阅notifySubscribers true的事件suppressUnreadBool若为 true此类活动不会把 grain 标记为“未读”。适用于“应该被记录但无需用户关注”的活动官方注释强调上述通知相关选项只是提示hints用户可以通过多种机制覆盖某个事件是否产生通知但这些提示被设计为合理的默认值。另外当用户通过 UI 显式订阅时有机会精确选择希望产生通知的事件类型当应用在自己的 UI 里提供“订阅”按钮并由用户点击时应用也可以为该按钮指定不同的默认值。通知展示信息由NotificationDisplayInfo承载activity.capnp#L192目前只有caption显示在通知框内的文本一个字段文件中的 TODO 还规划了更长的正文、支持文本回复的通知以及可交互富通知如播放/暂停按钮。通知的分发形式与到达渠道路线图文档列出了通知的多种送达形式右上角“铃铛菜单”未读通知到达时小铃铛图标上会出现带数字的红色圆点吸引用户点击展开菜单。用户访问通知或点击忽略后通知即被清除。侧边栏指示对于正打开着的 grain若有新通知会显示指示器。HTML5 桌面通知如果通知到达时 Sandstorm 恰好处于打开状态则弹出桌面通知。邮件通知文档标记为TODO(feature)尚未实现。前端实现可以从 shell/imports/client/notifications-client.js 看到铃铛角标数字来自notifications集合中当前用户未读记录数notifications-client.js#L143notificationCount: function () { return globalDb.collections.notifications.find({ userId: Meteor.userId(), isUnread: true }).count(); },一个值得注意的细节前台打开着标签页时会自动忽略所有指向当前 URL 的通知notifications-client.js#L55 的Tracker.autorun这正是“访问事件路径即隐式标记已读”的前端配合实现——通知携带grainId与path客户端据此构造/grain/grainId/path并与当前 URL 比对命中即调用dismissNotification。桌面通知的流程分两段服务端把通知写入desktopNotifications集合shell/imports/server/desktop-notifications.js#L20 的createAppActivityDesktopNotification客户端订阅后在 shell/imports/client/desktop-notifications-client.js#L76 的showActivityDesktopNotification中渲染为 HTML5 通知。服务端核心logActivity 的通知判定算法事件上报后到底谁会被通知、以什么规则服务端的完整实现位于 shell/imports/server/notifications-server.js#L27 的logActivity(grainId, accountIdOrAnonymous, event)。其处理流水线可概括为以下步骤解析事件类型从 grain 缓存的ViewInfo.eventTypes中按event.type索引查找类型定义找不到直接抛错No such event type in apps ViewInfo。处理未读位若类型未设置suppressUnread则清除除行为者外所有用户的seenAllActivitygrain 属主与 API Token 属主分别处理这正是活动指示器的数据来源。应用自动订阅若类型设置了autoSubscribeToGrain把行为者订阅到 grain若设置了autoSubscribeToThread且事件带thread把行为者订阅到对应线程路径db.js 的 subscribeToActivity。构建收件人映射notifyMap关键规则如下源码中的注释与逻辑顺序静默mute优先于订阅一旦某账号被静默映射值置为 false不通知自己行为者账号被当作 mute 处理隐式订阅 grain 属主属主默认被加入若notifySubscribers为真加入 grain 级订阅者getActivitySubscriptions(grainId)与线程级订阅者getActivitySubscriptions(grainId, event.thread.path)遍历event.users对每个mentioned || subscribed为真的用户通过unwrapFrontendCap解析身份对应的账号 ID 并加入收件人。写通知记录对每个收件人执行findAndModifyupsert——同一用户、同一 grain、同一事件的重复活动会聚合计数$inc: { count: 1 }并刷新isUnread与timestamp。通知记录携带grainId、path、threadPath若有、initiatingAccount发起者或initiatorAnonymous匿名用户发起以及eventType。触发桌面通知调用createAppActivityDesktopNotification把渲染所需数据发起者头像/名称、grainId、path、正文 caption、动作短语 verbPhrase写入desktopNotifications集合。订阅与静默机制路线图文档提到用户未来可以“调整每种通知类型的噪音级别或订阅特定 grain / 线程来控制哪些事件会通知自己”。订阅体系的数据层已经在 shell/imports/sandstorm-db/db.js 中就位getActivitySubscriptions(grainId, threadPath)db.js#L1874按 grain 与可选线程路径查询订阅记录只取accountId与mute字段subscribeToActivity(accountId, grainId, threadPath)db.js#L1883创建订阅记录但如果用户之前已对该 grain/线程执行过静默则不做任何事——静默优先于订阅muteActivity(accountId, grainId, threadPath)db.js#L1900通过 upsert 把对应记录的mute置为 true。这三者与logActivity中的addRecipient逻辑mute 优先共同构成了完整的“订阅-静默-通知”闭环订阅决定谁能被通知静默能在通知判定前把账号从收件人列表中剔除。规划中的功能通知线程与内联回复路线图文档为“通知线程与内联回复”标注为TODO(feature)。许多应用把活动组织成“线程”thread例如 GitHub 的每个 issue 和每个 pull request 都是一个线程。规划中的体验包括用户直接在通知界面回复线程而无需打开完整应用。例如点击铃铛菜单中的通知后可展开完整线程并就地回复对于邮件通知用户可能直接回复邮件。Sandstorm 应当负责净化sanitize该回复——例如剥离底部引用的邮件正文及其他无关信息——再回传给应用。在协议层ActivityEvent.ThreadInfo已经为线程建模提供了基础见上文而 activity.capnp#L206 的NotificationTarget与OngoingNotification接口则定义了通知目标与会话NotificationTarget.addOngoing()向目标通常是用户发送持续型通知返回一个句柄句柄被丢弃时通知移除OngoingNotification.cancel()用户请求取消底层任务时回调通知创建者。例如SandstormApi.stayAwake()场景下cancel()被调用后应用不再被保持唤醒应做好关闭准备。这两个接口也是 supervisor.capnp#L147 中getOwnerNotificationTarget()用于 grain 自身相关的通知如 wake lock 存在提示和 grain.capnp#L101 中SandstormApi.stayAwake()请求后台持续运行并借持续通知告知属主的基础。其中stayAwake的通知不需要持久化其目的就是防止应用被重启句柄也不持久化且官方注释明确警告机器故障等意外仍可能随时终止应用目前故障后应用不会被自动重启。规划中的功能审计日志与活动流路线图文档的最后一部分同样标注为TODO(feature)活动事件未来还将汇入 Sandstorm 的审计日志系统audit logging。规划要点包括用户可以看到跨其可访问的多个 grain 的统一活动流unified feed或某个 collection 内全部 grain 的活动流组织管理员可以启用组织级审计日志organization-wide audit logging监控整个组织内的全部活动。文档强调审计日志对安全很重要且常被法规强制要求例如 HIPAA。需要说明的是这部分目前在仓库中属于路线图规划而非已实现能力ActivityEvent协议、订阅/静默数据模型、通知判定与分发链路均已落地而“统一活动流界面”“组织级审计日志”“邮件通知”“通知线程内联回复”等仍标记为 TODO。引用时请注意区分已实现与规划中的能力避免过度承诺。应用接入速览从声明到上报的最小闭环综合协议与实现一个 Sandstorm 应用接入活动事件体系需要完成四件事声明事件类型在UiView.ViewInfo.eventTypes中列出ActivityTypeDef列表填写name、verbPhrase与各项通知提示位grain.capnp#L352。上报用户活动在用户执行值得记录的动作编辑、评论等时调用SessionContext.activity()构造ActivityEvent并填写path不带头/、typeeventTypes 索引、可选thread、users提及/订阅关系与notification展示信息grain.capnp#L610。上报后台活动非用户发起的活动后台任务、定时任务调用SandstormApi.backgroundActivity()grain.capnp#L119服务端会以accountId null处理通知记录标记为无发起者。让“已读”自然发生事件路径即用户查看入口前端会在用户停留于对应 URL 时自动忽略通知notifications-client.js#L55无需应用额外调用。调试时notifications-client.js#L28 提供的testNotifications()会在浏览器控制台触发一组模拟通知admin 统计、referral、identityChanges 等服务端对应实现见 notifications-server.js#L220可用于快速预览铃铛菜单与桌面通知的展示效果。结语Activity Events 是 Sandstorm 平台“被动未读指示 主动通知”双通道用户触达体系的核心协议。通过 src/sandstorm/activity.capnp 定义的ActivityEvent/ActivityTypeDef数据结构配合 shell/imports/server/notifications-server.js 中logActivity的通知判定算法与 shell/imports/sandstorm-db/db.js 的订阅/静默数据模型Sandstorm 在协议层、服务端逻辑与前端交互三个层面都已具备完整骨架邮件通知、线程内联回复与组织级审计日志则作为明确的 TODO 进入路线图等待后续迭代落地。赞分享后端容器运行时安全云原生【免费下载链接】sandstormSandstorm is a self-hostable web productivity suite. Its implemented as a security-hardened web app package manager. | Actively sponsored by our friends at TestMu AI项目地址https://gitcode.com/gh_mirrors/sa/sandstorm点击查看免费下载相关推荐fast-element SubscriberSet.notify() 方法深度解析FAST 响应式系统的订阅通知分发机制fast element SubscriberSet.notify 方法深度解析FAST 响应式系统的订阅通知分发机制 本篇技术指南围绕 microsoft前端UI组件Sandstorm 后台处理机制深度解析Ongoing Tasks 与 Scheduled Tasks 的 API 设计与平台实现Sandstorm 后台处理机制深度解析Ongoing Tasks 与 Scheduled Tasks 的 API 设计与平台实现 本文围绕 roadmap/后端容器运行时安全云原生NetBox Notification 模型深度解析订阅与事件规则驱动的用户通知机制NetBox Notification 模型深度解析订阅与事件规则驱动的用户通知机制 导读 NetBox 内置了一套面向用户的站内通知系统用于在对象发生变更后端网络数据建模上一篇ScottPlot终极指南快速创建高性能.NET图表下一篇TetWild算法原理解析稳健几何处理背后的核心技术创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表