diff options
Diffstat (limited to 'src/server/api/stream/channels')
| -rw-r--r-- | src/server/api/stream/channels/admin.ts | 2 | ||||
| -rw-r--r-- | src/server/api/stream/channels/drive.ts | 2 | ||||
| -rw-r--r-- | src/server/api/stream/channels/games/reversi-game.ts | 168 | ||||
| -rw-r--r-- | src/server/api/stream/channels/games/reversi.ts | 13 | ||||
| -rw-r--r-- | src/server/api/stream/channels/global-timeline.ts | 18 | ||||
| -rw-r--r-- | src/server/api/stream/channels/hashtag.ts | 48 | ||||
| -rw-r--r-- | src/server/api/stream/channels/home-timeline.ts | 45 | ||||
| -rw-r--r-- | src/server/api/stream/channels/hybrid-timeline.ts | 55 | ||||
| -rw-r--r-- | src/server/api/stream/channels/index.ts | 4 | ||||
| -rw-r--r-- | src/server/api/stream/channels/local-timeline.ts | 45 | ||||
| -rw-r--r-- | src/server/api/stream/channels/main.ts | 9 | ||||
| -rw-r--r-- | src/server/api/stream/channels/messaging-index.ts | 2 | ||||
| -rw-r--r-- | src/server/api/stream/channels/messaging.ts | 4 | ||||
| -rw-r--r-- | src/server/api/stream/channels/social-timeline.ts | 64 | ||||
| -rw-r--r-- | src/server/api/stream/channels/user-list.ts | 72 |
15 files changed, 310 insertions, 241 deletions
diff --git a/src/server/api/stream/channels/admin.ts b/src/server/api/stream/channels/admin.ts index 6bcd1a7e0b..e2eba10f78 100644 --- a/src/server/api/stream/channels/admin.ts +++ b/src/server/api/stream/channels/admin.ts @@ -9,7 +9,7 @@ export default class extends Channel { @autobind public async init(params: any) { // Subscribe admin stream - this.subscriber.on(`adminStream:${this.user._id}`, data => { + this.subscriber.on(`adminStream:${this.user.id}`, data => { this.send(data); }); } diff --git a/src/server/api/stream/channels/drive.ts b/src/server/api/stream/channels/drive.ts index 391c4b5c32..671aad4366 100644 --- a/src/server/api/stream/channels/drive.ts +++ b/src/server/api/stream/channels/drive.ts @@ -9,7 +9,7 @@ export default class extends Channel { @autobind public async init(params: any) { // Subscribe drive stream - this.subscriber.on(`driveStream:${this.user._id}`, data => { + this.subscriber.on(`driveStream:${this.user.id}`, data => { this.send(data); }); } diff --git a/src/server/api/stream/channels/games/reversi-game.ts b/src/server/api/stream/channels/games/reversi-game.ts index 87df9e194c..158f108c4e 100644 --- a/src/server/api/stream/channels/games/reversi-game.ts +++ b/src/server/api/stream/channels/games/reversi-game.ts @@ -1,22 +1,22 @@ import autobind from 'autobind-decorator'; import * as CRC32 from 'crc-32'; -import * as mongo from 'mongodb'; -import ReversiGame, { pack } from '../../../../../models/games/reversi/game'; import { publishReversiGameStream } from '../../../../../services/stream'; import Reversi from '../../../../../games/reversi/core'; import * as maps from '../../../../../games/reversi/maps'; import Channel from '../../channel'; +import { ReversiGame } from '../../../../../models/entities/games/reversi/game'; +import { ReversiGames } from '../../../../../models'; export default class extends Channel { public readonly chName = 'gamesReversiGame'; public static shouldShare = false; public static requireCredential = false; - private gameId: mongo.ObjectID; + private gameId: ReversiGame['id']; @autobind public async init(params: any) { - this.gameId = new mongo.ObjectID(params.gameId as string); + this.gameId = params.gameId; // Subscribe game stream this.subscriber.on(`reversiGameStream:${this.gameId}`, data => { @@ -29,7 +29,7 @@ export default class extends Channel { switch (type) { case 'accept': this.accept(true); break; case 'cancelAccept': this.accept(false); break; - case 'updateSettings': this.updateSettings(body.settings); break; + case 'updateSettings': this.updateSettings(body.key, body.value); break; case 'initForm': this.initForm(body); break; case 'updateForm': this.updateForm(body.id, body.value); break; case 'message': this.message(body); break; @@ -39,54 +39,55 @@ export default class extends Channel { } @autobind - private async updateSettings(settings: any) { - const game = await ReversiGame.findOne({ _id: this.gameId }); + private async updateSettings(key: string, value: any) { + const game = await ReversiGames.findOne(this.gameId); if (game.isStarted) return; - if (!game.user1Id.equals(this.user._id) && !game.user2Id.equals(this.user._id)) return; - if (game.user1Id.equals(this.user._id) && game.user1Accepted) return; - if (game.user2Id.equals(this.user._id) && game.user2Accepted) return; + if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; + if ((game.user1Id === this.user.id) && game.user1Accepted) return; + if ((game.user2Id === this.user.id) && game.user2Accepted) return; - await ReversiGame.update({ _id: this.gameId }, { - $set: { - settings - } + if (!['map', 'bw', 'isLlotheo', 'canPutEverywhere', 'loopedBoard'].includes(key)) return; + + await ReversiGames.update({ id: this.gameId }, { + [key]: value }); - publishReversiGameStream(this.gameId, 'updateSettings', settings); + publishReversiGameStream(this.gameId, 'updateSettings', { + key: key, + value: value + }); } @autobind private async initForm(form: any) { - const game = await ReversiGame.findOne({ _id: this.gameId }); + const game = await ReversiGames.findOne(this.gameId); if (game.isStarted) return; - if (!game.user1Id.equals(this.user._id) && !game.user2Id.equals(this.user._id)) return; + if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; - const set = game.user1Id.equals(this.user._id) ? { + const set = game.user1Id === this.user.id ? { form1: form } : { - form2: form - }; + form2: form + }; - await ReversiGame.update({ _id: this.gameId }, { - $set: set - }); + await ReversiGames.update({ id: this.gameId }, set); publishReversiGameStream(this.gameId, 'initForm', { - userId: this.user._id, + userId: this.user.id, form }); } @autobind private async updateForm(id: string, value: any) { - const game = await ReversiGame.findOne({ _id: this.gameId }); + const game = await ReversiGames.findOne({ id: this.gameId }); if (game.isStarted) return; - if (!game.user1Id.equals(this.user._id) && !game.user2Id.equals(this.user._id)) return; + if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; - const form = game.user1Id.equals(this.user._id) ? game.form2 : game.form1; + const form = game.user1Id === this.user.id ? game.form2 : game.form1; const item = form.find((i: any) => i.id == id); @@ -94,18 +95,16 @@ export default class extends Channel { item.value = value; - const set = game.user1Id.equals(this.user._id) ? { + const set = game.user1Id === this.user.id ? { form2: form } : { form1: form }; - await ReversiGame.update({ _id: this.gameId }, { - $set: set - }); + await ReversiGames.update({ id: this.gameId }, set); publishReversiGameStream(this.gameId, 'updateForm', { - userId: this.user._id, + userId: this.user.id, id, value }); @@ -115,24 +114,22 @@ export default class extends Channel { private async message(message: any) { message.id = Math.random(); publishReversiGameStream(this.gameId, 'message', { - userId: this.user._id, + userId: this.user.id, message }); } @autobind private async accept(accept: boolean) { - const game = await ReversiGame.findOne({ _id: this.gameId }); + const game = await ReversiGames.findOne(this.gameId); if (game.isStarted) return; let bothAccepted = false; - if (game.user1Id.equals(this.user._id)) { - await ReversiGame.update({ _id: this.gameId }, { - $set: { - user1Accepted: accept - } + if (game.user1Id === this.user.id) { + await ReversiGames.update({ id: this.gameId }, { + user1Accepted: accept }); publishReversiGameStream(this.gameId, 'changeAccepts', { @@ -141,11 +138,9 @@ export default class extends Channel { }); if (accept && game.user2Accepted) bothAccepted = true; - } else if (game.user2Id.equals(this.user._id)) { - await ReversiGame.update({ _id: this.gameId }, { - $set: { - user2Accepted: accept - } + } else if (game.user2Id === this.user.id) { + await ReversiGames.update({ id: this.gameId }, { + user2Accepted: accept }); publishReversiGameStream(this.gameId, 'changeAccepts', { @@ -161,15 +156,15 @@ export default class extends Channel { if (bothAccepted) { // 3秒後、まだacceptされていたらゲーム開始 setTimeout(async () => { - const freshGame = await ReversiGame.findOne({ _id: this.gameId }); + const freshGame = await ReversiGames.findOne(this.gameId); if (freshGame == null || freshGame.isStarted || freshGame.isEnded) return; if (!freshGame.user1Accepted || !freshGame.user2Accepted) return; let bw: number; - if (freshGame.settings.bw == 'random') { + if (freshGame.bw == 'random') { bw = Math.random() > 0.5 ? 1 : 2; } else { - bw = freshGame.settings.bw as number; + bw = parseInt(freshGame.bw, 10); } function getRandomMap() { @@ -178,22 +173,20 @@ export default class extends Channel { return Object.values(maps)[rnd].data; } - const map = freshGame.settings.map != null ? freshGame.settings.map : getRandomMap(); + const map = freshGame.map != null ? freshGame.map : getRandomMap(); - await ReversiGame.update({ _id: this.gameId }, { - $set: { - startedAt: new Date(), - isStarted: true, - black: bw, - 'settings.map': map - } + await ReversiGames.update({ id: this.gameId }, { + startedAt: new Date(), + isStarted: true, + black: bw, + map: map }); //#region 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理 const o = new Reversi(map, { - isLlotheo: freshGame.settings.isLlotheo, - canPutEverywhere: freshGame.settings.canPutEverywhere, - loopedBoard: freshGame.settings.loopedBoard + isLlotheo: freshGame.isLlotheo, + canPutEverywhere: freshGame.canPutEverywhere, + loopedBoard: freshGame.loopedBoard }); if (o.isEnded) { @@ -206,23 +199,22 @@ export default class extends Channel { winner = null; } - await ReversiGame.update({ - _id: this.gameId + await ReversiGames.update({ + id: this.gameId }, { - $set: { - isEnded: true, - winnerId: winner - } - }); + isEnded: true, + winnerId: winner + }); publishReversiGameStream(this.gameId, 'ended', { winnerId: winner, - game: await pack(this.gameId, this.user) + game: await ReversiGames.pack(this.gameId, this.user) }); } //#endregion - publishReversiGameStream(this.gameId, 'started', await pack(this.gameId, this.user)); + publishReversiGameStream(this.gameId, 'started', + await ReversiGames.pack(this.gameId, this.user)); }, 3000); } } @@ -230,16 +222,16 @@ export default class extends Channel { // 石を打つ @autobind private async set(pos: number) { - const game = await ReversiGame.findOne({ _id: this.gameId }); + const game = await ReversiGames.findOne(this.gameId); if (!game.isStarted) return; if (game.isEnded) return; - if (!game.user1Id.equals(this.user._id) && !game.user2Id.equals(this.user._id)) return; + if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; - const o = new Reversi(game.settings.map, { - isLlotheo: game.settings.isLlotheo, - canPutEverywhere: game.settings.canPutEverywhere, - loopedBoard: game.settings.loopedBoard + const o = new Reversi(game.map, { + isLlotheo: game.isLlotheo, + canPutEverywhere: game.canPutEverywhere, + loopedBoard: game.loopedBoard }); for (const log of game.logs) { @@ -247,7 +239,7 @@ export default class extends Channel { } const myColor = - (game.user1Id.equals(this.user._id) && game.black == 1) || (game.user2Id.equals(this.user._id) && game.black == 2) + ((game.user1Id === this.user.id) && game.black == 1) || ((game.user2Id === this.user.id) && game.black == 2) ? true : false; @@ -271,20 +263,18 @@ export default class extends Channel { pos }; - const crc32 = CRC32.str(game.logs.map(x => x.pos.toString()).join('') + pos.toString()); + const crc32 = CRC32.str(game.logs.map(x => x.pos.toString()).join('') + pos.toString()).toString(); - await ReversiGame.update({ - _id: this.gameId + game.logs.push(log); + + await ReversiGames.update({ + id: this.gameId }, { - $set: { - crc32, - isEnded: o.isEnded, - winnerId: winner - }, - $push: { - logs: log - } - }); + crc32, + isEnded: o.isEnded, + winnerId: winner, + logs: game.logs + }); publishReversiGameStream(this.gameId, 'set', Object.assign(log, { next: o.turn @@ -293,14 +283,14 @@ export default class extends Channel { if (o.isEnded) { publishReversiGameStream(this.gameId, 'ended', { winnerId: winner, - game: await pack(this.gameId, this.user) + game: await ReversiGames.pack(this.gameId, this.user) }); } } @autobind private async check(crc32: string) { - const game = await ReversiGame.findOne({ _id: this.gameId }); + const game = await ReversiGames.findOne(this.gameId); if (!game.isStarted) return; @@ -308,7 +298,7 @@ export default class extends Channel { if (game.crc32 == null) return; if (crc32 !== game.crc32) { - this.send('rescue', await pack(game, this.user)); + this.send('rescue', await ReversiGames.pack(game, this.user)); } } } diff --git a/src/server/api/stream/channels/games/reversi.ts b/src/server/api/stream/channels/games/reversi.ts index 1b1ad187a3..0498e5e017 100644 --- a/src/server/api/stream/channels/games/reversi.ts +++ b/src/server/api/stream/channels/games/reversi.ts @@ -1,8 +1,7 @@ import autobind from 'autobind-decorator'; -import * as mongo from 'mongodb'; -import Matching, { pack } from '../../../../../models/games/reversi/matching'; import { publishMainStream } from '../../../../../services/stream'; import Channel from '../../channel'; +import { ReversiMatchings } from '../../../../../models'; export default class extends Channel { public readonly chName = 'gamesReversi'; @@ -12,7 +11,7 @@ export default class extends Channel { @autobind public async init(params: any) { // Subscribe reversi stream - this.subscriber.on(`reversiStream:${this.user._id}`, data => { + this.subscriber.on(`reversiStream:${this.user.id}`, data => { this.send(data); }); } @@ -22,12 +21,12 @@ export default class extends Channel { switch (type) { case 'ping': if (body.id == null) return; - const matching = await Matching.findOne({ - parentId: this.user._id, - childId: new mongo.ObjectID(body.id) + const matching = await ReversiMatchings.findOne({ + parentId: this.user.id, + childId: body.id }); if (matching == null) return; - publishMainStream(matching.childId, 'reversiInvited', await pack(matching, matching.childId)); + publishMainStream(matching.childId, 'reversiInvited', await ReversiMatchings.pack(matching, matching.childId)); break; } } diff --git a/src/server/api/stream/channels/global-timeline.ts b/src/server/api/stream/channels/global-timeline.ts index b3689d47f5..bfb7697ba7 100644 --- a/src/server/api/stream/channels/global-timeline.ts +++ b/src/server/api/stream/channels/global-timeline.ts @@ -1,17 +1,14 @@ import autobind from 'autobind-decorator'; -import Mute from '../../../../models/mute'; -import { pack } from '../../../../models/note'; import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; import Channel from '../channel'; import fetchMeta from '../../../../misc/fetch-meta'; +import { Notes } from '../../../../models'; export default class extends Channel { public readonly chName = 'globalTimeline'; public static shouldShare = true; public static requireCredential = false; - private mutedUserIds: string[] = []; - @autobind public async init(params: any) { const meta = await fetchMeta(); @@ -20,29 +17,26 @@ export default class extends Channel { } // Subscribe events - this.subscriber.on('globalTimeline', this.onNote); - - const mute = await Mute.find({ muterId: this.user._id }); - this.mutedUserIds = mute.map(m => m.muteeId.toString()); + this.subscriber.on('notesStream', this.onNote); } @autobind private async onNote(note: any) { // リプライなら再pack if (note.replyId != null) { - note.reply = await pack(note.replyId, this.user, { + note.reply = await Notes.pack(note.replyId, this.user, { detail: true }); } // Renoteなら再pack if (note.renoteId != null) { - note.renote = await pack(note.renoteId, this.user, { + note.renote = await Notes.pack(note.renoteId, this.user, { detail: true }); } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する - if (shouldMuteThisNote(note, this.mutedUserIds)) return; + if (shouldMuteThisNote(note, this.muting)) return; this.send('note', note); } @@ -50,6 +44,6 @@ export default class extends Channel { @autobind public dispose() { // Unsubscribe events - this.subscriber.off('globalTimeline', this.onNote); + this.subscriber.off('notesStream', this.onNote); } } diff --git a/src/server/api/stream/channels/hashtag.ts b/src/server/api/stream/channels/hashtag.ts index 586ce02f06..36c56c7ab6 100644 --- a/src/server/api/stream/channels/hashtag.ts +++ b/src/server/api/stream/channels/hashtag.ts @@ -1,40 +1,46 @@ import autobind from 'autobind-decorator'; -import Mute from '../../../../models/mute'; -import { pack } from '../../../../models/note'; import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; import Channel from '../channel'; +import { Notes } from '../../../../models'; export default class extends Channel { public readonly chName = 'hashtag'; public static shouldShare = false; public static requireCredential = false; + private q: string[][]; @autobind public async init(params: any) { - const mute = this.user ? await Mute.find({ muterId: this.user._id }) : null; - const mutedUserIds = mute ? mute.map(m => m.muteeId.toString()) : []; + this.q = params.q; - const q: string[][] = params.q; - - if (q == null) return; + if (this.q == null) return; // Subscribe stream - this.subscriber.on('hashtag', async note => { - const noteTags = note.tags.map((t: string) => t.toLowerCase()); - const matched = q.some(tags => tags.every(tag => noteTags.includes(tag.toLowerCase()))); - if (!matched) return; + this.subscriber.on('notesStream', this.onNote); + } + + @autobind + private async onNote(note: any) { + const noteTags = note.tags.map((t: string) => t.toLowerCase()); + const matched = this.q.some(tags => tags.every(tag => noteTags.includes(tag.toLowerCase()))); + if (!matched) return; - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await pack(note.renoteId, this.user, { - detail: true - }); - } + // Renoteなら再pack + if (note.renoteId != null) { + note.renote = await Notes.pack(note.renoteId, this.user, { + detail: true + }); + } - // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する - if (shouldMuteThisNote(note, mutedUserIds)) return; + // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する + if (shouldMuteThisNote(note, this.muting)) return; - this.send('note', note); - }); + this.send('note', note); + } + + @autobind + public dispose() { + // Unsubscribe events + this.subscriber.off('notesStream', this.onNote); } } diff --git a/src/server/api/stream/channels/home-timeline.ts b/src/server/api/stream/channels/home-timeline.ts index 3c0b238720..2cece0947f 100644 --- a/src/server/api/stream/channels/home-timeline.ts +++ b/src/server/api/stream/channels/home-timeline.ts @@ -1,42 +1,49 @@ import autobind from 'autobind-decorator'; -import Mute from '../../../../models/mute'; -import { pack } from '../../../../models/note'; import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; import Channel from '../channel'; +import { Notes } from '../../../../models'; export default class extends Channel { public readonly chName = 'homeTimeline'; public static shouldShare = true; public static requireCredential = true; - private mutedUserIds: string[] = []; - @autobind public async init(params: any) { // Subscribe events - this.subscriber.on(`homeTimeline:${this.user._id}`, this.onNote); - - const mute = await Mute.find({ muterId: this.user._id }); - this.mutedUserIds = mute.map(m => m.muteeId.toString()); + this.subscriber.on('notesStream', this.onNote); } @autobind private async onNote(note: any) { - // リプライなら再pack - if (note.replyId != null) { - note.reply = await pack(note.replyId, this.user, { - detail: true - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await pack(note.renoteId, this.user, { + // その投稿のユーザーをフォローしていなかったら弾く + if (this.user.id !== note.userId && !this.following.includes(note.userId)) return; + + if (['followers', 'specified'].includes(note.visibility)) { + note = await Notes.pack(note.id, this.user, { detail: true }); + + if (note.isHidden) { + return; + } + } else { + // リプライなら再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 (shouldMuteThisNote(note, this.mutedUserIds)) return; + if (shouldMuteThisNote(note, this.muting)) return; this.send('note', note); } @@ -44,6 +51,6 @@ export default class extends Channel { @autobind public dispose() { // Unsubscribe events - this.subscriber.off(`homeTimeline:${this.user._id}`, this.onNote); + this.subscriber.off('notesStream', this.onNote); } } diff --git a/src/server/api/stream/channels/hybrid-timeline.ts b/src/server/api/stream/channels/hybrid-timeline.ts deleted file mode 100644 index 35ef17b56b..0000000000 --- a/src/server/api/stream/channels/hybrid-timeline.ts +++ /dev/null @@ -1,55 +0,0 @@ -import autobind from 'autobind-decorator'; -import Mute from '../../../../models/mute'; -import { pack } from '../../../../models/note'; -import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; -import Channel from '../channel'; -import fetchMeta from '../../../../misc/fetch-meta'; - -export default class extends Channel { - public readonly chName = 'hybridTimeline'; - public static shouldShare = true; - public static requireCredential = true; - - private mutedUserIds: string[] = []; - - @autobind - public async init(params: any) { - const meta = await fetchMeta(); - if (meta.disableLocalTimeline && !this.user.isAdmin && !this.user.isModerator) return; - - // Subscribe events - this.subscriber.on('hybridTimeline', this.onNewNote); - this.subscriber.on(`hybridTimeline:${this.user._id}`, this.onNewNote); - - const mute = await Mute.find({ muterId: this.user._id }); - this.mutedUserIds = mute.map(m => m.muteeId.toString()); - } - - @autobind - private async onNewNote(note: any) { - // リプライなら再pack - if (note.replyId != null) { - note.reply = await pack(note.replyId, this.user, { - detail: true - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await pack(note.renoteId, this.user, { - detail: true - }); - } - - // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する - if (shouldMuteThisNote(note, this.mutedUserIds)) return; - - this.send('note', note); - } - - @autobind - public dispose() { - // Unsubscribe events - this.subscriber.off('hybridTimeline', this.onNewNote); - this.subscriber.off(`hybridTimeline:${this.user._id}`, this.onNewNote); - } -} diff --git a/src/server/api/stream/channels/index.ts b/src/server/api/stream/channels/index.ts index 4527fb1e46..199ab0a809 100644 --- a/src/server/api/stream/channels/index.ts +++ b/src/server/api/stream/channels/index.ts @@ -1,7 +1,7 @@ import main from './main'; import homeTimeline from './home-timeline'; import localTimeline from './local-timeline'; -import hybridTimeline from './hybrid-timeline'; +import socialTimeline from './social-timeline'; import globalTimeline from './global-timeline'; import notesStats from './notes-stats'; import serverStats from './server-stats'; @@ -20,7 +20,7 @@ export default { main, homeTimeline, localTimeline, - hybridTimeline, + socialTimeline, globalTimeline, notesStats, serverStats, diff --git a/src/server/api/stream/channels/local-timeline.ts b/src/server/api/stream/channels/local-timeline.ts index 3402023192..4aec2d66b4 100644 --- a/src/server/api/stream/channels/local-timeline.ts +++ b/src/server/api/stream/channels/local-timeline.ts @@ -1,17 +1,14 @@ import autobind from 'autobind-decorator'; -import Mute from '../../../../models/mute'; -import { pack } from '../../../../models/note'; import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; import Channel from '../channel'; import fetchMeta from '../../../../misc/fetch-meta'; +import { Notes } from '../../../../models'; export default class extends Channel { public readonly chName = 'localTimeline'; public static shouldShare = true; public static requireCredential = false; - private mutedUserIds: string[] = []; - @autobind public async init(params: any) { const meta = await fetchMeta(); @@ -20,29 +17,39 @@ export default class extends Channel { } // Subscribe events - this.subscriber.on('localTimeline', this.onNote); - - const mute = this.user ? await Mute.find({ muterId: this.user._id }) : null; - this.mutedUserIds = mute ? mute.map(m => m.muteeId.toString()) : []; + this.subscriber.on('notesStream', this.onNote); } @autobind private async onNote(note: any) { - // リプライなら再pack - if (note.replyId != null) { - note.reply = await pack(note.replyId, this.user, { - detail: true - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await pack(note.renoteId, this.user, { + if (note.user.host !== null) return; + if (note.visibility === 'home') return; + + if (['followers', 'specified'].includes(note.visibility)) { + note = await Notes.pack(note.id, this.user, { detail: true }); + + if (note.isHidden) { + return; + } + } else { + // リプライなら再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 (shouldMuteThisNote(note, this.mutedUserIds)) return; + if (shouldMuteThisNote(note, this.muting)) return; this.send('note', note); } @@ -50,6 +57,6 @@ export default class extends Channel { @autobind public dispose() { // Unsubscribe events - this.subscriber.off('localTimeline', this.onNote); + this.subscriber.off('notesStream', this.onNote); } } diff --git a/src/server/api/stream/channels/main.ts b/src/server/api/stream/channels/main.ts index 175d914fa5..0d9bf3149d 100644 --- a/src/server/api/stream/channels/main.ts +++ b/src/server/api/stream/channels/main.ts @@ -1,6 +1,6 @@ import autobind from 'autobind-decorator'; -import Mute from '../../../../models/mute'; import Channel from '../channel'; +import { Mutings } from '../../../../models'; export default class extends Channel { public readonly chName = 'main'; @@ -9,16 +9,15 @@ export default class extends Channel { @autobind public async init(params: any) { - const mute = await Mute.find({ muterId: this.user._id }); - const mutedUserIds = mute.map(m => m.muteeId.toString()); + const mute = await Mutings.find({ muterId: this.user.id }); // Subscribe main stream channel - this.subscriber.on(`mainStream:${this.user._id}`, async data => { + this.subscriber.on(`mainStream:${this.user.id}`, async data => { const { type, body } = data; switch (type) { case 'notification': { - if (mutedUserIds.includes(body.userId)) return; + if (mute.map(m => m.muteeId).includes(body.userId)) return; if (body.note && body.note.isHidden) return; break; } diff --git a/src/server/api/stream/channels/messaging-index.ts b/src/server/api/stream/channels/messaging-index.ts index 148ff7f935..648badc1dc 100644 --- a/src/server/api/stream/channels/messaging-index.ts +++ b/src/server/api/stream/channels/messaging-index.ts @@ -9,7 +9,7 @@ export default class extends Channel { @autobind public async init(params: any) { // Subscribe messaging index stream - this.subscriber.on(`messagingIndexStream:${this.user._id}`, data => { + this.subscriber.on(`messagingIndexStream:${this.user.id}`, data => { this.send(data); }); } diff --git a/src/server/api/stream/channels/messaging.ts b/src/server/api/stream/channels/messaging.ts index 0d81b4e45c..b81fbb9d4c 100644 --- a/src/server/api/stream/channels/messaging.ts +++ b/src/server/api/stream/channels/messaging.ts @@ -14,7 +14,7 @@ export default class extends Channel { this.otherpartyId = params.otherparty as string; // Subscribe messaging stream - this.subscriber.on(`messagingStream:${this.user._id}-${this.otherpartyId}`, data => { + this.subscriber.on(`messagingStream:${this.user.id}-${this.otherpartyId}`, data => { this.send(data); }); } @@ -23,7 +23,7 @@ export default class extends Channel { public onMessage(type: string, body: any) { switch (type) { case 'read': - read(this.user._id, this.otherpartyId, body.id); + read(this.user.id, this.otherpartyId, body.id); break; } } diff --git a/src/server/api/stream/channels/social-timeline.ts b/src/server/api/stream/channels/social-timeline.ts new file mode 100644 index 0000000000..1d76eed297 --- /dev/null +++ b/src/server/api/stream/channels/social-timeline.ts @@ -0,0 +1,64 @@ +import autobind from 'autobind-decorator'; +import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; +import Channel from '../channel'; +import fetchMeta from '../../../../misc/fetch-meta'; +import { Notes } from '../../../../models'; + +export default class extends Channel { + public readonly chName = 'socialTimeline'; + public static shouldShare = true; + public static requireCredential = true; + + @autobind + public async init(params: any) { + const meta = await fetchMeta(); + if (meta.disableLocalTimeline && !this.user.isAdmin && !this.user.isModerator) return; + + // Subscribe events + this.subscriber.on('notesStream', this.onNote); + } + + @autobind + private async onNote(note: any) { + // 自分自身の投稿 または その投稿のユーザーをフォローしている または ローカルの投稿 の場合だけ + if (!( + this.user.id === note.userId || + this.following.includes(note.userId) || + note.user.host === null + )) return; + + if (['followers', 'specified'].includes(note.visibility)) { + note = await Notes.pack(note.id, this.user, { + detail: true + }); + + if (note.isHidden) { + return; + } + } else { + // リプライなら再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 (shouldMuteThisNote(note, this.muting)) return; + + this.send('note', note); + } + + @autobind + public dispose() { + // Unsubscribe events + this.subscriber.off('notesStream', this.onNote); + } +} diff --git a/src/server/api/stream/channels/user-list.ts b/src/server/api/stream/channels/user-list.ts index 5debf41770..f5434b8f08 100644 --- a/src/server/api/stream/channels/user-list.ts +++ b/src/server/api/stream/channels/user-list.ts @@ -1,23 +1,81 @@ import autobind from 'autobind-decorator'; import Channel from '../channel'; -import { pack } from '../../../../models/note'; +import { Notes, UserListJoinings } from '../../../../models'; +import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; +import { User } from '../../../../models/entities/user'; export default class extends Channel { public readonly chName = 'userList'; public static shouldShare = false; public static requireCredential = false; + private listId: string; + public listUsers: User['id'][] = []; + private listUsersClock: NodeJS.Timer; @autobind public async init(params: any) { - const listId = params.listId as string; + this.listId = params.listId as string; // Subscribe stream - this.subscriber.on(`userListStream:${listId}`, async data => { - // 再パック - if (data.type == 'note') data.body = await pack(data.body.id, this.user, { + this.subscriber.on(`userListStream:${this.listId}`, this.send); + + this.subscriber.on('notesStream', this.onNote); + + this.updateListUsers(); + this.listUsersClock = setInterval(this.updateListUsers, 5000); + } + + @autobind + private async updateListUsers() { + const users = await UserListJoinings.find({ + where: { + userListId: this.listId, + }, + select: ['userId'] + }); + + this.listUsers = users.map(x => x.userId); + } + + @autobind + private async onNote(note: any) { + if (!this.listUsers.includes(note.userId)) return; + + if (['followers', 'specified'].includes(note.visibility)) { + note = await Notes.pack(note.id, this.user, { detail: true }); - this.send(data); - }); + + if (note.isHidden) { + return; + } + } else { + // リプライなら再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 (shouldMuteThisNote(note, this.muting)) return; + + this.send('note', note); + } + + @autobind + public dispose() { + // Unsubscribe events + this.subscriber.off(`userListStream:${this.listId}`, this.send); + this.subscriber.off('notesStream', this.onNote); + + clearInterval(this.listUsersClock); } } |