fix: readAllNotifications message not working (#14374)
* refactor: add and use isJsonObject * fix: readNotification message without body is not working * docs(changelog): WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 * Update CHANGELOG.md Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> --------- Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									0d508db8a7
								
							
						
					
					
						commit
						f50941389d
					
				
					 6 changed files with 31 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -8,7 +8,9 @@
 | 
			
		|||
-
 | 
			
		||||
 | 
			
		||||
### Server
 | 
			
		||||
-
 | 
			
		||||
- Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374
 | 
			
		||||
  - 通知ページや通知カラム(デッキ)を開いている状態において、新たに発生した通知が既読されない問題が修正されます。
 | 
			
		||||
  - これにより、プッシュ通知が有効な同条件下の環境において、プッシュ通知が常に発生してしまう問題も修正されます。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 2024.7.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,3 +6,7 @@
 | 
			
		|||
export type JsonValue = JsonArray | JsonObject | string | number | boolean | null;
 | 
			
		||||
export type JsonObject = {[K in string]?: JsonValue};
 | 
			
		||||
export type JsonArray = JsonValue[];
 | 
			
		||||
 | 
			
		||||
export function isJsonObject(value: JsonValue | undefined): value is JsonObject {
 | 
			
		||||
	return typeof value === 'object' && value !== null && !Array.isArray(value);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,8 @@ import { CacheService } from '@/core/CacheService.js';
 | 
			
		|||
import { MiFollowing, MiUserProfile } from '@/models/_.js';
 | 
			
		||||
import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js';
 | 
			
		||||
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
 | 
			
		||||
import type { JsonObject } from '@/misc/json-value.js';
 | 
			
		||||
import { isJsonObject } from '@/misc/json-value.js';
 | 
			
		||||
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
 | 
			
		||||
import type { ChannelsService } from './ChannelsService.js';
 | 
			
		||||
import type { EventEmitter } from 'events';
 | 
			
		||||
import type Channel from './channel.js';
 | 
			
		||||
| 
						 | 
				
			
			@ -112,8 +113,6 @@ export default class Connection {
 | 
			
		|||
 | 
			
		||||
		const { type, body } = obj;
 | 
			
		||||
 | 
			
		||||
		if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
 | 
			
		||||
 | 
			
		||||
		switch (type) {
 | 
			
		||||
			case 'readNotification': this.onReadNotification(body); break;
 | 
			
		||||
			case 'subNote': this.onSubscribeNote(body); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +153,8 @@ export default class Connection {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@bindThis
 | 
			
		||||
	private readNote(body: JsonObject) {
 | 
			
		||||
	private readNote(body: JsonValue | undefined) {
 | 
			
		||||
		if (!isJsonObject(body)) return;
 | 
			
		||||
		const id = body.id;
 | 
			
		||||
 | 
			
		||||
		const note = this.cachedNotes.find(n => n.id === id);
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +166,7 @@ export default class Connection {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@bindThis
 | 
			
		||||
	private onReadNotification(payload: JsonObject) {
 | 
			
		||||
	private onReadNotification(payload: JsonValue | undefined) {
 | 
			
		||||
		this.notificationService.readAllNotification(this.user!.id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +174,8 @@ export default class Connection {
 | 
			
		|||
	 * 投稿購読要求時
 | 
			
		||||
	 */
 | 
			
		||||
	@bindThis
 | 
			
		||||
	private onSubscribeNote(payload: JsonObject) {
 | 
			
		||||
	private onSubscribeNote(payload: JsonValue | undefined) {
 | 
			
		||||
		if (!isJsonObject(payload)) return;
 | 
			
		||||
		if (!payload.id || typeof payload.id !== 'string') return;
 | 
			
		||||
 | 
			
		||||
		const current = this.subscribingNotes[payload.id] ?? 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +191,8 @@ export default class Connection {
 | 
			
		|||
	 * 投稿購読解除要求時
 | 
			
		||||
	 */
 | 
			
		||||
	@bindThis
 | 
			
		||||
	private onUnsubscribeNote(payload: JsonObject) {
 | 
			
		||||
	private onUnsubscribeNote(payload: JsonValue | undefined) {
 | 
			
		||||
		if (!isJsonObject(payload)) return;
 | 
			
		||||
		if (!payload.id || typeof payload.id !== 'string') return;
 | 
			
		||||
 | 
			
		||||
		const current = this.subscribingNotes[payload.id];
 | 
			
		||||
| 
						 | 
				
			
			@ -216,12 +218,13 @@ export default class Connection {
 | 
			
		|||
	 * チャンネル接続要求時
 | 
			
		||||
	 */
 | 
			
		||||
	@bindThis
 | 
			
		||||
	private onChannelConnectRequested(payload: JsonObject) {
 | 
			
		||||
	private onChannelConnectRequested(payload: JsonValue | undefined) {
 | 
			
		||||
		if (!isJsonObject(payload)) return;
 | 
			
		||||
		const { channel, id, params, pong } = payload;
 | 
			
		||||
		if (typeof id !== 'string') return;
 | 
			
		||||
		if (typeof channel !== 'string') return;
 | 
			
		||||
		if (typeof pong !== 'boolean' && typeof pong !== 'undefined' && pong !== null) return;
 | 
			
		||||
		if (typeof params !== 'undefined' && (typeof params !== 'object' || params === null || Array.isArray(params))) return;
 | 
			
		||||
		if (typeof params !== 'undefined' && !isJsonObject(params)) return;
 | 
			
		||||
		this.connectChannel(id, params, channel, pong ?? undefined);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -229,7 +232,8 @@ export default class Connection {
 | 
			
		|||
	 * チャンネル切断要求時
 | 
			
		||||
	 */
 | 
			
		||||
	@bindThis
 | 
			
		||||
	private onChannelDisconnectRequested(payload: JsonObject) {
 | 
			
		||||
	private onChannelDisconnectRequested(payload: JsonValue | undefined) {
 | 
			
		||||
		if (!isJsonObject(payload)) return;
 | 
			
		||||
		const { id } = payload;
 | 
			
		||||
		if (typeof id !== 'string') return;
 | 
			
		||||
		this.disconnectChannel(id);
 | 
			
		||||
| 
						 | 
				
			
			@ -297,7 +301,8 @@ export default class Connection {
 | 
			
		|||
	 * @param data メッセージ
 | 
			
		||||
	 */
 | 
			
		||||
	@bindThis
 | 
			
		||||
	private onChannelMessageRequested(data: JsonObject) {
 | 
			
		||||
	private onChannelMessageRequested(data: JsonValue | undefined) {
 | 
			
		||||
		if (!isJsonObject(data)) return;
 | 
			
		||||
		if (typeof data.id !== 'string') return;
 | 
			
		||||
		if (typeof data.type !== 'string') return;
 | 
			
		||||
		if (typeof data.body === 'undefined') return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
import Xev from 'xev';
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { bindThis } from '@/decorators.js';
 | 
			
		||||
import { isJsonObject } from '@/misc/json-value.js';
 | 
			
		||||
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
 | 
			
		||||
import Channel, { type MiChannelService } from '../channel.js';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +37,7 @@ class QueueStatsChannel extends Channel {
 | 
			
		|||
	public onMessage(type: string, body: JsonValue) {
 | 
			
		||||
		switch (type) {
 | 
			
		||||
			case 'requestLog':
 | 
			
		||||
				if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
 | 
			
		||||
				if (!isJsonObject(body)) return;
 | 
			
		||||
				if (typeof body.id !== 'string') return;
 | 
			
		||||
				if (typeof body.length !== 'number') return;
 | 
			
		||||
				ev.once(`queueStatsLog:${body.id}`, statsLog => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import { DI } from '@/di-symbols.js';
 | 
			
		|||
import { bindThis } from '@/decorators.js';
 | 
			
		||||
import { ReversiService } from '@/core/ReversiService.js';
 | 
			
		||||
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
 | 
			
		||||
import { isJsonObject } from '@/misc/json-value.js';
 | 
			
		||||
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
 | 
			
		||||
import Channel, { type MiChannelService } from '../channel.js';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,16 +45,16 @@ class ReversiGameChannel extends Channel {
 | 
			
		|||
				this.ready(body);
 | 
			
		||||
				break;
 | 
			
		||||
			case 'updateSettings':
 | 
			
		||||
				if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
 | 
			
		||||
				if (!isJsonObject(body)) return;
 | 
			
		||||
				if (typeof body.key !== 'string') return;
 | 
			
		||||
				if (typeof body.value !== 'object' || body.value === null || Array.isArray(body.value)) return;
 | 
			
		||||
				if (!isJsonObject(body.value)) return;
 | 
			
		||||
				this.updateSettings(body.key, body.value);
 | 
			
		||||
				break;
 | 
			
		||||
			case 'cancel':
 | 
			
		||||
				this.cancelGame();
 | 
			
		||||
				break;
 | 
			
		||||
			case 'putStone':
 | 
			
		||||
				if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
 | 
			
		||||
				if (!isJsonObject(body)) return;
 | 
			
		||||
				if (typeof body.pos !== 'number') return;
 | 
			
		||||
				if (typeof body.id !== 'string') return;
 | 
			
		||||
				this.putStone(body.pos, body.id);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
import Xev from 'xev';
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { bindThis } from '@/decorators.js';
 | 
			
		||||
import { isJsonObject } from '@/misc/json-value.js';
 | 
			
		||||
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
 | 
			
		||||
import Channel, { type MiChannelService } from '../channel.js';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +37,7 @@ class ServerStatsChannel extends Channel {
 | 
			
		|||
	public onMessage(type: string, body: JsonValue) {
 | 
			
		||||
		switch (type) {
 | 
			
		||||
			case 'requestLog':
 | 
			
		||||
				if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
 | 
			
		||||
				if (!isJsonObject(body)) return;
 | 
			
		||||
				ev.once(`serverStatsLog:${body.id}`, statsLog => {
 | 
			
		||||
					this.send('statsLog', statsLog);
 | 
			
		||||
				});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue