This commit is contained in:
tamaina 2021-09-06 22:12:07 +09:00
parent 3500705585
commit f4652ec4ac
8 changed files with 158 additions and 17 deletions

View File

@ -1,6 +1,8 @@
import { EntityRepository, Repository } from 'typeorm'; import { EntityRepository, Repository } from 'typeorm';
import { Emoji } from '@/models/entities/emoji'; import { Emoji } from '@/models/entities/emoji';
export type PackedEmoji = FIXME;
@EntityRepository(Emoji) @EntityRepository(Emoji)
export class EmojiRepository extends Repository<Emoji> { export class EmojiRepository extends Repository<Emoji> {
public async pack( public async pack(

View File

@ -3,6 +3,8 @@ import { EntityRepository, Repository } from 'typeorm';
import { Users } from '../../../index'; import { Users } from '../../../index';
import { ReversiGame } from '@/models/entities/games/reversi/game'; import { ReversiGame } from '@/models/entities/games/reversi/game';
export type PackedReversiGame = FIXME;
@EntityRepository(ReversiGame) @EntityRepository(ReversiGame)
export class ReversiGameRepository extends Repository<ReversiGame> { export class ReversiGameRepository extends Repository<ReversiGame> {
public async pack( public async pack(

View File

@ -4,6 +4,8 @@ import { Users } from '../../../index';
import { awaitAll } from '@/prelude/await-all'; import { awaitAll } from '@/prelude/await-all';
import { User } from '@/models/entities/user'; import { User } from '@/models/entities/user';
export type PackedReversiMatching = FIXME;
@EntityRepository(ReversiMatching) @EntityRepository(ReversiMatching)
export class ReversiMatchingRepository extends Repository<ReversiMatching> { export class ReversiMatchingRepository extends Repository<ReversiMatching> {
public async pack( public async pack(

View File

@ -77,7 +77,7 @@ export async function readGroupMessagingMessage(
id: In(messageIds) id: In(messageIds)
}); });
const reads = []; const reads: MessagingMessage['id'][] = [];
for (const message of messages) { for (const message of messages) {
if (message.userId === userId) continue; if (message.userId === userId) continue;

View File

@ -137,7 +137,7 @@ export default define(meta, async (ps, user) => {
notify: ps.notify, notify: ps.notify,
}); });
publishInternalEvent('antennaUpdated', Antennas.findOneOrFail(antenna.id)); publishInternalEvent('antennaUpdated', await Antennas.findOneOrFail(antenna.id));
return await Antennas.pack(antenna.id); return await Antennas.pack(antenna.id);
}); });

View File

@ -19,7 +19,7 @@ export default class extends Channel {
this.channelId = params.channelId as string; this.channelId = params.channelId as string;
// Subscribe stream // Subscribe stream
this.subscriber.on('notesStream', this.onNote); this.subscriber.on('notesStream', e => this.onNote(e));
this.subscriber.on(`channelStream:${this.channelId}`, this.onEvent); this.subscriber.on(`channelStream:${this.channelId}`, this.onEvent);
this.emitTypersIntervalId = setInterval(this.emitTypers, 5000); this.emitTypersIntervalId = setInterval(this.emitTypers, 5000);
} }

View File

@ -1,7 +1,6 @@
import { User } from '@/models/entities/user'; import { User } from '@/models/entities/user';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import Emitter from 'strict-event-emitter-types'; import Emitter from 'strict-event-emitter-types';
import StreamTypes from 'misskey-js/built/streaming.types';
import { Channel } from '@/models/entities/channel'; import { Channel } from '@/models/entities/channel';
import { UserProfile } from '@/models/entities/user-profile'; import { UserProfile } from '@/models/entities/user-profile';
import { PackedUser } from '@/models/repositories/user'; import { PackedUser } from '@/models/repositories/user';
@ -14,6 +13,16 @@ import { PackedDriveFolder } from '@/models/repositories/drive-folder';
import { DriveFolder } from '@/models/entities/drive-folder'; import { DriveFolder } from '@/models/entities/drive-folder';
import { Note } from '@/models/entities/note'; import { Note } from '@/models/entities/note';
import { Emoji } from '@/models/entities/emoji'; import { Emoji } from '@/models/entities/emoji';
import { UserList } from '@/models/entities/user-list';
import { MessagingMessage } from '@/models/entities/messaging-message';
import { PackedMessagingMessage } from '@/models/repositories/messaging-message';
import { UserGroup } from '@/models/entities/user-group';
import { PackedReversiGame } from '@/models/repositories/games/reversi/game';
import { PackedReversiMatching } from '@/models/repositories/games/reversi/matching';
import { ReversiGame } from '@/models/entities/games/reversi/game';
import { AbuseUserReport } from '@/models/entities/abuse-user-report';
import { PackedEmoji } from '@/models/repositories/emoji';
import StreamTypes from 'misskey-js/built/streaming.types';
// 辞書(interface or type)から{ type, body }ユニオンを定義 // 辞書(interface or type)から{ type, body }ユニオンを定義
// https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type // https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type
@ -25,12 +34,6 @@ type EventUnionFromDictionary<
// (payload: P) => void からPを取り出す // (payload: P) => void からPを取り出す
type Payload<T extends (payload: any) => void> = T extends (payload: infer P) => void ? P : never; type Payload<T extends (payload: any) => void> = T extends (payload: infer P) => void ? P : never;
// misskey.jsのstreaming.typesの辞書から{ type, body }ユニオンを定義
type EventUnionFromMkJSTypes<
T extends { [key: string]: ((payload: any) => void) | (() => void) },
U = { [K in keyof T]: { type: K; body: Payload<T[K]>} }
> = U[keyof U];
//#region Stream type-body definitions //#region Stream type-body definitions
export interface InternalStreamTypes { export interface InternalStreamTypes {
antennaCreated: Antenna; antennaCreated: Antenna;
@ -38,6 +41,10 @@ export interface InternalStreamTypes {
antennaUpdated: Antenna; antennaUpdated: Antenna;
} }
export interface BroadcastTypes {
emojiAdded: PackedEmoji;
};
export interface UserStreamTypes { export interface UserStreamTypes {
terminate: {}; terminate: {};
followChannel: Channel; followChannel: Channel;
@ -75,6 +82,7 @@ export interface MainStreamTypes {
readAllChannels: never; readAllChannels: never;
unreadChannel: never; unreadChannel: never;
myTokenRegenerated: never; myTokenRegenerated: never;
reversiInvited: PackedReversiMatching;
} }
export interface DriveStreamTypes { export interface DriveStreamTypes {
@ -117,7 +125,92 @@ export interface NoteStreamTypes {
}; };
} }
export interface ChannelStreamTypes {
typing: User['id'];
}
export interface UserListStreamTypes {
userAdded: PackedUser;
userRemoved: PackedUser;
}
export interface AntennaStreamTypes {
note: Note;
}
export interface MessagingStreamTypes {
read: MessagingMessage['id'][];
typing: User['id'];
message: PackedMessagingMessage;
deleted: MessagingMessage['id'];
}
export interface GroupMessagingStreamTypes {
read: {
ids: MessagingMessage['id'][];
userId: User['id'];
};
typing: User['id'];
message: PackedMessagingMessage;
deleted: MessagingMessage['id'];
}
export interface MessagingIndexStreamTypes {
read: MessagingMessage['id'][];
message: PackedMessagingMessage;
}
export interface ReversiStreamTypes {
matched: PackedReversiGame;
invited: PackedReversiMatching;
}
export interface ReversiGameStreamTypes {
started: PackedReversiGame;
ended: {
winnerId: User['id'],
game: PackedReversiGame;
};
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 //#endregion
//#region 名前とメッセージのペアを中間生成 //#region 名前とメッセージのペアを中間生成
interface StreamMessages { interface StreamMessages {
internal: { internal: {
@ -126,7 +219,7 @@ interface StreamMessages {
}; };
broadcast: { broadcast: {
name: 'broadcast'; name: 'broadcast';
spec: EventUnionFromMkJSTypes<StreamTypes.BroadcasrEvents>; spec: EventUnionFromDictionary<BroadcastTypes>;
}; };
user: { user: {
name: `user:${User['id']}`; name: `user:${User['id']}`;
@ -143,11 +236,52 @@ interface StreamMessages {
note: { note: {
name: `noteStream:${Note['id']}`; name: `noteStream:${Note['id']}`;
spec: EventUnionFromDictionary<NoteStreamTypes>; spec: EventUnionFromDictionary<NoteStreamTypes>;
};
channel: {
name: `channelStream:${Channel['id']}`;
spec: EventUnionFromDictionary<ChannelStreamTypes>;
};
userList: {
name: `userListStream:${UserList['id']}`;
spec: EventUnionFromDictionary<UserListStreamTypes>;
};
antenna: {
name: `antennaStream:${Antenna['id']}`;
spec: EventUnionFromDictionary<AntennaStreamTypes>;
};
messaging: {
name: `messagingStream:${User['id']}-${User['id']}`;
spec: EventUnionFromDictionary<MessagingStreamTypes>;
};
groupMessaging: {
name: `messagingStream:${UserGroup['id']}`;
spec: EventUnionFromDictionary<GroupMessagingStreamTypes>;
};
messagingIndex: {
name: `messagingIndexStream:${User['id']}`;
spec: EventUnionFromDictionary<MessagingIndexStreamTypes>;
};
reversi: {
name: `reversiStream:${User['id']}`;
spec: EventUnionFromDictionary<ReversiStreamTypes>;
};
reversiGame: {
name: `reversiGameStream:${ReversiGame['id']}`;
spec: EventUnionFromDictionary<ReversiGameStreamTypes>;
};
admin: {
name: `adminStream:${User['id']}`;
spec: EventUnionFromDictionary<AdminStreamTypes>;
} }
// and notesStream (specにPackedNoteを突っ込むとなぜかバグる)
} }
//#endregion //#endregion
// API event definitions // API event definitions
type EventsGenerater<K extends keyof StreamMessages> = { [key in StreamMessages[K]['name']]: (e: StreamMessages[K]['spec']) => void }; type EventsGenerater<K extends keyof StreamMessages> = { [key in StreamMessages[K]['name']]: (e: StreamMessages[K]['spec']) => void };
export type StreamEventEmitter = Emitter<EventEmitter, EventsGenerater<keyof StreamMessages>>; type NotesStreamEvent = { notesStream: (e: PackedNote) => void };
export type StreamEventEmitter = Emitter<EventEmitter, EventsGenerater<keyof StreamMessages> & NotesStreamEvent>;
// Channel Union
type ChannelsUnionGenerater<K extends keyof StreamMessages> = StreamMessages[K]['name'];
export type Channels = ChannelsUnionGenerater<keyof StreamMessages> | 'notesStream';

View File

@ -7,9 +7,10 @@ import { UserGroup } from '@/models/entities/user-group';
import config from '@/config/index'; import config from '@/config/index';
import { Antenna } from '@/models/entities/antenna'; import { Antenna } from '@/models/entities/antenna';
import { Channel } from '@/models/entities/channel'; import { Channel } from '@/models/entities/channel';
import { BroadcastTypes, Channels, InternalStreamTypes, UserStreamTypes } from '@/server/api/stream/types';
class Publisher { class Publisher {
private publish = (channel: string, type: string | null, value?: any): void => { private publish = (channel: Channels, type: string | null, value?: any): void => {
const message = type == null ? value : value == null ? const message = type == null ? value : value == null ?
{ type: type, body: null } : { type: type, body: null } :
{ type: type, body: value }; { type: type, body: value };
@ -20,15 +21,15 @@ 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); 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); 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); this.publish('broadcast', type, typeof value === 'undefined' ? null : value);
} }