import Channel from '../channel.js'; import { Notes, Users } from '@/models/index.js'; import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; import { User } from '@/models/entities/user.js'; import { StreamMessages } from '../types.js'; import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'channel'; public static shouldShare = false; public static requireCredential = false; private channelId: string; private typers: Record = {}; private emitTypersIntervalId: ReturnType; constructor(id: string, connection: Channel['connection']) { super(id, connection); this.onNote = this.onNote.bind(this); } public async init(params: any) { this.channelId = params.channelId as string; // Subscribe stream this.subscriber.on('notesStream', this.onNote); this.subscriber.on(`channelStream:${this.channelId}`, this.onEvent); this.emitTypersIntervalId = setInterval(this.emitTypers, 5000); } private async onNote(note: Packed<'Note'>) { if (note.channelId !== this.channelId) return; // リプライなら再pack if (note.replyId != null) { note.reply = await Notes.pack(note.replyId, this.user, { detail: true, }); } // Renoteなら再pack if (note.renoteId != null) { note.renote = await Notes.pack(note.renoteId, this.user, { detail: true, }); } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isMutedUserRelated(note, this.muting)) return; // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する if (isBlockerUserRelated(note, this.blocking)) return; this.connection.cacheNote(note); this.send('note', note); } private onEvent(data: StreamMessages['channel']['payload']) { if (data.type === 'typing') { const id = data.body; const begin = this.typers[id] == null; this.typers[id] = new Date(); if (begin) { this.emitTypers(); } } } private async emitTypers() { const now = new Date(); // Remove not typing users for (const [userId, date] of Object.entries(this.typers)) { if (now.getTime() - date.getTime() > 5000) delete this.typers[userId]; } const users = await Users.packMany(Object.keys(this.typers), null, { detail: false }); this.send({ type: 'typers', body: users, }); } public dispose() { // Unsubscribe events this.subscriber.off('notesStream', this.onNote); this.subscriber.off(`channelStream:${this.channelId}`, this.onEvent); clearInterval(this.emitTypersIntervalId); } }