Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UBERF-9230: Fix ses webpush #7760

Merged
merged 1 commit into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 12 additions & 17 deletions server-plugins/notification-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//

import activity, { ActivityMessage, DocUpdateMessage } from '@hcengineering/activity'
import { Analytics } from '@hcengineering/analytics'
import chunter, { ChatMessage } from '@hcengineering/chunter'
import contact, {
Employee,
Expand All @@ -39,7 +40,6 @@ import core, {
generateId,
MeasureContext,
MixinUpdate,
RateLimiter,
Ref,
RefTo,
SortingOrder,
Expand Down Expand Up @@ -82,7 +82,6 @@ import serverView from '@hcengineering/server-view'
import { markupToText, stripTags } from '@hcengineering/text-core'
import { encodeObjectURI } from '@hcengineering/view'
import { workbenchId } from '@hcengineering/workbench'
import { Analytics } from '@hcengineering/analytics'

import { Content, ContextsCache, ContextsCacheKey, NotifyParams, NotifyResult } from './types'
import {
Expand All @@ -92,6 +91,7 @@ import {
getNotificationContent,
getNotificationLink,
getNotificationProviderControl,
getObjectSpace,
getTextPresenter,
getUsersInfo,
isAllowed,
Expand All @@ -103,8 +103,7 @@ import {
replaceAll,
toReceiverInfo,
updateNotifyContextsSpace,
type NotificationProviderControl,
getObjectSpace
type NotificationProviderControl
} from './utils'

export function getPushCollaboratorTx (
Expand Down Expand Up @@ -602,25 +601,19 @@ export async function createPushNotification (
}
}

const limiter = new RateLimiter(5)
for (const subscription of userSubscriptions) {
await limiter.add(async () => {
await sendPushToSubscription(sesURL, sesAuth, control, target, subscription, data)
})
}
await limiter.waitProcessing()
void sendPushToSubscription(sesURL, sesAuth, control, target, userSubscriptions, data)
}

async function sendPushToSubscription (
sesURL: string,
sesAuth: string | undefined,
control: TriggerControl,
targetUser: Ref<Account>,
subscription: PushSubscription,
subscriptions: PushSubscription[],
data: PushData
): Promise<void> {
try {
const result: 'ok' | 'clear-push' = (
const result: Ref<PushSubscription>[] = (
await (
await fetch(concatLink(sesURL, '/web-push'), {
method: 'post',
Expand All @@ -629,15 +622,17 @@ async function sendPushToSubscription (
...(sesAuth != null ? { Authorization: `Bearer ${sesAuth}` } : {})
},
body: JSON.stringify({
subscription,
subscriptions,
data
})
})
).json()
).result
if (result === 'clear-push') {
const tx = control.txFactory.createTxRemoveDoc(subscription._class, subscription.space, subscription._id)
await control.apply(control.ctx, [tx])
if (result.length > 0) {
const domain = control.hierarchy.findDomain(notification.class.PushSubscription)
if (domain !== undefined) {
await control.lowLevel.clean(control.ctx, domain, result)
}
}
} catch (err) {
control.ctx.info('Cannot send push notification to', { user: targetUser, err })
Expand Down
6 changes: 5 additions & 1 deletion services/ses/pod-ses/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@

import { main } from './main'

void main()
void main().catch((err) => {
if (err != null) {
console.error(err)
}
})
47 changes: 33 additions & 14 deletions services/ses/pod-ses/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.
//

import type { Ref } from '@hcengineering/core'
import { PushSubscription, type PushData } from '@hcengineering/notification'
import type { Request, Response } from 'express'
import webpush, { WebPushError } from 'web-push'
Expand All @@ -22,25 +23,39 @@ import { SES } from './ses'
import { Endpoint } from './types'

const errorMessages = ['expired', 'Unregistered', 'No such subscription']
async function sendPushToSubscription (subscription: PushSubscription, data: PushData): Promise<'ok' | 'clear-push'> {
try {
await webpush.sendNotification(subscription, JSON.stringify(data))
} catch (err: any) {
if (err instanceof WebPushError) {
if (errorMessages.some((p) => JSON.stringify((err as WebPushError).body).includes(p))) {
return 'clear-push'
async function sendPushToSubscription (
subscriptions: PushSubscription[],
data: PushData
): Promise<Ref<PushSubscription>[]> {
const result: Ref<PushSubscription>[] = []
for (const subscription of subscriptions) {
try {
await webpush.sendNotification(subscription, JSON.stringify(data))
haiodo marked this conversation as resolved.
Show resolved Hide resolved
} catch (err: any) {
if (err instanceof WebPushError) {
if (errorMessages.some((p) => JSON.stringify((err as WebPushError).body).includes(p))) {
result.push(subscription._id)
}
}
}
}
return 'ok'
return result
}

export const main = async (): Promise<void> => {
const ses = new SES()
console.log('SES service has been started')
let webpushInitDone = false

if (config.PushPublicKey !== undefined && config.PushPrivateKey !== undefined) {
webpush.setVapidDetails(config.PushSubject ?? 'mailto:hey@huly.io', config.PushPublicKey, config.PushPublicKey)
try {
const subj = config.PushSubject ?? 'mailto:hey@huly.io'
console.log('Setting VAPID details', subj, config.PushPublicKey.length, config.PushPrivateKey.length)
webpush.setVapidDetails(config.PushSubject ?? 'mailto:hey@huly.io', config.PushPublicKey, config.PushPrivateKey)
webpushInitDone = true
} catch (err: any) {
console.error(err)
}
}

const checkAuth = (req: Request<any>, res: Response<any>): boolean => {
Expand Down Expand Up @@ -104,14 +119,18 @@ export const main = async (): Promise<void> => {
res.status(400).send({ err: "'data' is missing" })
return
}
const subscription: PushSubscription | undefined = req.body?.subscription
if (subscription === undefined) {
res.status(400).send({ err: "'subscription' is missing" })
const subscriptions: PushSubscription[] | undefined = req.body?.subscriptions
if (subscriptions === undefined) {
res.status(400).send({ err: "'subscriptions' is missing" })
return
}
if (!webpushInitDone) {
res.json({ result: [] }).end()
return
}

const result = await sendPushToSubscription(subscription, data)
res.json({ result })
const result = await sendPushToSubscription(subscriptions, data)
res.json({ result }).end()
}
}
]
Expand Down
Loading