From be47a120d75996864b6bc8a2f393a3ed87aebbb2 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Tue, 7 Sep 2021 02:40:38 +0900
Subject: [PATCH] :v:

---
 src/server/api/stream/channels/messaging.ts |  6 ++++--
 src/server/api/stream/index.ts              |  8 ++++----
 src/server/api/stream/types.ts              | 20 +++++++++++---------
 3 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/src/server/api/stream/channels/messaging.ts b/src/server/api/stream/channels/messaging.ts
index 015b0a7650..a75181d6d7 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']['spec'] | StreamMessages['groupMessaging']['spec']) {
 		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 b2cecb4470..89d9889220 100644
--- a/src/server/api/stream/index.ts
+++ b/src/server/api/stream/index.ts
@@ -15,7 +15,7 @@ import { UserProfile } from '@/models/entities/user-profile';
 import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '@/services/stream';
 import { UserGroup } from '@/models/entities/user-group';
 import { PackedNote } from '@/models/repositories/note';
-import { StreamEventEmitter, UserStreams } from './types';
+import { StreamEventEmitter, StreamMessages } from './types';
 
 /**
  * Main stream connection
@@ -47,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', async ev => {
+			this.onBroadcastMessage(ev.type, ev.body);
 		});
 
 		if (this.user) {
@@ -65,7 +65,7 @@ export default class Connection {
 	}
 
 	@autobind
-	private onUserEvent(ev: UserStreams) { // { type, body }と展開すると型も展開されてしまう
+	private onUserEvent(ev: StreamMessages['user']['spec']) { // { type, body }と展開すると型も展開されてしまう
 		switch (ev.type) {
 			case 'follow':
 				this.following.add(ev.body.id);
diff --git a/src/server/api/stream/types.ts b/src/server/api/stream/types.ts
index b78b894977..eb80c2e913 100644
--- a/src/server/api/stream/types.ts
+++ b/src/server/api/stream/types.ts
@@ -29,7 +29,7 @@ import { Page } from '@/models/entities/page';
 // https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type
 type EventUnionFromDictionary<
 	T extends object,
-	U = { [K in keyof T]: { type: K; body: T[K]} }
+	U = { [K in keyof T]: { type: K; body: T[K]; } }
 > = U[keyof U];
 
 //#region Stream type-body definitions
@@ -225,7 +225,7 @@ export interface AdminStreamTypes {
 //#endregion
 
 //#region 名前とメッセージのペアを中間生成
-interface StreamMessages {
+export type StreamMessages = {
 	internal: {
 		name: 'internal';
 		spec: EventUnionFromDictionary<InternalStreamTypes>;
@@ -286,15 +286,17 @@ interface StreamMessages {
 		name: `adminStream:${User['id']}`;
 		spec: EventUnionFromDictionary<AdminStreamTypes>;
 	};
-	// and notesStream (specにPackedNoteを突っ込むとなぜかバグる)
-}
+	notes: {
+		name: 'notesStream';
+		spec: PackedNote;
+	};
+};
 //#endregion
 
 // API event definitions
-type EventsGenerater<K extends keyof StreamMessages> = { [key in StreamMessages[K]['name']]: (e: StreamMessages[K]['spec']) => void };
-type NotesStreamEvent = { notesStream: (e: PackedNote) => void };
-export type StreamEventEmitter = Emitter<EventEmitter, EventsGenerater<keyof StreamMessages> & NotesStreamEvent>;
+type EventsDictionary = { [x in keyof StreamMessages]: { [y in StreamMessages[x]['name']]: (e: StreamMessages[x]['spec']) => void } };
+type Events<D> = (D extends any ? (k: D) => void : never) extends ((k: infer E) => void) ? E : never;
+export type StreamEventEmitter = Emitter<EventEmitter, Events<EventsDictionary[keyof StreamMessages]>>;
 
 // provide stream channels union
-type ChannelsUnionGenerater<K extends keyof StreamMessages> = StreamMessages[K]['name'];
-export type StreamChannels = ChannelsUnionGenerater<keyof StreamMessages> | 'notesStream';
+export type StreamChannels = StreamMessages[keyof StreamMessages]['name'] | 'notesStream';