From 2650a7a5b8ce95b343f932d029ddb2c20b38b073 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Thu, 6 Apr 2023 06:11:59 +0900
Subject: [PATCH] =?UTF-8?q?fix:=20=E9=80=9A=E7=9F=A5=E3=82=A4=E3=83=B3?=
 =?UTF-8?q?=E3=82=B8=E3=82=B1=E3=83=BC=E3=82=BF=E3=81=8C=E5=85=89=E3=82=8A?=
 =?UTF-8?q?=E3=81=A3=E3=81=B1=E3=81=AA=E3=81=97=E3=81=AB=E3=81=AA=E3=82=8B?=
 =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#10483)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(misskey-js): ストリームがstringで送信される場合があるのを修正

* pnpm run api

* force read notification

* fix competition
---
 .../backend/src/core/NotificationService.ts   |  7 ++++---
 .../notifications/mark-all-as-read.ts         |  2 +-
 packages/misskey-js/etc/misskey-js.api.md     | 19 +++++++------------
 packages/misskey-js/src/streaming.ts          | 19 +++++++++++++------
 4 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts
index 366dc08c02..c44dddea41 100644
--- a/packages/backend/src/core/NotificationService.ts
+++ b/packages/backend/src/core/NotificationService.ts
@@ -43,6 +43,7 @@ export class NotificationService implements OnApplicationShutdown {
 	@bindThis
 	public async readAllNotification(
 		userId: User['id'],
+		force = false,
 	) {
 		const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${userId}`);
 		
@@ -57,7 +58,7 @@ export class NotificationService implements OnApplicationShutdown {
 
 		this.redisClient.set(`latestReadNotification:${userId}`, latestNotificationId);
 
-		if (latestReadNotificationId == null || (latestReadNotificationId < latestNotificationId)) {
+		if (force || latestReadNotificationId == null || (latestReadNotificationId < latestNotificationId)) {
 			return this.postReadAllNotifications(userId);
 		}
 	}
@@ -95,7 +96,7 @@ export class NotificationService implements OnApplicationShutdown {
 			...data,
 		} as Notification;
 
-		this.redisClient.xadd(
+		const redisIdPromise = this.redisClient.xadd(
 			`notificationTimeline:${notifieeId}`,
 			'MAXLEN', '~', '300',
 			`${this.idService.parse(notification.id).date.getTime()}-*`,
@@ -109,7 +110,7 @@ export class NotificationService implements OnApplicationShutdown {
 		// 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
 		setTimeout(2000, 'unread notification', { signal: this.#shutdownController.signal }).then(async () => {
 			const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${notifieeId}`);
-			if (latestReadNotificationId && (latestReadNotificationId >= notification.id)) return;
+			if (latestReadNotificationId && (latestReadNotificationId >= await redisIdPromise)) return;
 
 			this.globalEventService.publishMainStream(notifieeId, 'unreadNotification', packed);
 			this.pushNotificationService.pushNotification(notifieeId, 'notification', packed);
diff --git a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts
index 9ba6079189..e601bf9d5b 100644
--- a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts
+++ b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts
@@ -24,7 +24,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 		private notificationService: NotificationService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
-			this.notificationService.readAllNotification(me.id);
+			this.notificationService.readAllNotification(me.id, true);
 		});
 	}
 }
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index e57484be6b..2511f14dcc 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -166,8 +166,6 @@ export type Channels = {
             readAllAntennas: () => void;
             unreadAntenna: (payload: Antenna) => void;
             readAllAnnouncements: () => void;
-            readAllChannels: () => void;
-            unreadChannel: (payload: Note['id']) => void;
             myTokenRegenerated: () => void;
             reversiNoInvites: () => void;
             reversiInvited: (payload: FIXME) => void;
@@ -1857,12 +1855,6 @@ export type Endpoints = {
         req: NoParams;
         res: null;
     };
-    'notifications/read': {
-        req: {
-            notificationId: Notification_2['id'];
-        };
-        res: null;
-    };
     'page-push': {
         req: {
             pageId: Page['id'];
@@ -2361,7 +2353,6 @@ type MeDetailed = UserDetailed & {
     hasPendingReceivedFollowRequest: boolean;
     hasUnreadAnnouncement: boolean;
     hasUnreadAntenna: boolean;
-    hasUnreadChannel: boolean;
     hasUnreadMentions: boolean;
     hasUnreadMessagingMessage: boolean;
     hasUnreadNotification: boolean;
@@ -2618,7 +2609,11 @@ export class Stream extends EventEmitter<StreamEvents> {
     // (undocumented)
     removeSharedConnectionPool(pool: Pool): void;
     // (undocumented)
-    send(typeOrPayload: any, payload?: any): void;
+    send(typeOrPayload: string): void;
+    // (undocumented)
+    send(typeOrPayload: string, payload: any): void;
+    // (undocumented)
+    send(typeOrPayload: Record<string, any> | any[]): void;
     // (undocumented)
     state: 'initializing' | 'reconnecting' | 'connected';
     // (undocumented)
@@ -2714,8 +2709,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
 //
 // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts
 // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
-// src/api.types.ts:595:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
-// src/streaming.types.ts:35:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts
+// src/api.types.ts:594:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
+// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts
 
 // (No @packageDocumentation comment for this package)
 
diff --git a/packages/misskey-js/src/streaming.ts b/packages/misskey-js/src/streaming.ts
index 12f386ddbf..0218b40a03 100644
--- a/packages/misskey-js/src/streaming.ts
+++ b/packages/misskey-js/src/streaming.ts
@@ -169,14 +169,21 @@ export default class Stream extends EventEmitter<StreamEvents> {
 
 	/**
 	 * Send a message to connection
+	 * ! ストリーム上のやり取りはすべてJSONで行われます !
 	 */
-	public send(typeOrPayload: any, payload?: any): void {
-		const data = payload === undefined ? typeOrPayload : {
-			type: typeOrPayload,
-			body: payload,
-		};
+	public send(typeOrPayload: string): void
+	public send(typeOrPayload: string, payload: any): void
+	public send(typeOrPayload: Record<string, any> | any[]): void
+	public send(typeOrPayload: string | Record<string, any> | any[], payload?: any): void {
+		if (typeof typeOrPayload === 'string') {
+			this.stream.send(JSON.stringify({
+				type: typeOrPayload,
+				...(payload === undefined ? {} : { body: payload }),
+			}));
+			return;
+		}
 
-		this.stream.send(JSON.stringify(data));
+		this.stream.send(JSON.stringify(typeOrPayload));
 	}
 
 	/**