@abtnode/blocklet-services 1.17.4-beta-20251201-225048-b1682a09 → 1.17.4-beta-20251202-122551-267b614d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/routes/user.js +2 -0
- package/api/services/notification/queue.js +190 -102
- package/api/socket/channel/did.js +80 -34
- package/api/util/user-util.js +6 -1
- package/dist/assets/{AdapterDayjs-OZNn2tpO.js → AdapterDayjs-BuAhqT20.js} +1 -1
- package/dist/assets/{Google-PoHjNVzr.js → Google-Dp7qGnxg.js} +1 -1
- package/dist/assets/{access-control-BpDf5eCc.js → access-control-B9EJ5tQF.js} +1 -1
- package/dist/assets/{actions-CIp6hu8_.js → actions-DhSvOHy-.js} +1 -1
- package/dist/assets/{add-component-core-DZMleaf7.js → add-component-core-VVqL08Uq.js} +21 -21
- package/dist/assets/{add-resource-fReirUEj.js → add-resource-DPXu2LFD.js} +1 -1
- package/dist/assets/{addon-CD2tT3Vk.js → addon-DimuRKXu.js} +1 -1
- package/dist/assets/{advanced-D_HYmeDL.js → advanced-C-M8n1zk.js} +1 -1
- package/dist/assets/{aigne-DKzLdZPY.js → aigne-Blnb_Xmg.js} +1 -1
- package/dist/assets/{appearance-DoI_K1yx.js → appearance-DcbXeaDh.js} +1 -1
- package/dist/assets/ar-C89Z16Ql.js +7 -0
- package/dist/assets/{arrow-down.svg-mj2eIUoA.js → arrow-down.svg-CNh-MHKv.js} +1 -1
- package/dist/assets/{audit-logs-CBeb46aa.js → audit-logs-D0mYj6Ut.js} +1 -1
- package/dist/assets/{authorize-BQTDaD7S.js → authorize-CZdmLVec.js} +1 -1
- package/dist/assets/{base-chart-DvlyWvB2.js → base-chart-DJyGks5q.js} +1 -1
- package/dist/assets/{base32-AX-I0UaR.js → base32-CnxuWLTI.js} +1 -1
- package/dist/assets/{bind-account--wlCwoIh.js → bind-account-GnACtKqD.js} +1 -1
- package/dist/assets/{branding-Sd6X0YqE.js → branding-CFP8OuF1.js} +1 -1
- package/dist/assets/branding-CihykCDo.js +1 -0
- package/dist/assets/{branding-CMNxsyrp.js → branding-DmNLEN0a.js} +4 -4
- package/dist/assets/{bundle-avatar-DACPWlAj.js → bundle-avatar-D3mFZG-3.js} +1 -1
- package/dist/assets/button-pTTwNqRf.js +1 -0
- package/dist/assets/{click-to-copy-DZ_4RDjR.js → click-to-copy-CAd3nEo4.js} +1 -1
- package/dist/assets/{collapse-CHg4yEHL.js → collapse-CzqKk-Uw.js} +1 -1
- package/dist/assets/{complete-BIrSCTBJ.js → complete-BDYaBiHT.js} +1 -1
- package/dist/assets/{component-BrH7uZv7.js → component-D_iXTtDp.js} +2 -2
- package/dist/assets/{config-BbbJtsEK.js → config--X9TgCMx.js} +1 -1
- package/dist/assets/{config-C0IukdMa.js → config-C_UzRk_x.js} +3 -3
- package/dist/assets/{config-navigation-CPqSm2b8.js → config-navigation-zOEBEK_N.js} +2 -2
- package/dist/assets/{config-space-B6ikfnoY.js → config-space-D1vOxWrR.js} +1 -1
- package/dist/assets/{config-BlvlFPnu.js → config-xLf7B5vm.js} +1 -1
- package/dist/assets/{confirm-Dge1BR0a.js → confirm-CC1M9sYT.js} +1 -1
- package/dist/assets/{connect-DwftqrTP.js → connect-4mXUuWwC.js} +1 -1
- package/dist/assets/{connect-DwfU2nBg.js → connect-BpoYmTzp.js} +1 -1
- package/dist/assets/{connect-to-D3Fxg-mH.js → connect-to-YDMOcSyq.js} +1 -1
- package/dist/assets/{content-layout-RghQFMLL.js → content-layout-B-2tfq3i.js} +1 -1
- package/dist/assets/{create-passport-svg-BZVXsAoP.js → create-passport-svg-BLBQxsEK.js} +1 -1
- package/dist/assets/{createClass-dlbhjEVd.js → createClass-mqcDPFI4.js} +1 -1
- package/dist/assets/{dashboard-BZMyxtap.js → dashboard-DeaTlS85.js} +2 -2
- package/dist/assets/de-BsCDrfBl.js +7 -0
- package/dist/assets/{delete-confirm-CaK42Rqi.js → delete-confirm-DF03c_mf.js} +1 -1
- package/dist/assets/{did-address-CihvGtuj.js → did-address-BOsJWqi1.js} +1 -1
- package/dist/assets/{domain-DZhOKUFR.js → domain-DdkBc4bt.js} +1 -1
- package/dist/assets/{domain-action-card-KBcfeUDt.js → domain-action-card-B8tM4_TO.js} +1 -1
- package/dist/assets/domains-CdpvlDLA.js +1 -0
- package/dist/assets/{email-mM-fSS-l.js → email-DOKW1a_7.js} +1 -1
- package/dist/assets/{empty-spinner-2ylB84wv.js → empty-spinner-G6osPzkH.js} +1 -1
- package/dist/assets/engine-BsqbrwXE.js +1 -0
- package/dist/assets/es-BJh_XsEm.js +9 -0
- package/dist/assets/{exchange-passport-CL0-QMoV.js → exchange-passport-Dnbu3e66.js} +1 -1
- package/dist/assets/{form-BQvsWiOt.js → form-mmswDYpL.js} +1 -1
- package/dist/assets/form-text-input-BFJU5Psq.js +11 -0
- package/dist/assets/{form-wrapper-CqFSijKV.js → form-wrapper-CU8kJXy5.js} +1 -1
- package/dist/assets/fr-DRJMwn7V.js +7 -0
- package/dist/assets/{fuel-BpMa6xEp.js → fuel-CpCUHgkW.js} +1 -1
- package/dist/assets/{gen-access-key-BLtBtR5W.js → gen-access-key-OHc0npoi.js} +1 -1
- package/dist/assets/{gen-simple-access-key-9tFWfYxA.js → gen-simple-access-key-C6tIufX7.js} +1 -1
- package/dist/assets/get-safe-url-DUB5fSqh.js +1 -0
- package/dist/assets/hi-h-9Yl5g9.js +5 -0
- package/dist/assets/{home-BG4Bn0-p.js → home-BFI-HNBw.js} +1 -1
- package/dist/assets/id-BDWggRsa.js +7 -0
- package/dist/assets/{iframe-BjsS1KQR.js → iframe-DB0OcQ6i.js} +1 -1
- package/dist/assets/{index-B00Da_zr.js → index-3hHmW6B5.js} +1 -1
- package/dist/assets/{index-DsQDfClt.js → index-7uZYu-Ep.js} +1 -1
- package/dist/assets/{index-bbu7QFpz.js → index-BIJNkmLb.js} +1 -1
- package/dist/assets/{index-sfOXn4Gu.js → index-BMkJtBkv.js} +2 -2
- package/dist/assets/{index-C40tsw4I.js → index-Bj8J6jnM.js} +1 -1
- package/dist/assets/{index-D6MFQa2J.js → index-Bksy_mMO.js} +1 -1
- package/dist/assets/{index-B8mnhcds.js → index-Bns8G6yV.js} +2 -2
- package/dist/assets/{index-DEDj0oVc.js → index-BphmxdkH.js} +1 -1
- package/dist/assets/index-BsP0-mXD.js +124 -0
- package/dist/assets/{index-B8uWH9ks.js → index-BuIBrsUM.js} +1 -1
- package/dist/assets/index-Bw9XS3Zt.js +7 -0
- package/dist/assets/{index-CxJOg5jI.js → index-C3BK6ln_.js} +1 -1
- package/dist/assets/{index-B9Igf2rm.js → index-C3cD5fjJ.js} +1 -1
- package/dist/assets/{index-h0Os_ox8.js → index-CDE0c6ul.js} +1 -1
- package/dist/assets/{index-BmuOS9l2.js → index-CDFYQ7q2.js} +1 -1
- package/dist/assets/{index-5hr4oNRS.js → index-CEyMJtzZ.js} +3 -3
- package/dist/assets/{index-KUb_kVWp.js → index-CHbWK92_.js} +2 -2
- package/dist/assets/{index-BF7MtybM.js → index-Ca4Ccmqm.js} +1 -1
- package/dist/assets/{index-lFDZOk_k.js → index-CeWTwSLE.js} +66 -66
- package/dist/assets/{index-B4Q4y_7n.js → index-CtouYMiN.js} +1 -1
- package/dist/assets/{index-D9UpcFKi.js → index-D0pDhWRx.js} +1 -1
- package/dist/assets/{index-BVYUGxzR.js → index-D8w8SYuc.js} +1 -1
- package/dist/assets/{index-Cy73v3o9.js → index-DUFdTykg.js} +1 -1
- package/dist/assets/{index-BIlfbBZ2.js → index-DWuLUiY3.js} +1 -1
- package/dist/assets/index-Duwa2sz8.js +1 -0
- package/dist/assets/{index-CO3X6G_g.js → index-Dx6HKVtJ.js} +1 -1
- package/dist/assets/{index-yGC4DbEU.js → index-Dy3yCmIK.js} +1 -1
- package/dist/assets/{index-BUomsang.js → index-V1TR40-z.js} +1 -1
- package/dist/assets/{index-BoeLorfn.js → index-WCk612vr.js} +1 -1
- package/dist/assets/{index-BzCDxVOL.js → index-Xg-It3qI.js} +1 -1
- package/dist/assets/{index-CgTWMV4T.js → index-ohq48KFN.js} +1 -1
- package/dist/assets/{index-V83VNrab.js → index-wS_uPsSR.js} +1 -1
- package/dist/assets/{invitation-LJOuA09f.js → invitation-BqyhoSaQ.js} +1 -1
- package/dist/assets/{invitations-DtmYY9Tr.js → invitations-Dmx5LkD1.js} +1 -1
- package/dist/assets/{invite-DrIYCYzj.js → invite-E-ZdmNWy.js} +1 -1
- package/dist/assets/{isURL-fcz3vuMN.js → isURL-HS60va5G.js} +1 -1
- package/dist/assets/{issue-passport-Dv9gH2LH.js → issue-passport-DhA2Aw2n.js} +1 -1
- package/dist/assets/{item-weuCOdTL.js → item-B8ah25gH.js} +1 -1
- package/dist/assets/ja-R9EF3xbB.js +9 -0
- package/dist/assets/ko-C_QLPZyk.js +9 -0
- package/dist/assets/{landing-page-Djj9jDve.js → landing-page-DQBBERn_.js} +1 -1
- package/dist/assets/{launch-result-message-AcBN2VCj.js → launch-result-message-CO-R7GIB.js} +1 -1
- package/dist/assets/{layout-0zU7a-3v.js → layout-DUsIwJhf.js} +1 -1
- package/dist/assets/{list-DXe9E4ws.js → list-C6OYD0M-.js} +3 -3
- package/dist/assets/{list-Co62gn7d.js → list-CLMUEykk.js} +1 -1
- package/dist/assets/{list-header-CA-QkwGq.js → list-header-Cv_gaaAc.js} +1 -1
- package/dist/assets/localization-CutEJG9u.js +1 -0
- package/dist/assets/{log-BCC7blv9.js → log-CaIfb_mj.js} +1 -1
- package/dist/assets/logger-CjpdOowp.js +1 -0
- package/dist/assets/{login-DlWL3WVr.js → login-N9lwWO_e.js} +1 -1
- package/dist/assets/{login-oauth-callback-CQFS2s22.js → login-oauth-callback-U2rdasmV.js} +1 -1
- package/dist/assets/{logo-uploader-Dz85eY-W.js → logo-uploader-BgXq5jHQ.js} +1 -1
- package/dist/assets/{lost-passport-pRlBbp2M.js → lost-passport-CPwExoAp.js} +1 -1
- package/dist/assets/{observability-Bzq6nAvX.js → observability-SEfRhcXj.js} +1 -1
- package/dist/assets/{open-window-X4W6wF0y.js → open-window-BPgl9r9H.js} +1 -1
- package/dist/assets/{over-due-invoice-payment-CvKa0suc.js → over-due-invoice-payment-Hi-FNl9O.js} +1 -1
- package/dist/assets/{overview-d6xffU9N.js → overview-DPJo9CyG.js} +2 -2
- package/dist/assets/{page-header-B4MDj6gy.js → page-header-BkgoSN-0.js} +1 -1
- package/dist/assets/{passport-DHiNUeVn.js → passport-DMZiwbhL.js} +1 -1
- package/dist/assets/{passport-item-BkmVlAdr.js → passport-item-yqBy6NcY.js} +1 -1
- package/dist/assets/{permission-B3_OQqtH.js → permission-CiiVpApl.js} +1 -1
- package/dist/assets/{playground-C71u8_tm.js → playground-Bo63Spph.js} +1 -1
- package/dist/assets/preferences-YgFBqLbX.js +1 -0
- package/dist/assets/profile-embed-C35dSucs.js +1 -0
- package/dist/assets/pt-DpYO8djd.js +5 -0
- package/dist/assets/{publish-resource-Aoo5xCZX.js → publish-resource-DUDgKqzf.js} +1 -1
- package/dist/assets/{react-beautiful-dnd.esm--C1KYPc1.js → react-beautiful-dnd.esm-Clor-N66.js} +1 -1
- package/dist/assets/{react-stripe.esm-DlJMzZK2.js → react-stripe.esm-C-04j7I2.js} +1 -1
- package/dist/assets/{required-glXJjYm5.js → required-Btg6mEmX.js} +1 -1
- package/dist/assets/ru-DkZtar3s.js +5 -0
- package/dist/assets/{runtime-xK-SJ1cq.js → runtime-B_yu4wL5.js} +1 -1
- package/dist/assets/sdk-D9qYMy_G.js +1 -0
- package/dist/assets/{section-4gVAq_Fp.js → section-Cyr0YvGa.js} +1 -1
- package/dist/assets/{security-B3q0KDVH.js → security-YhrYNktK.js} +1 -1
- package/dist/assets/{session-DR7jqIW5.js → session-CJQ7HeL8.js} +1 -1
- package/dist/assets/{setup-CPrn9v2_.js → setup-DVxC6L1D.js} +1 -1
- package/dist/assets/{shorten-label-Cf--RqV-.js → shorten-label-D6jbe4l0.js} +1 -1
- package/dist/assets/{simple-select-SyYgbCc2.js → simple-select-BW6-FLlf.js} +1 -1
- package/dist/assets/{spaces-C_pXJSzm.js → spaces-DB-xtAK9.js} +1 -1
- package/dist/assets/{start-BUxgx8Ah.js → start-CnOduVio.js} +1 -1
- package/dist/assets/{starting-progress-BP_Sqg1X.js → starting-progress-Qp2T3eDZ.js} +1 -1
- package/dist/assets/{status-CE6iXPs_.js → status-B2iiuI6t.js} +1 -1
- package/dist/assets/{step-actions-tRQyAl6A.js → step-actions-D7ku0W0o.js} +1 -1
- package/dist/assets/{studio-bbXFMut7.js → studio-DtnYEBjZ.js} +1 -1
- package/dist/assets/switch-CjOUxynL.js +1 -0
- package/dist/assets/{switch-control-DdOZdvsu.js → switch-control-BFsTsyuN.js} +1 -1
- package/dist/assets/{table-tips-cVuoMOXE.js → table-tips-EHWVzPWe.js} +1 -1
- package/dist/assets/{team-KWOyNaWn.js → team-CKeHAIQC.js} +1 -1
- package/dist/assets/th-04iX5CrT.js +5 -0
- package/dist/assets/{traffic-ChddnVTm.js → traffic-NcU-KhYi.js} +1 -1
- package/dist/assets/{transfer-CcCi6t4X.js → transfer-CB2s8PFZ.js} +1 -1
- package/dist/assets/{unsubscribe-Bp5VQCnR.js → unsubscribe-a8AJuSFd.js} +1 -1
- package/dist/assets/{use-app-logo-hGlkw2d_.js → use-app-logo-D38VoM1R.js} +1 -1
- package/dist/assets/{use-mobile-BpPz1bKz.js → use-mobile-C5RjvO7g.js} +1 -1
- package/dist/assets/{use-mobile-DoKVMODs.js → use-mobile-ajdJIsoX.js} +1 -1
- package/dist/assets/{use-server-logo-UGU40YsW.js → use-server-logo-D4Yh4atf.js} +1 -1
- package/dist/assets/{use-window-close-CbUhh9L6.js → use-window-close-Bo92fPIm.js} +1 -1
- package/dist/assets/{useAsyncRetry-DHTJ61Jg.js → useAsyncRetry-a2Wewn3F.js} +1 -1
- package/dist/assets/{useLocalStorage-UFpv-3wa.js → useLocalStorage-BBhMedc2.js} +1 -1
- package/dist/assets/{user-center-CXduwafJ.js → user-center-BNMJJTvG.js} +2 -2
- package/dist/assets/{user-follower-CmGz7Inx.js → user-follower-BXm4RUI2.js} +1 -1
- package/dist/assets/{util-MbDHkO8z.js → util-DPC-rfKa.js} +1 -1
- package/dist/assets/{util-D-cKMKUM.js → util-MwdZAHoO.js} +1 -1
- package/dist/assets/{vendor-arcblock-3xKfH3F1.js → vendor-arcblock-BL_VyzmH.js} +1 -1
- package/dist/assets/{vendor-mui-core-DHT36AZL.js → vendor-mui-core-BPQ6AEW_.js} +2 -2
- package/dist/assets/{vendor-mui-x-B4OOX5Es.js → vendor-mui-x-CWNb8fsW.js} +1 -1
- package/dist/assets/{vendor-ux-sqP3hEhY.js → vendor-ux-D507n6h6.js} +1 -1
- package/dist/assets/vi-kOP0E9Ga.js +5 -0
- package/dist/assets/{wait-connect-DDyEqw4h.js → wait-connect-Of13xq9u.js} +1 -1
- package/dist/assets/{wizard-B588KidT.js → wizard-BXTkkerl.js} +1 -1
- package/dist/assets/{wizard-components-DP7Z_TTm.js → wizard-components-BZ6jYzgt.js} +1 -1
- package/dist/assets/wrap-locale-CPp4ppiN.js +1 -0
- package/dist/assets/{zh-C_L8CY4f.js → zh-8l1HXCDx.js} +1 -1
- package/dist/assets/{zh-98nxdLeR.js → zh-DZI4Yy2m.js} +3 -3
- package/dist/assets/{zh-tw-BdDE7n5E.js → zh-tw-BLapUUeq.js} +2 -2
- package/dist/index.html +1 -1
- package/dist/service-worker.js +1 -1
- package/package.json +23 -23
- package/dist/assets/ar-BJZY7v5z.js +0 -7
- package/dist/assets/branding-Bs3FNZ79.js +0 -1
- package/dist/assets/button-8Nchte_6.js +0 -1
- package/dist/assets/de-BF0NHTXz.js +0 -7
- package/dist/assets/domains-Dr63r27w.js +0 -1
- package/dist/assets/engine-BCYKeHn7.js +0 -1
- package/dist/assets/es-Dv2m4LXp.js +0 -9
- package/dist/assets/form-text-input-CBL3JAev.js +0 -11
- package/dist/assets/fr-BGhg9oO3.js +0 -7
- package/dist/assets/get-safe-url-CxrqaBih.js +0 -1
- package/dist/assets/hi-CPfDhW8g.js +0 -5
- package/dist/assets/id-9TUzKF6k.js +0 -7
- package/dist/assets/index-88gdbkao.js +0 -1
- package/dist/assets/index-B6-5SXSy.js +0 -7
- package/dist/assets/index-CNE3uN5c.js +0 -124
- package/dist/assets/ja-DT5bRsBF.js +0 -9
- package/dist/assets/ko-CJn9PyPz.js +0 -9
- package/dist/assets/localization-CufkU3et.js +0 -1
- package/dist/assets/logger-DQUu6ucJ.js +0 -1
- package/dist/assets/preferences-D321ZAU1.js +0 -1
- package/dist/assets/profile-embed-Ba3F6nXm.js +0 -1
- package/dist/assets/pt-K9FK6Ube.js +0 -5
- package/dist/assets/ru-C_RwukUu.js +0 -5
- package/dist/assets/sdk-DAuiCSLy.js +0 -1
- package/dist/assets/th-Bhii_FfA.js +0 -5
- package/dist/assets/vi-DVF2tjOG.js +0 -5
- package/dist/assets/wrap-locale-CFMie_Pc.js +0 -1
package/api/routes/user.js
CHANGED
|
@@ -661,6 +661,8 @@ const notificationConfigSetSchema = Joi.object({
|
|
|
661
661
|
Joi.object({
|
|
662
662
|
url: Joi.string().uri(),
|
|
663
663
|
type: Joi.string().valid('slack', 'api'),
|
|
664
|
+
enabled: Joi.boolean().optional().default(true),
|
|
665
|
+
consecutiveFailures: Joi.number().optional().default(0),
|
|
664
666
|
})
|
|
665
667
|
)
|
|
666
668
|
.optional(),
|
|
@@ -17,9 +17,11 @@ const {
|
|
|
17
17
|
NOTIFICATION_SEND_STATUS,
|
|
18
18
|
NOTIFICATION_SEND_FAILED_REASON,
|
|
19
19
|
} = require('@abtnode/constant');
|
|
20
|
+
const sleep = require('@abtnode/util/lib/sleep');
|
|
20
21
|
const { nanoid } = require('@blocklet/meta/lib/util');
|
|
21
22
|
const get = require('lodash/get');
|
|
22
23
|
const uniqBy = require('lodash/uniqBy');
|
|
24
|
+
const { getQueueConcurrencyByMem } = require('@abtnode/core/lib/util');
|
|
23
25
|
const { getBlockletInfo } = require('../../cache');
|
|
24
26
|
const { updateNotificationSendStatus } = require('../../socket/channel/did');
|
|
25
27
|
const eventHub =
|
|
@@ -29,6 +31,8 @@ const logger = require('../../libs/logger')('blocklet-services:notification-queu
|
|
|
29
31
|
|
|
30
32
|
const emailSchema = Joi.string().email().required();
|
|
31
33
|
|
|
34
|
+
const concurrency = getQueueConcurrencyByMem();
|
|
35
|
+
|
|
32
36
|
/**
|
|
33
37
|
*
|
|
34
38
|
* 校验是否是有效的 passthrough 消息
|
|
@@ -58,10 +62,14 @@ const createNotificationQueue = (name, options, handler) => {
|
|
|
58
62
|
maxRetries: 3,
|
|
59
63
|
retryDelay: 10 * 1000,
|
|
60
64
|
maxTimeout: 60 * 1000, // throw timeout error after 1 minutes
|
|
65
|
+
concurrency,
|
|
61
66
|
...(options ?? {}),
|
|
62
67
|
},
|
|
63
68
|
onJob: async (job) => {
|
|
64
69
|
await handler(job);
|
|
70
|
+
if (options.delay) {
|
|
71
|
+
await sleep(options.delay * 1000);
|
|
72
|
+
}
|
|
65
73
|
},
|
|
66
74
|
});
|
|
67
75
|
};
|
|
@@ -73,7 +81,15 @@ const init = ({ node, notificationService }) => {
|
|
|
73
81
|
const getServerWebhooks = async () => {
|
|
74
82
|
const webhookList = (await webhookState.list()) ?? [];
|
|
75
83
|
return webhookList.flatMap((item) =>
|
|
76
|
-
item.params
|
|
84
|
+
item.params
|
|
85
|
+
.filter((param) => param.name === 'url' && param.value)
|
|
86
|
+
.map((param) => ({
|
|
87
|
+
id: item.id,
|
|
88
|
+
type: item.type,
|
|
89
|
+
url: param.value,
|
|
90
|
+
enabled: param.enabled ?? true,
|
|
91
|
+
consecutiveFailures: param.consecutiveFailures || 0,
|
|
92
|
+
}))
|
|
77
93
|
);
|
|
78
94
|
};
|
|
79
95
|
|
|
@@ -85,6 +101,7 @@ const init = ({ node, notificationService }) => {
|
|
|
85
101
|
{
|
|
86
102
|
maxRetries: 1,
|
|
87
103
|
retryDelay: 0,
|
|
104
|
+
enableScheduledJob: true,
|
|
88
105
|
},
|
|
89
106
|
async (job) => {
|
|
90
107
|
try {
|
|
@@ -104,6 +121,7 @@ const init = ({ node, notificationService }) => {
|
|
|
104
121
|
});
|
|
105
122
|
} catch (error) {
|
|
106
123
|
logger.error('Failed to send to app', { notificationId: job.notification.id, receiver: job.receiver, error });
|
|
124
|
+
throw error;
|
|
107
125
|
}
|
|
108
126
|
}
|
|
109
127
|
);
|
|
@@ -111,28 +129,42 @@ const init = ({ node, notificationService }) => {
|
|
|
111
129
|
/**
|
|
112
130
|
* Push Kit 推送队列
|
|
113
131
|
*/
|
|
114
|
-
const pushKitPushQueue = createNotificationQueue(
|
|
115
|
-
|
|
116
|
-
|
|
132
|
+
const pushKitPushQueue = createNotificationQueue(
|
|
133
|
+
'send-notification-push',
|
|
134
|
+
{
|
|
135
|
+
enableScheduledJob: true,
|
|
136
|
+
},
|
|
137
|
+
async (job) => {
|
|
138
|
+
try {
|
|
139
|
+
const { notification, receiver, sender } = job;
|
|
117
140
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
141
|
+
if (!receiver) {
|
|
142
|
+
throw new Error('Invalid receiver');
|
|
143
|
+
}
|
|
121
144
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
145
|
+
await notificationService.sendToPush.exec({
|
|
146
|
+
sender,
|
|
147
|
+
receiver,
|
|
148
|
+
notification,
|
|
149
|
+
pushOnly: job.pushOnly,
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
if (error.logLevel === 'debug') {
|
|
153
|
+
logger.debug('Failed to send to push', {
|
|
154
|
+
notificationId: job.notification.id,
|
|
155
|
+
receiver: job.receiver,
|
|
156
|
+
error,
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
logger.error('Failed to send to push', {
|
|
160
|
+
notificationId: job.notification.id,
|
|
161
|
+
receiver: job.receiver,
|
|
162
|
+
error,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
133
165
|
}
|
|
134
166
|
}
|
|
135
|
-
|
|
167
|
+
);
|
|
136
168
|
|
|
137
169
|
/**
|
|
138
170
|
* email 推送队列
|
|
@@ -184,7 +216,6 @@ const init = ({ node, notificationService }) => {
|
|
|
184
216
|
: null;
|
|
185
217
|
|
|
186
218
|
logger.info('Start send to email', {
|
|
187
|
-
email,
|
|
188
219
|
notificationId: job.notificationId,
|
|
189
220
|
});
|
|
190
221
|
await notificationService.sendToMail.exec({
|
|
@@ -206,7 +237,6 @@ const init = ({ node, notificationService }) => {
|
|
|
206
237
|
options,
|
|
207
238
|
});
|
|
208
239
|
logger.info('End send to email', {
|
|
209
|
-
email,
|
|
210
240
|
notificationId: job.notificationId,
|
|
211
241
|
});
|
|
212
242
|
} catch (error) {
|
|
@@ -225,6 +255,7 @@ const init = ({ node, notificationService }) => {
|
|
|
225
255
|
error,
|
|
226
256
|
});
|
|
227
257
|
}
|
|
258
|
+
throw error;
|
|
228
259
|
}
|
|
229
260
|
}
|
|
230
261
|
);
|
|
@@ -285,6 +316,7 @@ const init = ({ node, notificationService }) => {
|
|
|
285
316
|
receivers: job.input.receivers.join(','),
|
|
286
317
|
error,
|
|
287
318
|
});
|
|
319
|
+
throw error;
|
|
288
320
|
}
|
|
289
321
|
}
|
|
290
322
|
);
|
|
@@ -381,7 +413,7 @@ const init = ({ node, notificationService }) => {
|
|
|
381
413
|
options,
|
|
382
414
|
},
|
|
383
415
|
},
|
|
384
|
-
delay:
|
|
416
|
+
delay: 8,
|
|
385
417
|
});
|
|
386
418
|
} else {
|
|
387
419
|
// eslint-disable-next-line no-lonely-if
|
|
@@ -403,8 +435,40 @@ const init = ({ node, notificationService }) => {
|
|
|
403
435
|
}
|
|
404
436
|
};
|
|
405
437
|
|
|
438
|
+
/**
|
|
439
|
+
* 批量更新 webhook 发送失败状态(并行处理)
|
|
440
|
+
* @param {Array} webhooks - webhook 列表
|
|
441
|
+
* @param {string} failedReason - 失败原因
|
|
442
|
+
* @param {object} params - 公共参数
|
|
443
|
+
* @returns {Promise<void>}
|
|
444
|
+
*/
|
|
445
|
+
const batchUpdateWebhookFailedStatus = (webhooks, failedReason, params) => {
|
|
446
|
+
const updatePromises = webhooks.map((webhook) => {
|
|
447
|
+
const { url, type } = webhook;
|
|
448
|
+
const webhookParams = {
|
|
449
|
+
[url]: {
|
|
450
|
+
type,
|
|
451
|
+
sendAt: new Date(),
|
|
452
|
+
status: NOTIFICATION_SEND_STATUS.FAILED,
|
|
453
|
+
failedReason,
|
|
454
|
+
},
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
return updateNotificationSendStatus({
|
|
458
|
+
...params,
|
|
459
|
+
channel: NOTIFICATION_SEND_CHANNEL.WEBHOOK,
|
|
460
|
+
status: NOTIFICATION_SEND_STATUS.FAILED,
|
|
461
|
+
webhookParams,
|
|
462
|
+
}).catch((err) => {
|
|
463
|
+
logger.debug('update webhook failed status error', { err, url });
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
return Promise.all(updatePromises);
|
|
468
|
+
};
|
|
469
|
+
|
|
406
470
|
const insertToWebhookPushQueue = async (props, nodeInfo, isResend) => {
|
|
407
|
-
const { channels, notification, sender, userInfo, teamDid } = props;
|
|
471
|
+
const { channels, notification, sender, userInfo, teamDid, pushOnly } = props;
|
|
408
472
|
|
|
409
473
|
const receiverDid = userInfo.did;
|
|
410
474
|
|
|
@@ -412,6 +476,7 @@ const init = ({ node, notificationService }) => {
|
|
|
412
476
|
node,
|
|
413
477
|
teamDid: teamDid ?? nodeInfo.did,
|
|
414
478
|
notificationId: notification.id,
|
|
479
|
+
receivers: [receiverDid],
|
|
415
480
|
};
|
|
416
481
|
|
|
417
482
|
const isServer = teamDid === nodeInfo.did;
|
|
@@ -423,20 +488,34 @@ const init = ({ node, notificationService }) => {
|
|
|
423
488
|
|
|
424
489
|
const webhookList = uniqBy(webhooks, 'url');
|
|
425
490
|
|
|
426
|
-
//
|
|
491
|
+
// 分类 webhook:有效、禁用、类型不匹配
|
|
427
492
|
const validWebhookList = [];
|
|
493
|
+
const invalidWebhooks = []; // { webhook, reason }
|
|
494
|
+
|
|
428
495
|
for (const webhook of webhookList) {
|
|
429
|
-
const { url, type } = webhook;
|
|
430
|
-
|
|
496
|
+
const { url, type, enabled = true } = webhook;
|
|
497
|
+
|
|
498
|
+
// 检查是否禁用
|
|
499
|
+
if (!enabled) {
|
|
500
|
+
invalidWebhooks.push({ webhook, reason: 'Current webhook is disabled' });
|
|
501
|
+
} else if (type === 'api' && isUrl(url)) {
|
|
502
|
+
// api 类型且 URL 有效
|
|
431
503
|
validWebhookList.push(webhook);
|
|
432
504
|
} else if (type === 'slack' && isUrl(url) && isSlackWebhookUrl(url)) {
|
|
505
|
+
// slack 类型且 URL 有效
|
|
433
506
|
validWebhookList.push(webhook);
|
|
507
|
+
} else {
|
|
508
|
+
// 类型不支持或 URL 无效
|
|
509
|
+
invalidWebhooks.push({ webhook, reason: 'Webhook type is not supported or URL is invalid' });
|
|
434
510
|
}
|
|
435
511
|
}
|
|
436
512
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
513
|
+
const isWebhookChannelEnabled = channels.includes(NOTIFICATION_SEND_CHANNEL.WEBHOOK);
|
|
514
|
+
|
|
515
|
+
// 如果有有效的 webhook 且 channel 启用,推送到队列
|
|
516
|
+
if (validWebhookList.length > 0 && isWebhookChannelEnabled) {
|
|
517
|
+
for (const webhook of validWebhookList) {
|
|
518
|
+
const { url } = webhook;
|
|
440
519
|
logger.info('Insert to webhook push queue', {
|
|
441
520
|
notificationId: notification.id,
|
|
442
521
|
receiver: receiverDid,
|
|
@@ -452,45 +531,50 @@ const init = ({ node, notificationService }) => {
|
|
|
452
531
|
receivers: [receiverDid],
|
|
453
532
|
isResend,
|
|
454
533
|
pushOnly: props.pushOnly && !isResend,
|
|
455
|
-
webhook
|
|
456
|
-
url,
|
|
457
|
-
type,
|
|
458
|
-
},
|
|
534
|
+
webhook,
|
|
459
535
|
},
|
|
460
536
|
},
|
|
461
537
|
delay: 5,
|
|
462
538
|
});
|
|
463
539
|
}
|
|
464
|
-
}
|
|
465
|
-
// eslint-disable-next-line no-lonely-if
|
|
466
|
-
if (webhookList.length > 0 && !isResend) {
|
|
467
|
-
const webhookParams = {};
|
|
540
|
+
}
|
|
468
541
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
542
|
+
// 如果不是重发,需要更新失败状态(并行处理)
|
|
543
|
+
if (!isResend && !pushOnly) {
|
|
544
|
+
const updatePromises = [];
|
|
545
|
+
|
|
546
|
+
// 处理无效的 webhook(按失败原因分组并行更新)
|
|
547
|
+
if (invalidWebhooks.length > 0) {
|
|
548
|
+
// 按失败原因分组
|
|
549
|
+
const groupedByReason = {};
|
|
550
|
+
for (const { webhook, reason } of invalidWebhooks) {
|
|
551
|
+
if (!groupedByReason[reason]) {
|
|
552
|
+
groupedByReason[reason] = [];
|
|
553
|
+
}
|
|
554
|
+
groupedByReason[reason].push(webhook);
|
|
474
555
|
}
|
|
475
556
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
sendAt: new Date(),
|
|
480
|
-
status: NOTIFICATION_SEND_STATUS.FAILED,
|
|
481
|
-
failedReason: reason,
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
// eslint-disable-next-line no-await-in-loop
|
|
485
|
-
await updateNotificationSendStatus({
|
|
486
|
-
...commonParams,
|
|
487
|
-
receivers: [receiverDid],
|
|
488
|
-
channel: NOTIFICATION_SEND_CHANNEL.WEBHOOK,
|
|
489
|
-
status: NOTIFICATION_SEND_STATUS.FAILED,
|
|
490
|
-
webhookParams: { [url]: webhookParams[url] },
|
|
491
|
-
});
|
|
557
|
+
// 每组并行更新
|
|
558
|
+
for (const [reason, webhookGroup] of Object.entries(groupedByReason)) {
|
|
559
|
+
updatePromises.push(batchUpdateWebhookFailedStatus(webhookGroup, reason, commonParams));
|
|
492
560
|
}
|
|
493
561
|
}
|
|
562
|
+
|
|
563
|
+
// 处理有效但 channel 禁用的 webhook
|
|
564
|
+
if (validWebhookList.length > 0 && !isWebhookChannelEnabled) {
|
|
565
|
+
updatePromises.push(
|
|
566
|
+
batchUpdateWebhookFailedStatus(
|
|
567
|
+
validWebhookList,
|
|
568
|
+
NOTIFICATION_SEND_FAILED_REASON.CHANNEL_DISABLED,
|
|
569
|
+
commonParams
|
|
570
|
+
)
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// 等待所有更新完成(不阻塞主流程)
|
|
575
|
+
Promise.all(updatePromises).catch((err) => {
|
|
576
|
+
logger.error('batch update webhook failed status error', { err });
|
|
577
|
+
});
|
|
494
578
|
}
|
|
495
579
|
};
|
|
496
580
|
|
|
@@ -516,12 +600,15 @@ const init = ({ node, notificationService }) => {
|
|
|
516
600
|
receiver: receiverDid,
|
|
517
601
|
});
|
|
518
602
|
pushKitPushQueue.push({
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
603
|
+
job: {
|
|
604
|
+
notification,
|
|
605
|
+
sender,
|
|
606
|
+
options,
|
|
607
|
+
receiver: receiverDid,
|
|
608
|
+
isResend,
|
|
609
|
+
pushOnly: props.pushOnly && !isResend,
|
|
610
|
+
},
|
|
611
|
+
delay: 10,
|
|
525
612
|
});
|
|
526
613
|
} else {
|
|
527
614
|
// eslint-disable-next-line no-lonely-if
|
|
@@ -557,13 +644,16 @@ const init = ({ node, notificationService }) => {
|
|
|
557
644
|
receiver: receiverDid,
|
|
558
645
|
});
|
|
559
646
|
walletPushQueue.push({
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
647
|
+
job: {
|
|
648
|
+
notification,
|
|
649
|
+
sender,
|
|
650
|
+
options,
|
|
651
|
+
receiver: receiverDid,
|
|
652
|
+
isResend,
|
|
653
|
+
pushOnly: props.pushOnly && !isResend,
|
|
654
|
+
source,
|
|
655
|
+
},
|
|
656
|
+
delay: 5,
|
|
567
657
|
});
|
|
568
658
|
} else {
|
|
569
659
|
// 如果是重发的消息,只需要更新推送状态,不需要更新 channel状态
|
|
@@ -628,7 +718,7 @@ const init = ({ node, notificationService }) => {
|
|
|
628
718
|
* }
|
|
629
719
|
*/
|
|
630
720
|
const queue = createNotificationQueue('notification-receivers', {}, async (job) => {
|
|
631
|
-
const { teamDid, channels, receiver, sender, notification, nodeInfo,
|
|
721
|
+
const { teamDid, channels, receiver, sender, notification, nodeInfo, ...rest } = job;
|
|
632
722
|
|
|
633
723
|
logger.info('notification start insert to queue', {
|
|
634
724
|
teamDid,
|
|
@@ -636,6 +726,17 @@ const init = ({ node, notificationService }) => {
|
|
|
636
726
|
receiver,
|
|
637
727
|
});
|
|
638
728
|
try {
|
|
729
|
+
const selection = {
|
|
730
|
+
did: 1,
|
|
731
|
+
fullName: 1,
|
|
732
|
+
email: 1,
|
|
733
|
+
extra: 1,
|
|
734
|
+
};
|
|
735
|
+
const userInfo = await node.getUser({
|
|
736
|
+
teamDid,
|
|
737
|
+
user: { did: receiver },
|
|
738
|
+
options: { enableConnectedAccount: true, selection, includePassports: false, includeConnectedAccounts: false },
|
|
739
|
+
});
|
|
639
740
|
if (!userInfo) {
|
|
640
741
|
throw new Error(`Invalid receiver user: ${receiver}`);
|
|
641
742
|
}
|
|
@@ -654,26 +755,22 @@ const init = ({ node, notificationService }) => {
|
|
|
654
755
|
});
|
|
655
756
|
// websocket 通知
|
|
656
757
|
const receiverDid = userInfo.did;
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
notification
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
...(rest.actorInfo ? { actorInfo: rest.actorInfo } : {}),
|
|
668
|
-
},
|
|
669
|
-
receiver: receiverDid,
|
|
670
|
-
teamDid,
|
|
671
|
-
isServices: rest.isServices,
|
|
758
|
+
websocketQueue.push({
|
|
759
|
+
input: {
|
|
760
|
+
notification: {
|
|
761
|
+
...notification,
|
|
762
|
+
entityType: rest.entityType,
|
|
763
|
+
entityId: rest.entityId,
|
|
764
|
+
componentDid: rest.componentDid,
|
|
765
|
+
source: rest.source,
|
|
766
|
+
createdAt: rest.createdAt,
|
|
767
|
+
...(rest.actorInfo ? { actorInfo: rest.actorInfo } : {}),
|
|
672
768
|
},
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
769
|
+
receiver: receiverDid,
|
|
770
|
+
teamDid,
|
|
771
|
+
isServices: rest.isServices,
|
|
772
|
+
},
|
|
773
|
+
});
|
|
677
774
|
}
|
|
678
775
|
|
|
679
776
|
notification.type = notification.type || 'notification';
|
|
@@ -727,7 +824,6 @@ const init = ({ node, notificationService }) => {
|
|
|
727
824
|
logger.info('notification start insert to queue:', {
|
|
728
825
|
teamDid: data?.teamDid,
|
|
729
826
|
notificationId: data?.notification?.id,
|
|
730
|
-
receivers: data?.receivers?.join(','),
|
|
731
827
|
});
|
|
732
828
|
if (isInstanceWorker()) {
|
|
733
829
|
return;
|
|
@@ -753,13 +849,7 @@ const init = ({ node, notificationService }) => {
|
|
|
753
849
|
type: 'server',
|
|
754
850
|
});
|
|
755
851
|
|
|
756
|
-
|
|
757
|
-
teamDid,
|
|
758
|
-
userDids: receivers,
|
|
759
|
-
includeConnectedAccounts: true,
|
|
760
|
-
});
|
|
761
|
-
|
|
762
|
-
if (users.length === 0) {
|
|
852
|
+
if (receivers.length === 0) {
|
|
763
853
|
throw new Error('No users found');
|
|
764
854
|
}
|
|
765
855
|
// 如果 notification 没有 id,则生成一个, wallet 要基于这唯一个ID进行处理
|
|
@@ -771,8 +861,7 @@ const init = ({ node, notificationService }) => {
|
|
|
771
861
|
notification.id = `NOTIF-${nanoid()}`;
|
|
772
862
|
}
|
|
773
863
|
|
|
774
|
-
|
|
775
|
-
const receiverDid = userInfo.did;
|
|
864
|
+
receivers.forEach((receiverDid) => {
|
|
776
865
|
queue.push({
|
|
777
866
|
...rest,
|
|
778
867
|
notification,
|
|
@@ -781,7 +870,6 @@ const init = ({ node, notificationService }) => {
|
|
|
781
870
|
receiver: receiverDid,
|
|
782
871
|
sender,
|
|
783
872
|
nodeInfo,
|
|
784
|
-
userInfo,
|
|
785
873
|
});
|
|
786
874
|
});
|
|
787
875
|
} catch (error) {
|
|
@@ -164,40 +164,38 @@ const sendToUserDid = async ({ sender, receiver: rawDid, notification, options,
|
|
|
164
164
|
|
|
165
165
|
const isServer = !teamDid || teamDid === nodeInfo.did;
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return undefined;
|
|
200
|
-
}
|
|
167
|
+
// 开始执行 service 消息的推送,不需要同步执行
|
|
168
|
+
Promise.all(
|
|
169
|
+
notifications.map((_notification) => {
|
|
170
|
+
// 如果类型不存在或者是 notification 类型是才进行保存数据库,其他类型只需要通知到用户即可
|
|
171
|
+
// eg: type = 'passthrough', 'hi', 'connect', 'feed', 默认只需要通知 wallet
|
|
172
|
+
const pushOnly = _notification.type && _notification.type.toLowerCase() !== NOTIFICATION_TYPES.NOTIFICATION;
|
|
173
|
+
|
|
174
|
+
// 通知渠道的确定有两种方式 1. 用户传入的 channels 2. 根据 notification 类型确定
|
|
175
|
+
// 如果是 hi connect, 只需要通知 wallet
|
|
176
|
+
// passthrough 类型,用于 discuss kit 的 chat channel
|
|
177
|
+
// 1. push kit: native 通知快速跳转到 chat channel
|
|
178
|
+
// 2. app: 钱包消息,可以查看到接收到消息
|
|
179
|
+
|
|
180
|
+
return node.createNotification({
|
|
181
|
+
teamDid,
|
|
182
|
+
...(pushOnly ? { notification: _notification } : { ..._notification }),
|
|
183
|
+
receiver: rawDid,
|
|
184
|
+
componentDid: sender.componentDid,
|
|
185
|
+
// 这两个字段用于 socket 通知
|
|
186
|
+
entityType: _notification.entityType || 'blocklet',
|
|
187
|
+
entityId: _notification.entityId || sender.appDid,
|
|
188
|
+
source: isServer ? 'system' : _notification.source || 'component',
|
|
189
|
+
channels: CHANNEL_MAP[_notification.type] || channels,
|
|
190
|
+
sender,
|
|
191
|
+
options: { ...rest },
|
|
192
|
+
pushOnly,
|
|
193
|
+
});
|
|
194
|
+
})
|
|
195
|
+
).catch((error) => {
|
|
196
|
+
logger.error('Failed to send notification', { error });
|
|
197
|
+
});
|
|
198
|
+
return true;
|
|
201
199
|
};
|
|
202
200
|
|
|
203
201
|
// server send notification to app
|
|
@@ -352,6 +350,36 @@ const onAuthenticate = async ({ channel, did, payload }) => {
|
|
|
352
350
|
}
|
|
353
351
|
};
|
|
354
352
|
|
|
353
|
+
/**
|
|
354
|
+
* 安全地更新 webhook 状态,不影响主流程
|
|
355
|
+
* @param {object} params - 更新参数
|
|
356
|
+
* @param {object} params.node - node 实例
|
|
357
|
+
* @param {object} params.webhook - webhook 对象
|
|
358
|
+
* @param {string} params.teamDid - team DID
|
|
359
|
+
* @param {boolean} params.isService - 是否为服务
|
|
360
|
+
* @param {Array<string>} params.receivers - 接收者列表
|
|
361
|
+
* @param {number|undefined} params.consecutiveFailures - 连续失败次数,0=重置,undefined=自动+1
|
|
362
|
+
*/
|
|
363
|
+
const safeUpdateWebhookState = async ({ node, webhook, teamDid, isService, receivers, consecutiveFailures }) => {
|
|
364
|
+
try {
|
|
365
|
+
await node.updateWebHookState({
|
|
366
|
+
webhook,
|
|
367
|
+
teamDid,
|
|
368
|
+
isService,
|
|
369
|
+
userDids: receivers,
|
|
370
|
+
consecutiveFailures,
|
|
371
|
+
});
|
|
372
|
+
} catch (error) {
|
|
373
|
+
logger.debug('Failed to update webhook state', {
|
|
374
|
+
error,
|
|
375
|
+
teamDid,
|
|
376
|
+
receivers,
|
|
377
|
+
webhook: webhook.url,
|
|
378
|
+
consecutiveFailures,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
|
|
355
383
|
const sendToWebhook = async ({ sender, receiver, notification, node, pushOnly }) => {
|
|
356
384
|
const teamDid = sender.appDid;
|
|
357
385
|
const { id, appInfo, ...rest } = notification;
|
|
@@ -371,6 +399,7 @@ const sendToWebhook = async ({ sender, receiver, notification, node, pushOnly })
|
|
|
371
399
|
|
|
372
400
|
const senderInfo = await ensureSenderApp({ sender, node, nodeInfo });
|
|
373
401
|
|
|
402
|
+
const isService = teamDid && teamDid !== nodeInfo.did;
|
|
374
403
|
// 发送消息前要添加 sender 内容。否则邮件中没有 blocklet 的信息
|
|
375
404
|
const notifications = parseNotification({ id, ...rest }, senderInfo);
|
|
376
405
|
const webhookSenderMap = new Map();
|
|
@@ -405,6 +434,15 @@ const sendToWebhook = async ({ sender, receiver, notification, node, pushOnly })
|
|
|
405
434
|
webhookParams,
|
|
406
435
|
});
|
|
407
436
|
}
|
|
437
|
+
// 发送成功,重置失败次数
|
|
438
|
+
await safeUpdateWebhookState({
|
|
439
|
+
node,
|
|
440
|
+
webhook,
|
|
441
|
+
teamDid,
|
|
442
|
+
isService,
|
|
443
|
+
receivers,
|
|
444
|
+
consecutiveFailures: 0,
|
|
445
|
+
});
|
|
408
446
|
return res;
|
|
409
447
|
} catch (error) {
|
|
410
448
|
// 使用 debug 级别记录详细执行信息,避免与上层业务日志重复
|
|
@@ -424,6 +462,14 @@ const sendToWebhook = async ({ sender, receiver, notification, node, pushOnly })
|
|
|
424
462
|
webhookParams,
|
|
425
463
|
});
|
|
426
464
|
}
|
|
465
|
+
// 发送失败,不传入 consecutiveFailures,让底层自动 +1
|
|
466
|
+
await safeUpdateWebhookState({
|
|
467
|
+
node,
|
|
468
|
+
webhook,
|
|
469
|
+
teamDid,
|
|
470
|
+
isService,
|
|
471
|
+
receivers,
|
|
472
|
+
});
|
|
427
473
|
const err = new Error('Failed to send webhook');
|
|
428
474
|
err.details = error;
|
|
429
475
|
throw err;
|
package/api/util/user-util.js
CHANGED
|
@@ -315,7 +315,12 @@ const validateWebhooks = async ({ webhooks, user }) => {
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
// 去重:webhooks 包含全量的数据,去重时会把历史数据存在的重复数据清理掉
|
|
318
|
-
const uniqueWebhooks = uniqBy(webhooks, 'url')
|
|
318
|
+
const uniqueWebhooks = uniqBy(webhooks, 'url').map((webhook) => {
|
|
319
|
+
return {
|
|
320
|
+
...webhook,
|
|
321
|
+
consecutiveFailures: webhook.enabled ? webhook.consecutiveFailures : 0,
|
|
322
|
+
};
|
|
323
|
+
});
|
|
319
324
|
|
|
320
325
|
return { value: uniqueWebhooks, error: null };
|
|
321
326
|
};
|