import Channel from "../channel.js"; import { Users } from "../../../../models/index.js"; import { isUserRelated } from "../../../../misc/is-user-related.js"; export default class extends Channel { chName = "channel"; static shouldShare = false; static requireCredential = false; channelId; typers = new Map(); emitTypersIntervalId; constructor(id, connection){ super(id, connection); this.onNote = this.withPackedNote(this.onNote.bind(this)); this.emitTypers = this.emitTypers.bind(this); } async init(params) { this.channelId = params.channelId; // Subscribe stream this.subscriber.on("notesStream", this.onNote); this.subscriber.on(`channelStream:${this.channelId}`, this.onEvent); this.emitTypersIntervalId = setInterval(this.emitTypers, 5000); } async onNote(note) { if (note.visibility === "hidden") return; if (note.channelId !== this.channelId) return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.muting)) return; // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する if (isUserRelated(note, this.blocking)) return; if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return; this.connection.cacheNote(note); this.send("note", note); } onEvent(data) { if (data.type === "typing") { const id = data.body; const begin = !this.typers.has(id); this.typers.set(id, new Date()); if (begin) { this.emitTypers(); } } } 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) this.typers.delete(userId); } const userIds = Array.from(this.typers.keys()); const users = await Users.packMany(userIds, null, { detail: false }); this.send({ type: "typers", body: users }); } dispose() { // Unsubscribe events this.subscriber.off("notesStream", this.onNote); this.subscriber.off(`channelStream:${this.channelId}`, this.onEvent); clearInterval(this.emitTypersIntervalId); } }