117 lines
2.9 KiB
TypeScript
117 lines
2.9 KiB
TypeScript
import push from "web-push";
|
|
import config from "@/config/index.js";
|
|
import { SwSubscriptions } from "@/models/index.js";
|
|
import { fetchMeta } from "@/misc/fetch-meta.js";
|
|
import type { Packed } from "@/misc/schema.js";
|
|
import { getNoteSummary } from "@/misc/get-note-summary.js";
|
|
|
|
// Defined also packages/sw/types.ts#L14-L21
|
|
type pushNotificationsTypes = {
|
|
notification: Packed<"Notification">;
|
|
unreadMessagingMessage: Packed<"MessagingMessage">;
|
|
readNotifications: { notificationIds: string[] };
|
|
readAllNotifications: undefined;
|
|
readAllMessagingMessages: undefined;
|
|
readAllMessagingMessagesOfARoom: { userId: string } | { groupId: string };
|
|
};
|
|
|
|
// プッシュメッセージサーバーには文字数制限があるため、内容を削減します
|
|
function truncateNotification(notification: Packed<"Notification">): any {
|
|
if (notification.note) {
|
|
return {
|
|
...notification,
|
|
note: {
|
|
...notification.note,
|
|
// textをgetNoteSummaryしたものに置き換える
|
|
text: getNoteSummary(
|
|
notification.type === "renote"
|
|
? (notification.note.renote as Packed<"Note">)
|
|
: notification.note,
|
|
),
|
|
|
|
cw: undefined,
|
|
reply: undefined,
|
|
renote: undefined,
|
|
user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる
|
|
},
|
|
};
|
|
}
|
|
|
|
return notification;
|
|
}
|
|
|
|
export async function pushNotification<T extends keyof pushNotificationsTypes>(
|
|
userId: string,
|
|
type: T,
|
|
body: pushNotificationsTypes[T],
|
|
) {
|
|
const meta = await fetchMeta();
|
|
|
|
if (
|
|
!meta.enableServiceWorker ||
|
|
meta.swPublicKey == null ||
|
|
meta.swPrivateKey == null
|
|
)
|
|
return;
|
|
|
|
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録
|
|
push.setVapidDetails(config.url, meta.swPublicKey, meta.swPrivateKey);
|
|
|
|
// Fetch
|
|
const subscriptions = await SwSubscriptions.findBy({
|
|
userId: userId,
|
|
});
|
|
|
|
for (const subscription of subscriptions) {
|
|
if (
|
|
[
|
|
"readNotifications",
|
|
"readAllNotifications",
|
|
"readAllMessagingMessages",
|
|
"readAllMessagingMessagesOfARoom",
|
|
].includes(type) &&
|
|
!subscription.sendReadMessage
|
|
)
|
|
continue;
|
|
|
|
const pushSubscription = {
|
|
endpoint: subscription.endpoint,
|
|
keys: {
|
|
auth: subscription.auth,
|
|
p256dh: subscription.publickey,
|
|
},
|
|
};
|
|
|
|
push
|
|
.sendNotification(
|
|
pushSubscription,
|
|
JSON.stringify({
|
|
type,
|
|
body:
|
|
type === "notification"
|
|
? truncateNotification(body as Packed<"Notification">)
|
|
: body,
|
|
userId,
|
|
dateTime: new Date().getTime(),
|
|
}),
|
|
{
|
|
proxy: config.proxy,
|
|
},
|
|
)
|
|
.catch((err: any) => {
|
|
//swLogger.info(err.statusCode);
|
|
//swLogger.info(err.headers);
|
|
//swLogger.info(err.body);
|
|
|
|
if (err.statusCode === 410) {
|
|
SwSubscriptions.delete({
|
|
userId: userId,
|
|
endpoint: subscription.endpoint,
|
|
auth: subscription.auth,
|
|
publickey: subscription.publickey,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|