summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortamaina <tamaina@hotmail.co.jp>2021-10-21 01:04:10 +0900
committerGitHub <noreply@github.com>2021-10-21 01:04:10 +0900
commit69b56f6658dcbef0a54fa030ebf30913ca3d30bd (patch)
tree376ee75076a4c7de6be2c6b3a54168319b8ded84
parentMerge branch 'develop' of https://github.com/misskey-dev/misskey into develop (diff)
downloadsharkey-69b56f6658dcbef0a54fa030ebf30913ca3d30bd.tar.gz
sharkey-69b56f6658dcbef0a54fa030ebf30913ca3d30bd.tar.bz2
sharkey-69b56f6658dcbef0a54fa030ebf30913ca3d30bd.zip
refactor: publishHogeStreamとStreamのEventEmitterに型定義する (#7769)
* wip * wip * wip * :v: * add main stream * packedNotificationSchemaを更新 * read:gallery, write:gallery, read:gallery-likes, write:gallery-likesに翻訳を追加 * fix * ok * add header, choice, invitation * add header, choice, invitation * test * fix * fix * yatta * remove no longer needed "as PackedUser/PackedNote" * clean up * add simple-schema * fix lint * fix lint * wip * wip! * wip * fix * wip * wip * :v: * 送信側に型エラーがないことを3回確認した * :v: * wip * update typescript * define items in full Schema * edit comment * edit comment * edit comment * Update src/prelude/types.ts Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> * https://github.com/misskey-dev/misskey/pull/7769#discussion_r703058458 * user packとnote packの型不整合を修正 * revert https://github.com/misskey-dev/misskey/pull/7772#discussion_r706627736 * revert https://github.com/misskey-dev/misskey/pull/7772#discussion_r706627736 * user packとnote packの型不整合を修正 * add prelude/types.ts * emoji * signin * game * matching * clean up * ev => data * refactor * clean up * add type * antenna * channel * fix * add Packed type * add PackedRef * fix lint * add emoji schema * add reversiGame * add reversiMatching * remove signin schema (use Signin entity) * add schemas refs, fix Packed type * wip PackedHoge => Packed<'Hoge'> * add Packed type * note-reaction * user * user-group * user-list * note * app, messaging-message * notification * drive-file * drive-folder * following * muting * blocking * hashtag * page * app (with modifying schema) * import user? * channel * antenna * clip * gallery-post * emoji * Packed * reversi-matching * update stream.ts * https://github.com/misskey-dev/misskey/pull/7769#issuecomment-917542339 * fix lint * clean up? * add changelog * add changelog * add changelog * fix: アンテナが既読にならないのを修正 * revert fix * https://github.com/misskey-dev/misskey/pull/7769#discussion_r711474875 * spec => payload * edit commetn Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
-rw-r--r--package.json1
-rw-r--r--src/models/repositories/signin.ts2
-rw-r--r--src/server/api/common/read-messaging-message.ts2
-rw-r--r--src/server/api/endpoints/antennas/update.ts2
-rw-r--r--src/server/api/stream/channels/antenna.ts11
-rw-r--r--src/server/api/stream/channels/channel.ts3
-rw-r--r--src/server/api/stream/channels/main.ts24
-rw-r--r--src/server/api/stream/channels/messaging.ts6
-rw-r--r--src/server/api/stream/index.ts35
-rw-r--r--src/server/api/stream/types.ts299
-rw-r--r--src/services/stream.ts53
-rw-r--r--yarn.lock5
12 files changed, 383 insertions, 60 deletions
diff --git a/package.json b/package.json
index c1fcff7126..10ddea2c1e 100644
--- a/package.json
+++ b/package.json
@@ -208,6 +208,7 @@
"seedrandom": "3.0.5",
"sharp": "0.29.1",
"speakeasy": "2.0.0",
+ "strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"style-loader": "3.3.0",
"summaly": "2.4.1",
diff --git a/src/models/repositories/signin.ts b/src/models/repositories/signin.ts
index 9942d2d962..f375f9b5c0 100644
--- a/src/models/repositories/signin.ts
+++ b/src/models/repositories/signin.ts
@@ -4,7 +4,7 @@ import { Signin } from '@/models/entities/signin';
@EntityRepository(Signin)
export class SigninRepository extends Repository<Signin> {
public async pack(
- src: any,
+ src: Signin,
) {
return src;
}
diff --git a/src/server/api/common/read-messaging-message.ts b/src/server/api/common/read-messaging-message.ts
index 1dce76d2a9..33f41b2770 100644
--- a/src/server/api/common/read-messaging-message.ts
+++ b/src/server/api/common/read-messaging-message.ts
@@ -77,7 +77,7 @@ export async function readGroupMessagingMessage(
id: In(messageIds)
});
- const reads = [];
+ const reads: MessagingMessage['id'][] = [];
for (const message of messages) {
if (message.userId === userId) continue;
diff --git a/src/server/api/endpoints/antennas/update.ts b/src/server/api/endpoints/antennas/update.ts
index ff13e89bcc..d69b4feee6 100644
--- a/src/server/api/endpoints/antennas/update.ts
+++ b/src/server/api/endpoints/antennas/update.ts
@@ -137,7 +137,7 @@ export default define(meta, async (ps, user) => {
notify: ps.notify,
});
- publishInternalEvent('antennaUpdated', Antennas.findOneOrFail(antenna.id));
+ publishInternalEvent('antennaUpdated', await Antennas.findOneOrFail(antenna.id));
return await Antennas.pack(antenna.id);
});
diff --git a/src/server/api/stream/channels/antenna.ts b/src/server/api/stream/channels/antenna.ts
index bf9c53c453..3cbdfebb43 100644
--- a/src/server/api/stream/channels/antenna.ts
+++ b/src/server/api/stream/channels/antenna.ts
@@ -3,6 +3,7 @@ import Channel from '../channel';
import { Notes } from '@/models/index';
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
+import { StreamMessages } from '../types';
export default class extends Channel {
public readonly chName = 'antenna';
@@ -19,11 +20,9 @@ export default class extends Channel {
}
@autobind
- private async onEvent(data: any) {
- const { type, body } = data;
-
- if (type === 'note') {
- const note = await Notes.pack(body.id, this.user, { detail: true });
+ private async onEvent(data: StreamMessages['antenna']['payload']) {
+ if (data.type === 'note') {
+ const note = await Notes.pack(data.body.id, this.user, { detail: true });
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
@@ -34,7 +33,7 @@ export default class extends Channel {
this.send('note', note);
} else {
- this.send(type, body);
+ this.send(data.type, data.body);
}
}
diff --git a/src/server/api/stream/channels/channel.ts b/src/server/api/stream/channels/channel.ts
index 72ddbf93b4..bf7942f522 100644
--- a/src/server/api/stream/channels/channel.ts
+++ b/src/server/api/stream/channels/channel.ts
@@ -4,6 +4,7 @@ import { Notes, Users } from '@/models/index';
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
import { User } from '@/models/entities/user';
+import { StreamMessages } from '../types';
import { Packed } from '@/misc/schema';
export default class extends Channel {
@@ -52,7 +53,7 @@ export default class extends Channel {
}
@autobind
- private onEvent(data: any) {
+ private onEvent(data: StreamMessages['channel']['payload']) {
if (data.type === 'typing') {
const id = data.body;
const begin = this.typers[id] == null;
diff --git a/src/server/api/stream/channels/main.ts b/src/server/api/stream/channels/main.ts
index b99cb931da..131ac30472 100644
--- a/src/server/api/stream/channels/main.ts
+++ b/src/server/api/stream/channels/main.ts
@@ -11,35 +11,33 @@ export default class extends Channel {
public async init(params: any) {
// Subscribe main stream channel
this.subscriber.on(`mainStream:${this.user!.id}`, async data => {
- const { type } = data;
- let { body } = data;
-
- switch (type) {
+ switch (data.type) {
case 'notification': {
- if (this.muting.has(body.userId)) return;
- if (body.note && body.note.isHidden) {
- const note = await Notes.pack(body.note.id, this.user, {
+ if (data.body.userId && this.muting.has(data.body.userId)) return;
+
+ if (data.body.note && data.body.note.isHidden) {
+ const note = await Notes.pack(data.body.note.id, this.user, {
detail: true
});
this.connection.cacheNote(note);
- body.note = note;
+ data.body.note = note;
}
break;
}
case 'mention': {
- if (this.muting.has(body.userId)) return;
- if (body.isHidden) {
- const note = await Notes.pack(body.id, this.user, {
+ if (this.muting.has(data.body.userId)) return;
+ if (data.body.isHidden) {
+ const note = await Notes.pack(data.body.id, this.user, {
detail: true
});
this.connection.cacheNote(note);
- body = note;
+ data.body = note;
}
break;
}
}
- this.send(type, body);
+ this.send(data.type, data.body);
});
}
}
diff --git a/src/server/api/stream/channels/messaging.ts b/src/server/api/stream/channels/messaging.ts
index 015b0a7650..c049e880b9 100644
--- a/src/server/api/stream/channels/messaging.ts
+++ b/src/server/api/stream/channels/messaging.ts
@@ -3,6 +3,8 @@ import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivit
import Channel from '../channel';
import { UserGroupJoinings, Users, MessagingMessages } from '@/models/index';
import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
+import { UserGroup } from '@/models/entities/user-group';
+import { StreamMessages } from '../types';
export default class extends Channel {
public readonly chName = 'messaging';
@@ -12,7 +14,7 @@ export default class extends Channel {
private otherpartyId: string | null;
private otherparty: User | null;
private groupId: string | null;
- private subCh: string;
+ private subCh: `messagingStream:${User['id']}-${User['id']}` | `messagingStream:${UserGroup['id']}`;
private typers: Record<User['id'], Date> = {};
private emitTypersIntervalId: ReturnType<typeof setInterval>;
@@ -45,7 +47,7 @@ export default class extends Channel {
}
@autobind
- private onEvent(data: any) {
+ private onEvent(data: StreamMessages['messaging']['payload'] | StreamMessages['groupMessaging']['payload']) {
if (data.type === 'typing') {
const id = data.body;
const begin = this.typers[id] == null;
diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts
index ccd555e149..da4ea5ec99 100644
--- a/src/server/api/stream/index.ts
+++ b/src/server/api/stream/index.ts
@@ -14,6 +14,7 @@ import { AccessToken } from '@/models/entities/access-token';
import { UserProfile } from '@/models/entities/user-profile';
import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '@/services/stream';
import { UserGroup } from '@/models/entities/user-group';
+import { StreamEventEmitter, StreamMessages } from './types';
import { Packed } from '@/misc/schema';
/**
@@ -28,7 +29,7 @@ export default class Connection {
public followingChannels: Set<ChannelModel['id']> = new Set();
public token?: AccessToken;
private wsConnection: websocket.connection;
- public subscriber: EventEmitter;
+ public subscriber: StreamEventEmitter;
private channels: Channel[] = [];
private subscribingNotes: any = {};
private cachedNotes: Packed<'Note'>[] = [];
@@ -46,8 +47,8 @@ export default class Connection {
this.wsConnection.on('message', this.onWsConnectionMessage);
- this.subscriber.on('broadcast', async ({ type, body }) => {
- this.onBroadcastMessage(type, body);
+ this.subscriber.on('broadcast', data => {
+ this.onBroadcastMessage(data);
});
if (this.user) {
@@ -57,43 +58,41 @@ export default class Connection {
this.updateFollowingChannels();
this.updateUserProfile();
- this.subscriber.on(`user:${this.user.id}`, ({ type, body }) => {
- this.onUserEvent(type, body);
- });
+ this.subscriber.on(`user:${this.user.id}`, this.onUserEvent);
}
}
@autobind
- private onUserEvent(type: string, body: any) {
- switch (type) {
+ private onUserEvent(data: StreamMessages['user']['payload']) { // { type, body }と展開するとそれぞれ型が分離してしまう
+ switch (data.type) {
case 'follow':
- this.following.add(body.id);
+ this.following.add(data.body.id);
break;
case 'unfollow':
- this.following.delete(body.id);
+ this.following.delete(data.body.id);
break;
case 'mute':
- this.muting.add(body.id);
+ this.muting.add(data.body.id);
break;
case 'unmute':
- this.muting.delete(body.id);
+ this.muting.delete(data.body.id);
break;
// TODO: block events
case 'followChannel':
- this.followingChannels.add(body.id);
+ this.followingChannels.add(data.body.id);
break;
case 'unfollowChannel':
- this.followingChannels.delete(body.id);
+ this.followingChannels.delete(data.body.id);
break;
case 'updateUserProfile':
- this.userProfile = body;
+ this.userProfile = data.body;
break;
case 'terminate':
@@ -145,8 +144,8 @@ export default class Connection {
}
@autobind
- private onBroadcastMessage(type: string, body: any) {
- this.sendMessageToWs(type, body);
+ private onBroadcastMessage(data: StreamMessages['broadcast']['payload']) {
+ this.sendMessageToWs(data.type, data.body);
}
@autobind
@@ -249,7 +248,7 @@ export default class Connection {
}
@autobind
- private async onNoteStreamMessage(data: any) {
+ private async onNoteStreamMessage(data: StreamMessages['note']['payload']) {
this.sendMessageToWs('noteUpdated', {
id: data.body.id,
type: data.type,
diff --git a/src/server/api/stream/types.ts b/src/server/api/stream/types.ts
new file mode 100644
index 0000000000..70eb5c5ce5
--- /dev/null
+++ b/src/server/api/stream/types.ts
@@ -0,0 +1,299 @@
+import { EventEmitter } from 'events';
+import Emitter from 'strict-event-emitter-types';
+import { Channel } from '@/models/entities/channel';
+import { User } from '@/models/entities/user';
+import { UserProfile } from '@/models/entities/user-profile';
+import { Note } from '@/models/entities/note';
+import { Antenna } from '@/models/entities/antenna';
+import { DriveFile } from '@/models/entities/drive-file';
+import { DriveFolder } from '@/models/entities/drive-folder';
+import { Emoji } from '@/models/entities/emoji';
+import { UserList } from '@/models/entities/user-list';
+import { MessagingMessage } from '@/models/entities/messaging-message';
+import { UserGroup } from '@/models/entities/user-group';
+import { ReversiGame } from '@/models/entities/games/reversi/game';
+import { AbuseUserReport } from '@/models/entities/abuse-user-report';
+import { Signin } from '@/models/entities/signin';
+import { Page } from '@/models/entities/page';
+import { Packed } from '@/misc/schema';
+
+//#region Stream type-body definitions
+export interface InternalStreamTypes {
+ antennaCreated: Antenna;
+ antennaDeleted: Antenna;
+ antennaUpdated: Antenna;
+}
+
+export interface BroadcastTypes {
+ emojiAdded: {
+ emoji: Packed<'Emoji'>;
+ };
+}
+
+export interface UserStreamTypes {
+ terminate: {};
+ followChannel: Channel;
+ unfollowChannel: Channel;
+ updateUserProfile: UserProfile;
+ mute: User;
+ unmute: User;
+ follow: Packed<'User'>;
+ unfollow: Packed<'User'>;
+ userAdded: Packed<'User'>;
+}
+
+export interface MainStreamTypes {
+ notification: Packed<'Notification'>;
+ mention: Packed<'Note'>;
+ reply: Packed<'Note'>;
+ renote: Packed<'Note'>;
+ follow: Packed<'User'>;
+ followed: Packed<'User'>;
+ unfollow: Packed<'User'>;
+ meUpdated: Packed<'User'>;
+ pageEvent: {
+ pageId: Page['id'];
+ event: string;
+ var: any;
+ userId: User['id'];
+ user: Packed<'User'>;
+ };
+ urlUploadFinished: {
+ marker?: string | null;
+ file: Packed<'DriveFile'>;
+ };
+ readAllNotifications: undefined;
+ unreadNotification: Packed<'Notification'>;
+ unreadMention: Note['id'];
+ readAllUnreadMentions: undefined;
+ unreadSpecifiedNote: Note['id'];
+ readAllUnreadSpecifiedNotes: undefined;
+ readAllMessagingMessages: undefined;
+ messagingMessage: Packed<'MessagingMessage'>;
+ unreadMessagingMessage: Packed<'MessagingMessage'>;
+ readAllAntennas: undefined;
+ unreadAntenna: Antenna;
+ readAllAnnouncements: undefined;
+ readAllChannels: undefined;
+ unreadChannel: Note['id'];
+ myTokenRegenerated: undefined;
+ reversiNoInvites: undefined;
+ reversiInvited: Packed<'ReversiMatching'>;
+ signin: Signin;
+ registryUpdated: {
+ scope?: string[];
+ key: string;
+ value: any | null;
+ };
+ driveFileCreated: Packed<'DriveFile'>;
+ readAntenna: Antenna;
+}
+
+export interface DriveStreamTypes {
+ fileCreated: Packed<'DriveFile'>;
+ fileDeleted: DriveFile['id'];
+ fileUpdated: Packed<'DriveFile'>;
+ folderCreated: Packed<'DriveFolder'>;
+ folderDeleted: DriveFolder['id'];
+ folderUpdated: Packed<'DriveFolder'>;
+}
+
+export interface NoteStreamTypes {
+ pollVoted: {
+ choice: number;
+ userId: User['id'];
+ };
+ deleted: {
+ deletedAt: Date;
+ };
+ reacted: {
+ reaction: string;
+ emoji?: Emoji;
+ userId: User['id'];
+ };
+ unreacted: {
+ reaction: string;
+ userId: User['id'];
+ };
+}
+type NoteStreamEventTypes = {
+ [key in keyof NoteStreamTypes]: {
+ id: Note['id'];
+ body: NoteStreamTypes[key];
+ };
+};
+
+export interface ChannelStreamTypes {
+ typing: User['id'];
+}
+
+export interface UserListStreamTypes {
+ userAdded: Packed<'User'>;
+ userRemoved: Packed<'User'>;
+}
+
+export interface AntennaStreamTypes {
+ note: Note;
+}
+
+export interface MessagingStreamTypes {
+ read: MessagingMessage['id'][];
+ typing: User['id'];
+ message: Packed<'MessagingMessage'>;
+ deleted: MessagingMessage['id'];
+}
+
+export interface GroupMessagingStreamTypes {
+ read: {
+ ids: MessagingMessage['id'][];
+ userId: User['id'];
+ };
+ typing: User['id'];
+ message: Packed<'MessagingMessage'>;
+ deleted: MessagingMessage['id'];
+}
+
+export interface MessagingIndexStreamTypes {
+ read: MessagingMessage['id'][];
+ message: Packed<'MessagingMessage'>;
+}
+
+export interface ReversiStreamTypes {
+ matched: Packed<'ReversiGame'>;
+ invited: Packed<'ReversiMatching'>;
+}
+
+export interface ReversiGameStreamTypes {
+ started: Packed<'ReversiGame'>;
+ ended: {
+ winnerId?: User['id'] | null,
+ game: Packed<'ReversiGame'>;
+ };
+ updateSettings: {
+ key: string;
+ value: FIXME;
+ };
+ initForm: {
+ userId: User['id'];
+ form: FIXME;
+ };
+ updateForm: {
+ userId: User['id'];
+ id: string;
+ value: FIXME;
+ };
+ message: {
+ userId: User['id'];
+ message: FIXME;
+ };
+ changeAccepts: {
+ user1: boolean;
+ user2: boolean;
+ };
+ set: {
+ at: Date;
+ color: boolean;
+ pos: number;
+ next: boolean;
+ };
+ watching: User['id'];
+}
+
+export interface AdminStreamTypes {
+ newAbuseUserReport: {
+ id: AbuseUserReport['id'];
+ targetUserId: User['id'],
+ reporterId: User['id'],
+ comment: string;
+ };
+}
+//#endregion
+
+// 辞書(interface or type)から{ type, body }ユニオンを定義
+// https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type
+// VS Codeの展開を防止するためにEvents型を定義
+type Events<T extends object> = { [K in keyof T]: { type: K; body: T[K]; } };
+type EventUnionFromDictionary<
+ T extends object,
+ U = Events<T>
+> = U[keyof U];
+
+// name/messages(spec) pairs dictionary
+export type StreamMessages = {
+ internal: {
+ name: 'internal';
+ payload: EventUnionFromDictionary<InternalStreamTypes>;
+ };
+ broadcast: {
+ name: 'broadcast';
+ payload: EventUnionFromDictionary<BroadcastTypes>;
+ };
+ user: {
+ name: `user:${User['id']}`;
+ payload: EventUnionFromDictionary<UserStreamTypes>;
+ };
+ main: {
+ name: `mainStream:${User['id']}`;
+ payload: EventUnionFromDictionary<MainStreamTypes>;
+ };
+ drive: {
+ name: `driveStream:${User['id']}`;
+ payload: EventUnionFromDictionary<DriveStreamTypes>;
+ };
+ note: {
+ name: `noteStream:${Note['id']}`;
+ payload: EventUnionFromDictionary<NoteStreamEventTypes>;
+ };
+ channel: {
+ name: `channelStream:${Channel['id']}`;
+ payload: EventUnionFromDictionary<ChannelStreamTypes>;
+ };
+ userList: {
+ name: `userListStream:${UserList['id']}`;
+ payload: EventUnionFromDictionary<UserListStreamTypes>;
+ };
+ antenna: {
+ name: `antennaStream:${Antenna['id']}`;
+ payload: EventUnionFromDictionary<AntennaStreamTypes>;
+ };
+ messaging: {
+ name: `messagingStream:${User['id']}-${User['id']}`;
+ payload: EventUnionFromDictionary<MessagingStreamTypes>;
+ };
+ groupMessaging: {
+ name: `messagingStream:${UserGroup['id']}`;
+ payload: EventUnionFromDictionary<GroupMessagingStreamTypes>;
+ };
+ messagingIndex: {
+ name: `messagingIndexStream:${User['id']}`;
+ payload: EventUnionFromDictionary<MessagingIndexStreamTypes>;
+ };
+ reversi: {
+ name: `reversiStream:${User['id']}`;
+ payload: EventUnionFromDictionary<ReversiStreamTypes>;
+ };
+ reversiGame: {
+ name: `reversiGameStream:${ReversiGame['id']}`;
+ payload: EventUnionFromDictionary<ReversiGameStreamTypes>;
+ };
+ admin: {
+ name: `adminStream:${User['id']}`;
+ payload: EventUnionFromDictionary<AdminStreamTypes>;
+ };
+ notes: {
+ name: 'notesStream';
+ payload: Packed<'Note'>;
+ };
+};
+
+// API event definitions
+// ストリームごとのEmitterの辞書を用意
+type EventEmitterDictionary = { [x in keyof StreamMessages]: Emitter<EventEmitter, { [y in StreamMessages[x]['name']]: (e: StreamMessages[x]['payload']) => void }> };
+// 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
+type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
+// Emitter辞書から共用体型を作り、UnionToIntersectionで交差型にする
+export type StreamEventEmitter = UnionToIntersection<EventEmitterDictionary[keyof StreamMessages]>;
+// { [y in name]: (e: spec) => void }をまとめてその交差型をEmitterにかけるとts(2590)にひっかかる
+
+// provide stream channels union
+export type StreamChannels = StreamMessages[keyof StreamMessages]['name'];
diff --git a/src/services/stream.ts b/src/services/stream.ts
index 4db1a77395..2c308a1b54 100644
--- a/src/services/stream.ts
+++ b/src/services/stream.ts
@@ -7,9 +7,28 @@ import { UserGroup } from '@/models/entities/user-group';
import config from '@/config/index';
import { Antenna } from '@/models/entities/antenna';
import { Channel } from '@/models/entities/channel';
+import {
+ StreamChannels,
+ AdminStreamTypes,
+ AntennaStreamTypes,
+ BroadcastTypes,
+ ChannelStreamTypes,
+ DriveStreamTypes,
+ GroupMessagingStreamTypes,
+ InternalStreamTypes,
+ MainStreamTypes,
+ MessagingIndexStreamTypes,
+ MessagingStreamTypes,
+ NoteStreamTypes,
+ ReversiGameStreamTypes,
+ ReversiStreamTypes,
+ UserListStreamTypes,
+ UserStreamTypes
+} from '@/server/api/stream/types';
+import { Packed } from '@/misc/schema';
class Publisher {
- private publish = (channel: string, type: string | null, value?: any): void => {
+ private publish = (channel: StreamChannels, type: string | null, value?: any): void => {
const message = type == null ? value : value == null ?
{ type: type, body: null } :
{ type: type, body: value };
@@ -20,70 +39,70 @@ class Publisher {
}));
}
- public publishInternalEvent = (type: string, value?: any): void => {
+ public publishInternalEvent = <K extends keyof InternalStreamTypes>(type: K, value?: InternalStreamTypes[K]): void => {
this.publish('internal', type, typeof value === 'undefined' ? null : value);
}
- public publishUserEvent = (userId: User['id'], type: string, value?: any): void => {
+ public publishUserEvent = <K extends keyof UserStreamTypes>(userId: User['id'], type: K, value?: UserStreamTypes[K]): void => {
this.publish(`user:${userId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishBroadcastStream = (type: string, value?: any): void => {
+ public publishBroadcastStream = <K extends keyof BroadcastTypes>(type: K, value?: BroadcastTypes[K]): void => {
this.publish('broadcast', type, typeof value === 'undefined' ? null : value);
}
- public publishMainStream = (userId: User['id'], type: string, value?: any): void => {
+ public publishMainStream = <K extends keyof MainStreamTypes>(userId: User['id'], type: K, value?: MainStreamTypes[K]): void => {
this.publish(`mainStream:${userId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishDriveStream = (userId: User['id'], type: string, value?: any): void => {
+ public publishDriveStream = <K extends keyof DriveStreamTypes>(userId: User['id'], type: K, value?: DriveStreamTypes[K]): void => {
this.publish(`driveStream:${userId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishNoteStream = (noteId: Note['id'], type: string, value: any): void => {
+ public publishNoteStream = <K extends keyof NoteStreamTypes>(noteId: Note['id'], type: K, value?: NoteStreamTypes[K]): void => {
this.publish(`noteStream:${noteId}`, type, {
id: noteId,
body: value
});
}
- public publishChannelStream = (channelId: Channel['id'], type: string, value?: any): void => {
+ public publishChannelStream = <K extends keyof ChannelStreamTypes>(channelId: Channel['id'], type: K, value?: ChannelStreamTypes[K]): void => {
this.publish(`channelStream:${channelId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishUserListStream = (listId: UserList['id'], type: string, value?: any): void => {
+ public publishUserListStream = <K extends keyof UserListStreamTypes>(listId: UserList['id'], type: K, value?: UserListStreamTypes[K]): void => {
this.publish(`userListStream:${listId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishAntennaStream = (antennaId: Antenna['id'], type: string, value?: any): void => {
+ public publishAntennaStream = <K extends keyof AntennaStreamTypes>(antennaId: Antenna['id'], type: K, value?: AntennaStreamTypes[K]): void => {
this.publish(`antennaStream:${antennaId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishMessagingStream = (userId: User['id'], otherpartyId: User['id'], type: string, value?: any): void => {
+ public publishMessagingStream = <K extends keyof MessagingStreamTypes>(userId: User['id'], otherpartyId: User['id'], type: K, value?: MessagingStreamTypes[K]): void => {
this.publish(`messagingStream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishGroupMessagingStream = (groupId: UserGroup['id'], type: string, value?: any): void => {
+ public publishGroupMessagingStream = <K extends keyof GroupMessagingStreamTypes>(groupId: UserGroup['id'], type: K, value?: GroupMessagingStreamTypes[K]): void => {
this.publish(`messagingStream:${groupId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishMessagingIndexStream = (userId: User['id'], type: string, value?: any): void => {
+ public publishMessagingIndexStream = <K extends keyof MessagingIndexStreamTypes>(userId: User['id'], type: K, value?: MessagingIndexStreamTypes[K]): void => {
this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishReversiStream = (userId: User['id'], type: string, value?: any): void => {
+ public publishReversiStream = <K extends keyof ReversiStreamTypes>(userId: User['id'], type: K, value?: ReversiStreamTypes[K]): void => {
this.publish(`reversiStream:${userId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishReversiGameStream = (gameId: ReversiGame['id'], type: string, value?: any): void => {
+ public publishReversiGameStream = <K extends keyof ReversiGameStreamTypes>(gameId: ReversiGame['id'], type: K, value?: ReversiGameStreamTypes[K]): void => {
this.publish(`reversiGameStream:${gameId}`, type, typeof value === 'undefined' ? null : value);
}
- public publishNotesStream = (note: any): void => {
+ public publishNotesStream = (note: Packed<'Note'>): void => {
this.publish('notesStream', null, note);
}
- public publishAdminStream = (userId: User['id'], type: string, value?: any): void => {
+ public publishAdminStream = <K extends keyof AdminStreamTypes>(userId: User['id'], type: K, value?: AdminStreamTypes[K]): void => {
this.publish(`adminStream:${userId}`, type, typeof value === 'undefined' ? null : value);
}
}
diff --git a/yarn.lock b/yarn.lock
index cd76b59af6..e2140e185a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10288,6 +10288,11 @@ streamsearch@0.1.2:
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
+strict-event-emitter-types@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz#05e15549cb4da1694478a53543e4e2f4abcf277f"
+ integrity sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==
+
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"