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