From 5e61c60f85e262421c1655eb6f8a317b88ccb88f Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 19 Mar 2021 18:22:34 +0900 Subject: perf(server): Improver performance --- src/server/api/endpoints/i/notifications.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/server/api/endpoints') diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts index 0e09bc73fd..7a423edb8d 100644 --- a/src/server/api/endpoints/i/notifications.ts +++ b/src/server/api/endpoints/i/notifications.ts @@ -85,7 +85,9 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notifications.createQueryBuilder('notification'), ps.sinceId, ps.untilId) .andWhere(`notification.notifieeId = :meId`, { meId: user.id }) - .leftJoinAndSelect('notification.notifier', 'notifier'); + .leftJoinAndSelect('notification.notifier', 'notifier') + .leftJoinAndSelect('notification.note', 'note') + .leftJoinAndSelect('note.user', 'user'); query.andWhere(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`); query.setParameters(mutingQuery.getParameters()); -- cgit v1.2.3-freya From 87c8f9ff953499340496e9c5db09c93eaff08851 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 19 Mar 2021 20:43:24 +0900 Subject: perf: Reduce database query --- src/client/components/note-detailed.vue | 10 ++- src/client/components/note.vue | 10 ++- src/client/ui/chat/note.vue | 10 ++- src/server/api/endpoints/notes/mentions.ts | 6 +- src/server/api/stream/index.ts | 38 ++++++++--- src/services/note/read-mention.ts | 29 ++++++++ src/services/note/read-specified-note.ts | 29 ++++++++ src/services/note/read.ts | 105 ----------------------------- 8 files changed, 114 insertions(+), 123 deletions(-) create mode 100644 src/services/note/read-mention.ts create mode 100644 src/services/note/read-specified-note.ts delete mode 100644 src/services/note/read.ts (limited to 'src/server/api/endpoints') diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue index 1ef3f43389..4ad3d2d898 100644 --- a/src/client/components/note-detailed.vue +++ b/src/client/components/note-detailed.vue @@ -350,7 +350,15 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); + this.connection.send('sn', { id: this.appearNote.id }); + if (this.appearNote.userId !== this.$i.id) { + if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) { + this.connection.send('readMention', { id: this.appearNote.id }); + } + if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) { + this.connection.send('readSpecifiedNote', { id: this.appearNote.id }); + } + } if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/client/components/note.vue b/src/client/components/note.vue index 65e09b7802..3b59afd71d 100644 --- a/src/client/components/note.vue +++ b/src/client/components/note.vue @@ -325,7 +325,15 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); + this.connection.send('sn', { id: this.appearNote.id }); + if (this.appearNote.userId !== this.$i.id) { + if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) { + this.connection.send('readMention', { id: this.appearNote.id }); + } + if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) { + this.connection.send('readSpecifiedNote', { id: this.appearNote.id }); + } + } if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue index 5a4a13d889..29bc61d9c5 100644 --- a/src/client/ui/chat/note.vue +++ b/src/client/ui/chat/note.vue @@ -325,7 +325,15 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); + this.connection.send('sn', { id: this.appearNote.id }); + if (this.appearNote.userId !== this.$i.id) { + if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) { + this.connection.send('readMention', { id: this.appearNote.id }); + } + if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) { + this.connection.send('readSpecifiedNote', { id: this.appearNote.id }); + } + } if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts index 8a9d295d38..1e3014bd46 100644 --- a/src/server/api/endpoints/notes/mentions.ts +++ b/src/server/api/endpoints/notes/mentions.ts @@ -1,12 +1,12 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; -import read from '../../../../services/note/read'; import { Notes, Followings } from '../../../../models'; import { generateVisibilityQuery } from '../../common/generate-visibility-query'; import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; import { makePaginationQuery } from '../../common/make-pagination-query'; import { Brackets } from 'typeorm'; +import { readMention } from '../../../../services/note/read-mention'; export const meta = { desc: { @@ -79,9 +79,7 @@ export default define(meta, async (ps, user) => { const mentions = await query.take(ps.limit!).getMany(); - for (const note of mentions) { - read(user.id, note.id); - } + readMention(user.id, mentions.map(n => n.id)); return await Notes.packMany(mentions, user); }); diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts index bb37cfa622..4a87f61e7f 100644 --- a/src/server/api/stream/index.ts +++ b/src/server/api/stream/index.ts @@ -2,7 +2,6 @@ import autobind from 'autobind-decorator'; import * as websocket from 'websocket'; import { readNotification } from '../common/read-notification'; import call from '../call'; -import readNote from '../../../services/note/read'; import Channel from './channel'; import channels from './channels'; import { EventEmitter } from 'events'; @@ -14,6 +13,8 @@ import { AccessToken } from '../../../models/entities/access-token'; import { UserProfile } from '../../../models/entities/user-profile'; import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '../../../services/stream'; import { UserGroup } from '../../../models/entities/user-group'; +import { readMention } from '../../../services/note/read-mention'; +import { readSpecifiedNote } from '../../../services/note/read-specified-note'; /** * Main stream connection @@ -86,9 +87,10 @@ export default class Connection { switch (type) { case 'api': this.onApiRequest(body); break; case 'readNotification': this.onReadNotification(body); break; - case 'subNote': this.onSubscribeNote(body, true); break; - case 'sn': this.onSubscribeNote(body, true); break; // alias - case 's': this.onSubscribeNote(body, false); break; + case 'readMention': this.onReadMention(body); break; + case 'readSpecifiedNote': this.onReadSpecifiedNote(body); break; + case 'subNote': this.onSubscribeNote(body); break; + case 'sn': this.onSubscribeNote(body); break; // alias case 'unsubNote': this.onUnsubscribeNote(body); break; case 'un': this.onUnsubscribeNote(body); break; // alias case 'connect': this.onChannelConnectRequested(body); break; @@ -141,11 +143,31 @@ export default class Connection { readNotification(this.user!.id, [payload.id]); } + @autobind + private onReadMention(payload: any) { + if (!payload.id) return; + if (this.user) { + // TODO: ある程度まとめてreadMentionするようにする + // 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadMentionに渡すような実装にする + readMention(this.user.id, [payload.id]); + } + } + + @autobind + private onReadSpecifiedNote(payload: any) { + if (!payload.id) return; + if (this.user) { + // TODO: ある程度まとめてreadSpecifiedNoteするようにする + // 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadSpecifiedNoteに渡すような実装にする + readSpecifiedNote(this.user.id, [payload.id]); + } + } + /** * 投稿購読要求時 */ @autobind - private onSubscribeNote(payload: any, read: boolean) { + private onSubscribeNote(payload: any) { if (!payload.id) return; if (this.subscribingNotes[payload.id] == null) { @@ -157,12 +179,6 @@ export default class Connection { if (this.subscribingNotes[payload.id] === 1) { this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage); } - - if (this.user && read) { - // TODO: クライアントでタイムライン読み込みなどすると、一度に大量のreadNoteが発生しクエリ数がすごいことになるので、ある程度まとめてreadNoteするようにする - // 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadNoteに渡すような実装にする - readNote(this.user.id, payload.id); - } } /** diff --git a/src/services/note/read-mention.ts b/src/services/note/read-mention.ts new file mode 100644 index 0000000000..2a668ecd6c --- /dev/null +++ b/src/services/note/read-mention.ts @@ -0,0 +1,29 @@ +import { publishMainStream } from '../stream'; +import { Note } from '../../models/entities/note'; +import { User } from '../../models/entities/user'; +import { NoteUnreads } from '../../models'; +import { In } from 'typeorm'; + +/** + * Mark a mention note as read + */ +export async function readMention( + userId: User['id'], + noteIds: Note['id'][] +) { + // Remove the records + await NoteUnreads.delete({ + userId: userId, + noteId: In(noteIds), + }); + + const mentionsCount = await NoteUnreads.count({ + userId: userId, + isMentioned: true + }); + + if (mentionsCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllUnreadMentions'); + } +} diff --git a/src/services/note/read-specified-note.ts b/src/services/note/read-specified-note.ts new file mode 100644 index 0000000000..0fcb66bf98 --- /dev/null +++ b/src/services/note/read-specified-note.ts @@ -0,0 +1,29 @@ +import { publishMainStream } from '../stream'; +import { Note } from '../../models/entities/note'; +import { User } from '../../models/entities/user'; +import { NoteUnreads } from '../../models'; +import { In } from 'typeorm'; + +/** + * Mark a specified note as read + */ +export async function readSpecifiedNote( + userId: User['id'], + noteIds: Note['id'][] +) { + // Remove the records + await NoteUnreads.delete({ + userId: userId, + noteId: In(noteIds), + }); + + const specifiedCount = await NoteUnreads.count({ + userId: userId, + isSpecified: true + }); + + if (specifiedCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); + } +} diff --git a/src/services/note/read.ts b/src/services/note/read.ts deleted file mode 100644 index 5a39ab30b7..0000000000 --- a/src/services/note/read.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { publishMainStream } from '../stream'; -import { Note } from '../../models/entities/note'; -import { User } from '../../models/entities/user'; -import { NoteUnreads, Antennas, AntennaNotes, Users } from '../../models'; -import { Not, IsNull } from 'typeorm'; - -/** - * Mark a note as read - */ -export default async function( - userId: User['id'], - noteId: Note['id'] -) { - async function careNoteUnreads() { - const exist = await NoteUnreads.findOne({ - userId: userId, - noteId: noteId, - }); - - if (!exist) return; - - // Remove the record - await NoteUnreads.delete({ - userId: userId, - noteId: noteId, - }); - - if (exist.isMentioned) { - NoteUnreads.count({ - userId: userId, - isMentioned: true - }).then(mentionsCount => { - if (mentionsCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadMentions'); - } - }); - } - - if (exist.isSpecified) { - NoteUnreads.count({ - userId: userId, - isSpecified: true - }).then(specifiedCount => { - if (specifiedCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); - } - }); - } - - if (exist.noteChannelId) { - NoteUnreads.count({ - userId: userId, - noteChannelId: Not(IsNull()) - }).then(channelNoteCount => { - if (channelNoteCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllChannels'); - } - }); - } - } - - async function careAntenna() { - const beforeUnread = await Users.getHasUnreadAntenna(userId); - if (!beforeUnread) return; - - const antennas = await Antennas.find({ userId }); - - await Promise.all(antennas.map(async antenna => { - const countBefore = await AntennaNotes.count({ - antennaId: antenna.id, - read: false - }); - - if (countBefore === 0) return; - - await AntennaNotes.update({ - antennaId: antenna.id, - noteId: noteId - }, { - read: true - }); - - const countAfter = await AntennaNotes.count({ - antennaId: antenna.id, - read: false - }); - - if (countAfter === 0) { - publishMainStream(userId, 'readAntenna', antenna); - } - })); - - Users.getHasUnreadAntenna(userId).then(unread => { - if (!unread) { - publishMainStream(userId, 'readAllAntennas'); - } - }); - } - - careNoteUnreads(); - careAntenna(); -} -- cgit v1.2.3-freya From e523e54881834a50b7b5e1f0efebcc98cfc34dd7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 20 Mar 2021 11:05:33 +0900 Subject: perf(server): Reduce database query --- src/models/repositories/notification.ts | 67 ++++++++++++++++++++++++----- src/server/api/endpoints/i/notifications.ts | 2 +- 2 files changed, 58 insertions(+), 11 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/models/repositories/notification.ts b/src/models/repositories/notification.ts index d593dc22a9..a9fe5e7b4e 100644 --- a/src/models/repositories/notification.ts +++ b/src/models/repositories/notification.ts @@ -1,8 +1,11 @@ -import { EntityRepository, Repository } from 'typeorm'; -import { Users, Notes, UserGroupInvitations, AccessTokens } from '..'; +import { EntityRepository, In, Repository } from 'typeorm'; +import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '..'; import { Notification } from '../entities/notification'; import { awaitAll } from '../../prelude/await-all'; import { SchemaType } from '../../misc/schema'; +import { Note } from '../entities/note'; +import { NoteReaction } from '../entities/note-reaction'; +import { User } from '../entities/user'; export type PackedNotification = SchemaType; @@ -10,6 +13,11 @@ export type PackedNotification = SchemaType; export class NotificationRepository extends Repository { public async pack( src: Notification['id'] | Notification, + options: { + _hintForEachNotes_: { + myReactions: Map; + }; + } ): Promise { const notification = typeof src === 'object' ? src : await this.findOneOrFail(src); const token = notification.appAccessTokenId ? await AccessTokens.findOneOrFail(notification.appAccessTokenId) : null; @@ -22,23 +30,41 @@ export class NotificationRepository extends Repository { userId: notification.notifierId, user: notification.notifierId ? Users.pack(notification.notifier || notification.notifierId) : null, ...(notification.type === 'mention' ? { - note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId), + note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, { + detail: true, + _hint_: options._hintForEachNotes_ + }), } : {}), ...(notification.type === 'reply' ? { - note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId), + note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, { + detail: true, + _hint_: options._hintForEachNotes_ + }), } : {}), ...(notification.type === 'renote' ? { - note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId), + note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, { + detail: true, + _hint_: options._hintForEachNotes_ + }), } : {}), ...(notification.type === 'quote' ? { - note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId), + note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, { + detail: true, + _hint_: options._hintForEachNotes_ + }), } : {}), ...(notification.type === 'reaction' ? { - note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId), + note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, { + detail: true, + _hint_: options._hintForEachNotes_ + }), reaction: notification.reaction } : {}), ...(notification.type === 'pollVote' ? { - note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId), + note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, { + detail: true, + _hint_: options._hintForEachNotes_ + }), choice: notification.choice } : {}), ...(notification.type === 'groupInvited' ? { @@ -52,10 +78,31 @@ export class NotificationRepository extends Repository { }); } - public packMany( + public async packMany( notifications: Notification[], + meId: User['id'] ) { - return Promise.all(notifications.map(x => this.pack(x))); + if (notifications.length === 0) return []; + + const notes = notifications.filter(x => x.note != null).map(x => x.note!); + const noteIds = notes.map(n => n.id); + const myReactionsMap = new Map(); + const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); + const targets = [...noteIds, ...renoteIds]; + const myReactions = await NoteReactions.find({ + userId: meId, + noteId: In(targets), + }); + + for (const target of targets) { + myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) || null); + } + + return await Promise.all(notifications.map(x => this.pack(x, { + _hintForEachNotes_: { + myReactions: myReactionsMap + } + }))); } } diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts index 7a423edb8d..af49549d37 100644 --- a/src/server/api/endpoints/i/notifications.ts +++ b/src/server/api/endpoints/i/notifications.ts @@ -112,5 +112,5 @@ export default define(meta, async (ps, user) => { readNotification(user.id, notifications.map(x => x.id)); } - return await Notifications.packMany(notifications); + return await Notifications.packMany(notifications, user.id); }); -- cgit v1.2.3-freya From f27e4033a6599203ba37efe01edbd988699b4068 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 20 Mar 2021 13:54:59 +0900 Subject: perf(server): Reduce database query Related: #6813 --- src/models/repositories/note.ts | 86 ++++++++++++++++++++-- src/models/repositories/notification.ts | 45 ++++++++++- src/models/repositories/user.ts | 40 ++++++++-- src/server/api/endpoints/antennas/notes.ts | 4 + src/server/api/endpoints/channels/timeline.ts | 4 + src/server/api/endpoints/clips/notes.ts | 4 + src/server/api/endpoints/i/notifications.ts | 6 +- src/server/api/endpoints/notes.ts | 6 +- src/server/api/endpoints/notes/children.ts | 6 +- src/server/api/endpoints/notes/featured.ts | 6 +- src/server/api/endpoints/notes/global-timeline.ts | 6 +- src/server/api/endpoints/notes/hybrid-timeline.ts | 4 + src/server/api/endpoints/notes/local-timeline.ts | 6 +- src/server/api/endpoints/notes/mentions.ts | 6 +- src/server/api/endpoints/notes/renotes.ts | 6 +- src/server/api/endpoints/notes/replies.ts | 6 +- src/server/api/endpoints/notes/search-by-tag.ts | 6 +- src/server/api/endpoints/notes/search.ts | 6 +- src/server/api/endpoints/notes/timeline.ts | 4 + .../api/endpoints/notes/user-list-timeline.ts | 4 + src/server/api/endpoints/users/notes.ts | 6 +- 21 files changed, 240 insertions(+), 27 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/models/repositories/note.ts b/src/models/repositories/note.ts index 43caaf94b2..1fcedbd56f 100644 --- a/src/models/repositories/note.ts +++ b/src/models/repositories/note.ts @@ -85,6 +85,7 @@ export class NoteRepository extends Repository { detail?: boolean; skipHide?: boolean; _hint_?: { + emojis: Emoji[] | null; myReactions: Map; }; } @@ -141,11 +142,43 @@ export class NoteRepository extends Repository { * @param reactionNames Note等にリアクションされたカスタム絵文字名 (:は含めない) */ async function populateEmojis(emojiNames: string[], noteUserHost: string | null, reactionNames: string[]) { + const customReactions = reactionNames?.map(x => decodeReaction(x)).filter(x => x.name); + let all = [] as { name: string, url: string }[]; + // 与えられたhintだけで十分(=新たにクエリする必要がない)かどうかを表すフラグ + let enough = true; + if (options?._hint_?.emojis) { + for (const name of emojiNames) { + const matched = options._hint_.emojis.find(x => x.name === name && x.host === noteUserHost); + if (matched) { + all.push({ + name: matched.name, + url: matched.url, + }); + } else { + enough = false; + } + } + for (const customReaction of customReactions) { + const matched = options._hint_.emojis.find(x => x.name === customReaction.name && x.host === customReaction.host); + if (matched) { + all.push({ + name: `${matched.name}@${matched.host || '.'}`, // @host付きでローカルは. + url: matched.url, + }); + } else { + enough = false; + } + } + } else { + enough = false; + } + if (enough) return all; + // カスタム絵文字 if (emojiNames?.length > 0) { const tmp = await Emojis.find({ @@ -164,8 +197,6 @@ export class NoteRepository extends Repository { all = concat([all, tmp]); } - const customReactions = reactionNames?.map(x => decodeReaction(x)).filter(x => x.name); - if (customReactions?.length > 0) { const where = [] as {}[]; @@ -230,7 +261,12 @@ export class NoteRepository extends Repository { id: note.id, createdAt: note.createdAt.toISOString(), userId: note.userId, - user: Users.pack(note.user || note.userId, meId), + user: Users.pack(note.user || note.userId, meId, { + detail: false, + _hint_: { + emojis: options?._hint_?.emojis || null + } + }), text: text, cw: note.cw, visibility: note.visibility, @@ -258,12 +294,12 @@ export class NoteRepository extends Repository { _prId_: (note as any)._prId_ || undefined, ...(opts.detail ? { - reply: note.replyId ? this.pack(note.replyId, meId, { + reply: note.replyId ? this.pack(note.reply || note.replyId, meId, { detail: false, _hint_: options?._hint_ }) : undefined, - renote: note.renoteId ? this.pack(note.renoteId, meId, { + renote: note.renoteId ? this.pack(note.renote || note.renoteId, meId, { detail: true, _hint_: options?._hint_ }) : undefined, @@ -314,10 +350,48 @@ export class NoteRepository extends Repository { } } + // TODO: ここら辺の処理をaggregateEmojisみたいな関数に切り出したい + let emojisWhere: any[] = []; + for (const note of notes) { + if (typeof note !== 'object') continue; + emojisWhere.push({ + name: In(note.emojis), + host: note.userHost + }); + if (note.renote) { + emojisWhere.push({ + name: In(note.renote.emojis), + host: note.renote.userHost + }); + if (note.renote.user) { + emojisWhere.push({ + name: In(note.renote.user.emojis), + host: note.renote.userHost + }); + } + } + const customReactions = Object.keys(note.reactions).map(x => decodeReaction(x)).filter(x => x.name); + emojisWhere = emojisWhere.concat(customReactions.map(x => ({ + name: x.name, + host: x.host + }))); + if (note.user) { + emojisWhere.push({ + name: In(note.user.emojis), + host: note.userHost + }); + } + } + const emojis = emojisWhere.length > 0 ? await Emojis.find({ + where: emojisWhere, + select: ['name', 'host', 'url'] + }) : null; + return await Promise.all(notes.map(n => this.pack(n, me, { ...options, _hint_: { - myReactions: myReactionsMap + myReactions: myReactionsMap, + emojis: emojis } }))); } diff --git a/src/models/repositories/notification.ts b/src/models/repositories/notification.ts index a9fe5e7b4e..1027155873 100644 --- a/src/models/repositories/notification.ts +++ b/src/models/repositories/notification.ts @@ -1,11 +1,13 @@ import { EntityRepository, In, Repository } from 'typeorm'; -import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '..'; +import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions, Emojis } from '..'; import { Notification } from '../entities/notification'; import { awaitAll } from '../../prelude/await-all'; import { SchemaType } from '../../misc/schema'; import { Note } from '../entities/note'; import { NoteReaction } from '../entities/note-reaction'; import { User } from '../entities/user'; +import { decodeReaction } from '../../misc/reaction-lib'; +import { Emoji } from '../entities/emoji'; export type PackedNotification = SchemaType; @@ -15,6 +17,7 @@ export class NotificationRepository extends Repository { src: Notification['id'] | Notification, options: { _hintForEachNotes_: { + emojis: Emoji[] | null; myReactions: Map; }; } @@ -98,9 +101,47 @@ export class NotificationRepository extends Repository { myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) || null); } + // TODO: ここら辺の処理をaggregateEmojisみたいな関数に切り出したい + let emojisWhere: any[] = []; + for (const note of notes) { + if (typeof note !== 'object') continue; + emojisWhere.push({ + name: In(note.emojis), + host: note.userHost + }); + if (note.renote) { + emojisWhere.push({ + name: In(note.renote.emojis), + host: note.renote.userHost + }); + if (note.renote.user) { + emojisWhere.push({ + name: In(note.renote.user.emojis), + host: note.renote.userHost + }); + } + } + const customReactions = Object.keys(note.reactions).map(x => decodeReaction(x)).filter(x => x.name); + emojisWhere = emojisWhere.concat(customReactions.map(x => ({ + name: x.name, + host: x.host + }))); + if (note.user) { + emojisWhere.push({ + name: In(note.user.emojis), + host: note.userHost + }); + } + } + const emojis = emojisWhere.length > 0 ? await Emojis.find({ + where: emojisWhere, + select: ['name', 'host', 'url'] + }) : null; + return await Promise.all(notifications.map(x => this.pack(x, { _hintForEachNotes_: { - myReactions: myReactionsMap + myReactions: myReactionsMap, + emojis: emojis, } }))); } diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts index 3a6ab48c5f..19b0e54239 100644 --- a/src/models/repositories/user.ts +++ b/src/models/repositories/user.ts @@ -5,6 +5,7 @@ import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMes import config from '../../config'; import { SchemaType } from '../../misc/schema'; import { awaitAll } from '../../prelude/await-all'; +import { Emoji } from '../entities/emoji'; export type PackedUser = SchemaType; @@ -149,6 +150,9 @@ export class UserRepository extends Repository { options?: { detail?: boolean, includeSecrets?: boolean, + _hint_?: { + emojis: Emoji[] | null; + }; } ): Promise { const opts = Object.assign({ @@ -166,6 +170,34 @@ export class UserRepository extends Repository { }) : []; const profile = opts.detail ? await UserProfiles.findOneOrFail(user.id) : null; + let emojis: Emoji[] = []; + if (user.emojis.length > 0) { + // 与えられたhintだけで十分(=新たにクエリする必要がない)かどうかを表すフラグ + let enough = true; + if (options?._hint_?.emojis) { + for (const name of user.emojis) { + const matched = options._hint_.emojis.find(x => x.name === name && x.host === user.host); + if (matched) { + emojis.push(matched); + } else { + enough = false; + } + } + } else { + enough = false; + } + + if (!enough) { + emojis = await Emojis.find({ + where: { + name: In(user.emojis), + host: user.host + }, + select: ['name', 'host', 'url', 'aliases'] + }); + } + } + const falsy = opts.detail ? false : undefined; const packed = { @@ -190,13 +222,7 @@ export class UserRepository extends Repository { } : undefined) : undefined, // カスタム絵文字添付 - emojis: user.emojis.length > 0 ? Emojis.find({ - where: { - name: In(user.emojis), - host: user.host - }, - select: ['name', 'host', 'url', 'aliases'] - }) : [], + emojis: emojis, ...(opts.detail ? { url: profile!.url, diff --git a/src/server/api/endpoints/antennas/notes.ts b/src/server/api/endpoints/antennas/notes.ts index 750fc080cf..2ea3e43745 100644 --- a/src/server/api/endpoints/antennas/notes.ts +++ b/src/server/api/endpoints/antennas/notes.ts @@ -74,6 +74,10 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ antennaQuery.getQuery() })`) .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(antennaQuery.getParameters()); generateVisibilityQuery(query, user); diff --git a/src/server/api/endpoints/channels/timeline.ts b/src/server/api/endpoints/channels/timeline.ts index acb34f124d..292f21b63d 100644 --- a/src/server/api/endpoints/channels/timeline.ts +++ b/src/server/api/endpoints/channels/timeline.ts @@ -88,6 +88,10 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.channelId = :channelId', { channelId: channel.id }) .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .leftJoinAndSelect('note.channel', 'channel'); //#endregion diff --git a/src/server/api/endpoints/clips/notes.ts b/src/server/api/endpoints/clips/notes.ts index 6a507e2036..86d1e507f4 100644 --- a/src/server/api/endpoints/clips/notes.ts +++ b/src/server/api/endpoints/clips/notes.ts @@ -72,6 +72,10 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ clipQuery.getQuery() })`) .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(clipQuery.getParameters()); if (user) { diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts index af49549d37..812a4bd1dd 100644 --- a/src/server/api/endpoints/i/notifications.ts +++ b/src/server/api/endpoints/i/notifications.ts @@ -87,7 +87,11 @@ export default define(meta, async (ps, user) => { .andWhere(`notification.notifieeId = :meId`, { meId: user.id }) .leftJoinAndSelect('notification.notifier', 'notifier') .leftJoinAndSelect('notification.note', 'note') - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); query.andWhere(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`); query.setParameters(mutingQuery.getParameters()); diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts index fab8455d78..708ce38c0e 100644 --- a/src/server/api/endpoints/notes.ts +++ b/src/server/api/endpoints/notes.ts @@ -76,7 +76,11 @@ export default define(meta, async (ps) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.visibility = 'public'`) .andWhere(`note.localOnly = FALSE`) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); if (ps.local) { query.andWhere('note.userHost IS NULL'); diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts index 0875e0f240..a8b239e445 100644 --- a/src/server/api/endpoints/notes/children.ts +++ b/src/server/api/endpoints/notes/children.ts @@ -64,7 +64,11 @@ export default define(meta, async (ps, user) => { })); })); })) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/featured.ts b/src/server/api/endpoints/notes/featured.ts index 4dda7d0edb..6c416b1c04 100644 --- a/src/server/api/endpoints/notes/featured.ts +++ b/src/server/api/endpoints/notes/featured.ts @@ -49,7 +49,11 @@ export default define(meta, async (ps, user) => { .andWhere(`note.score > 0`) .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts index 6d99f1fdbc..64c2f5851c 100644 --- a/src/server/api/endpoints/notes/global-timeline.ts +++ b/src/server/api/endpoints/notes/global-timeline.ts @@ -81,7 +81,11 @@ export default define(meta, async (ps, user) => { ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.visibility = \'public\'') .andWhere('note.channelId IS NULL') - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateRepliesQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index 2b91b8c67b..c01e170aa9 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -130,6 +130,10 @@ export default define(meta, async (ps, user) => { .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); })) .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts index 51e35e6241..31abb26882 100644 --- a/src/server/api/endpoints/notes/local-timeline.ts +++ b/src/server/api/endpoints/notes/local-timeline.ts @@ -98,7 +98,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateChannelQuery(query, user); generateRepliesQuery(query, user); diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts index 1e3014bd46..83e890d9ad 100644 --- a/src/server/api/endpoints/notes/mentions.ts +++ b/src/server/api/endpoints/notes/mentions.ts @@ -63,7 +63,11 @@ export default define(meta, async (ps, user) => { .where(`:meId = ANY(note.mentions)`, { meId: user.id }) .orWhere(`:meId = ANY(note.visibleUserIds)`, { meId: user.id }); })) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/renotes.ts b/src/server/api/endpoints/notes/renotes.ts index 31c24f294a..f528197220 100644 --- a/src/server/api/endpoints/notes/renotes.ts +++ b/src/server/api/endpoints/notes/renotes.ts @@ -68,7 +68,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts index 9fad74c78e..5ac663d77a 100644 --- a/src/server/api/endpoints/notes/replies.ts +++ b/src/server/api/endpoints/notes/replies.ts @@ -59,7 +59,11 @@ export const meta = { export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere('note.replyId = :replyId', { replyId: ps.noteId }) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts index e0f7f4d62c..d878f379c3 100644 --- a/src/server/api/endpoints/notes/search-by-tag.ts +++ b/src/server/api/endpoints/notes/search-by-tag.ts @@ -95,7 +95,11 @@ export const meta = { export default define(meta, async (ps, me) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts index 1aca056299..ae0e9242a6 100644 --- a/src/server/api/endpoints/notes/search.ts +++ b/src/server/api/endpoints/notes/search.ts @@ -79,7 +79,11 @@ export default define(meta, async (ps, me) => { query .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index f09f3d1733..c91bea0c1f 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -123,6 +123,10 @@ export default define(meta, async (ps, user) => { if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); })) .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts index b0ff499d95..040f017fd5 100644 --- a/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/src/server/api/endpoints/notes/user-list-timeline.ts @@ -131,6 +131,10 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.userId IN (${ listQuery.getQuery() })`) .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(listQuery.getParameters()); generateVisibilityQuery(query, user); diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts index 33e3ecb03f..91d1d7f4dd 100644 --- a/src/server/api/endpoints/users/notes.ts +++ b/src/server/api/endpoints/users/notes.ts @@ -131,7 +131,11 @@ export default define(meta, async (ps, me) => { //#region Construct query const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.userId = :userId', { userId: user.id }) - .leftJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me, user); -- cgit v1.2.3-freya From 73df95c42d98c38d362e02a79c5d7620a06f6633 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 20 Mar 2021 14:09:17 +0900 Subject: クライアントサイドで実装したいため一旦 injectPromo および injectFeatured を無効化 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/api/endpoints/notes/global-timeline.ts | 5 ----- src/server/api/endpoints/notes/hybrid-timeline.ts | 5 ----- src/server/api/endpoints/notes/local-timeline.ts | 5 ----- src/server/api/endpoints/notes/timeline.ts | 5 ----- 4 files changed, 20 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts index 64c2f5851c..985760bd9d 100644 --- a/src/server/api/endpoints/notes/global-timeline.ts +++ b/src/server/api/endpoints/notes/global-timeline.ts @@ -8,8 +8,6 @@ import { Notes } from '../../../../models'; import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; import { activeUsersChart } from '../../../../services/chart'; import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { injectPromo } from '../../common/inject-promo'; -import { injectFeatured } from '../../common/inject-featured'; import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; export const meta = { @@ -98,9 +96,6 @@ export default define(meta, async (ps, user) => { const timeline = await query.take(ps.limit!).getMany(); - await injectPromo(timeline, user); - await injectFeatured(timeline, user); - process.nextTick(() => { if (user) { activeUsersChart.update(user); diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index c01e170aa9..69f2a7c107 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -10,8 +10,6 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query' import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; import { activeUsersChart } from '../../../../services/chart'; import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { injectPromo } from '../../common/inject-promo'; -import { injectFeatured } from '../../common/inject-featured'; import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; import { generateChannelQuery } from '../../common/generate-channel-query'; @@ -179,9 +177,6 @@ export default define(meta, async (ps, user) => { const timeline = await query.take(ps.limit!).getMany(); - await injectPromo(timeline, user); - await injectFeatured(timeline, user); - process.nextTick(() => { if (user) { activeUsersChart.update(user); diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts index 31abb26882..9e1c081966 100644 --- a/src/server/api/endpoints/notes/local-timeline.ts +++ b/src/server/api/endpoints/notes/local-timeline.ts @@ -10,8 +10,6 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query' import { activeUsersChart } from '../../../../services/chart'; import { Brackets } from 'typeorm'; import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { injectPromo } from '../../common/inject-promo'; -import { injectFeatured } from '../../common/inject-featured'; import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; import { generateChannelQuery } from '../../common/generate-channel-query'; @@ -132,9 +130,6 @@ export default define(meta, async (ps, user) => { const timeline = await query.take(ps.limit!).getMany(); - await injectPromo(timeline, user); - await injectFeatured(timeline, user); - process.nextTick(() => { if (user) { activeUsersChart.update(user); diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index c91bea0c1f..a158bcd3f0 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -8,8 +8,6 @@ import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; import { activeUsersChart } from '../../../../services/chart'; import { Brackets } from 'typeorm'; import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { injectPromo } from '../../common/inject-promo'; -import { injectFeatured } from '../../common/inject-featured'; import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; import { generateChannelQuery } from '../../common/generate-channel-query'; @@ -172,9 +170,6 @@ export default define(meta, async (ps, user) => { const timeline = await query.take(ps.limit!).getMany(); - await injectPromo(timeline, user); - await injectFeatured(timeline, user); - process.nextTick(() => { if (user) { activeUsersChart.update(user); -- cgit v1.2.3-freya From 9bb6dc52b855dcebd0c0493240d6282ba21810c2 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 20 Mar 2021 15:42:02 +0900 Subject: clean up など MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/init.ts | 34 ---------------------------------- src/client/store.ts | 1 - src/client/theme-store.ts | 27 --------------------------- src/server/api/define.ts | 1 + src/server/api/endpoints/i.ts | 27 +++------------------------ 5 files changed, 4 insertions(+), 86 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/client/init.ts b/src/client/init.ts index 1c44e7f23e..2a2b6a2f86 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -4,40 +4,6 @@ import '@/style.scss'; -// TODO: そのうち消す -if (localStorage.getItem('vuex') != null) { - const vuex = JSON.parse(localStorage.getItem('vuex')); - - localStorage.setItem('account', JSON.stringify({ - ...vuex.i, - token: localStorage.getItem('i') - })); - localStorage.setItem('accounts', JSON.stringify(vuex.device.accounts)); - localStorage.setItem('miux:themes', JSON.stringify(vuex.device.themes)); - - if (vuex.device.userData) { - for (const [k, v] of Object.entries(vuex.device.userData)) { - localStorage.setItem('pizzax::base::' + k, JSON.stringify({ - widgets: v.widgets - })); - - if (v.deck) { - localStorage.setItem('pizzax::deck::' + k, JSON.stringify({ - columns: v.deck.columns, - layout: v.deck.layout, - })); - } - } - } - - localStorage.setItem('vuex-old', JSON.stringify(vuex)); - localStorage.removeItem('vuex'); - localStorage.removeItem('i'); - localStorage.removeItem('locale'); - - location.reload(); -} - import * as Sentry from '@sentry/browser'; import { Integrations } from '@sentry/tracing'; import { createApp, watch } from 'vue'; diff --git a/src/client/store.ts b/src/client/store.ts index 14924dadd0..e6fdd12f1d 100644 --- a/src/client/store.ts +++ b/src/client/store.ts @@ -212,7 +212,6 @@ type Plugin = { */ export class ColdDeviceStorage { public static default = { - themes: [] as Theme[], // TODO: そのうち消す // TODO: テーマをアカウントに保存するようになったのにもかかわらず、以下のどのテーマを使うかという情報だけがブラウザ保存になっていて、アカウント切り替えたりログアウトしたときに不具合が発生するのでなんとかする // テーマIDを保存するのではなく、テーマ自体を保存するようにすれば解決するかも darkTheme: '8050783a-7f63-445a-b270-36d0f6ba1677', diff --git a/src/client/theme-store.ts b/src/client/theme-store.ts index 5e440efbf9..8e21af70fc 100644 --- a/src/client/theme-store.ts +++ b/src/client/theme-store.ts @@ -33,30 +33,3 @@ export async function removeTheme(theme: Theme): Promise { await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); localStorage.setItem(lsCacheKey, JSON.stringify(themes)); } - -// TODO: そのうち消す -if (ColdDeviceStorage.get('themes').length > 0) { - const lsThemes = ColdDeviceStorage.get('themes'); - let registryThemes; - try { - registryThemes = await api('i/registry/get', { scope: ['client'], key: 'themes' }); - } catch (e) { - if (e.code === 'NO_SUCH_KEY') { - registryThemes = []; - } else { - throw e; - } - } - const themes = [] as Theme[]; - for (const theme of lsThemes) { - if (themes.some(x => x.id === theme.id)) continue; - themes.push(theme); - } - for (const theme of registryThemes) { - if (themes.some(x => x.id === theme.id)) continue; - themes.push(theme); - } - await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); - localStorage.setItem(lsCacheKey, JSON.stringify(themes)); - ColdDeviceStorage.set('themes', []); -} diff --git a/src/server/api/define.ts b/src/server/api/define.ts index 1c7ee26479..4e59357c13 100644 --- a/src/server/api/define.ts +++ b/src/server/api/define.ts @@ -18,6 +18,7 @@ type executor = (params: Params, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any, cleanup?: Function) => Promise>>; +// TODO: API関数に user まるごと渡すのではなくユーザーIDなどの最小限のプロパティだけ渡すようにしたい(キャッシュとか考えないでよくなるため) export default function (meta: T, cb: executor) : (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => Promise { return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => { diff --git a/src/server/api/endpoints/i.ts b/src/server/api/endpoints/i.ts index e5b65e0930..87f6ae778d 100644 --- a/src/server/api/endpoints/i.ts +++ b/src/server/api/endpoints/i.ts @@ -1,6 +1,5 @@ import define from '../define'; -import { RegistryItems, UserProfiles, Users } from '../../../models'; -import { genId } from '../../../misc/gen-id'; +import { Users } from '../../../models'; export const meta = { desc: { @@ -23,28 +22,8 @@ export const meta = { export default define(meta, async (ps, user, token) => { const isSecure = token == null; - // TODO: そのうち消す - const profile = await UserProfiles.findOneOrFail(user.id); - for (const [k, v] of Object.entries(profile.clientData)) { - await RegistryItems.insert({ - id: genId(), - createdAt: new Date(), - updatedAt: new Date(), - userId: user.id, - domain: null, - scope: ['client', 'base'], - key: k, - value: v - }); - } - await UserProfiles.createQueryBuilder().update() - .set({ - clientData: {}, - }) - .where('userId = :id', { id: user.id }) - .execute(); - - return await Users.pack(user, user, { + // ここで渡ってきている user はキャッシュされていて古い可能性もあるので id だけ渡す + return await Users.pack(user.id, user, { detail: true, includeSecrets: isSecure }); -- cgit v1.2.3-freya From d7e7848c9206b68ab86d2d566ec4247db87827c0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 10:39:32 +0900 Subject: fix(server): Use inner join https://github.com/syuilo/misskey/issues/6813#issuecomment-803400023 --- src/server/api/common/inject-featured.ts | 2 +- src/server/api/endpoints/antennas/notes.ts | 10 +++++----- src/server/api/endpoints/channels/timeline.ts | 10 +++++----- src/server/api/endpoints/clips/notes.ts | 10 +++++----- src/server/api/endpoints/i/notifications.ts | 10 +++++----- src/server/api/endpoints/notes.ts | 10 +++++----- src/server/api/endpoints/notes/children.ts | 10 +++++----- src/server/api/endpoints/notes/featured.ts | 10 +++++----- src/server/api/endpoints/notes/global-timeline.ts | 10 +++++----- src/server/api/endpoints/notes/hybrid-timeline.ts | 10 +++++----- src/server/api/endpoints/notes/local-timeline.ts | 10 +++++----- src/server/api/endpoints/notes/mentions.ts | 10 +++++----- src/server/api/endpoints/notes/renotes.ts | 10 +++++----- src/server/api/endpoints/notes/replies.ts | 10 +++++----- src/server/api/endpoints/notes/search-by-tag.ts | 10 +++++----- src/server/api/endpoints/notes/search.ts | 10 +++++----- src/server/api/endpoints/notes/timeline.ts | 10 +++++----- src/server/api/endpoints/notes/user-list-timeline.ts | 10 +++++----- src/server/api/endpoints/users/notes.ts | 10 +++++----- 19 files changed, 91 insertions(+), 91 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/server/api/common/inject-featured.ts b/src/server/api/common/inject-featured.ts index 3f47c13385..bbed7f69cb 100644 --- a/src/server/api/common/inject-featured.ts +++ b/src/server/api/common/inject-featured.ts @@ -23,7 +23,7 @@ export async function injectFeatured(timeline: Note[], user?: User | null) { .andWhere(`note.score > 0`) .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .leftJoinAndSelect('note.user', 'user'); + .innerJoinAndSelect('note.user', 'user'); if (user) { query.andWhere('note.userId != :userId', { userId: user.id }); diff --git a/src/server/api/endpoints/antennas/notes.ts b/src/server/api/endpoints/antennas/notes.ts index 2ea3e43745..8025ecc66b 100644 --- a/src/server/api/endpoints/antennas/notes.ts +++ b/src/server/api/endpoints/antennas/notes.ts @@ -73,11 +73,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ antennaQuery.getQuery() })`) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser') .setParameters(antennaQuery.getParameters()); generateVisibilityQuery(query, user); diff --git a/src/server/api/endpoints/channels/timeline.ts b/src/server/api/endpoints/channels/timeline.ts index 292f21b63d..33dcb24144 100644 --- a/src/server/api/endpoints/channels/timeline.ts +++ b/src/server/api/endpoints/channels/timeline.ts @@ -87,11 +87,11 @@ export default define(meta, async (ps, user) => { //#region Construct query const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.channelId = :channelId', { channelId: channel.id }) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser') .leftJoinAndSelect('note.channel', 'channel'); //#endregion diff --git a/src/server/api/endpoints/clips/notes.ts b/src/server/api/endpoints/clips/notes.ts index 86d1e507f4..12baa2e344 100644 --- a/src/server/api/endpoints/clips/notes.ts +++ b/src/server/api/endpoints/clips/notes.ts @@ -71,11 +71,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ clipQuery.getQuery() })`) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser') .setParameters(clipQuery.getParameters()); if (user) { diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts index 812a4bd1dd..e3091ebb0a 100644 --- a/src/server/api/endpoints/i/notifications.ts +++ b/src/server/api/endpoints/i/notifications.ts @@ -87,11 +87,11 @@ export default define(meta, async (ps, user) => { .andWhere(`notification.notifieeId = :meId`, { meId: user.id }) .leftJoinAndSelect('notification.notifier', 'notifier') .leftJoinAndSelect('notification.note', 'note') - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); query.andWhere(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`); query.setParameters(mutingQuery.getParameters()); diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts index 708ce38c0e..9fd644dcab 100644 --- a/src/server/api/endpoints/notes.ts +++ b/src/server/api/endpoints/notes.ts @@ -76,11 +76,11 @@ export default define(meta, async (ps) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.visibility = 'public'`) .andWhere(`note.localOnly = FALSE`) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); if (ps.local) { query.andWhere('note.userHost IS NULL'); diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts index a8b239e445..4a03ae2d39 100644 --- a/src/server/api/endpoints/notes/children.ts +++ b/src/server/api/endpoints/notes/children.ts @@ -64,11 +64,11 @@ export default define(meta, async (ps, user) => { })); })); })) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/featured.ts b/src/server/api/endpoints/notes/featured.ts index 6c416b1c04..74a28f25a4 100644 --- a/src/server/api/endpoints/notes/featured.ts +++ b/src/server/api/endpoints/notes/featured.ts @@ -49,11 +49,11 @@ export default define(meta, async (ps, user) => { .andWhere(`note.score > 0`) .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts index 985760bd9d..e6ad9eeba8 100644 --- a/src/server/api/endpoints/notes/global-timeline.ts +++ b/src/server/api/endpoints/notes/global-timeline.ts @@ -79,11 +79,11 @@ export default define(meta, async (ps, user) => { ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.visibility = \'public\'') .andWhere('note.channelId IS NULL') - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateRepliesQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index 69f2a7c107..aa09be23d2 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -127,11 +127,11 @@ export default define(meta, async (ps, user) => { qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id }) .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); })) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts index 9e1c081966..cb6f854b05 100644 --- a/src/server/api/endpoints/notes/local-timeline.ts +++ b/src/server/api/endpoints/notes/local-timeline.ts @@ -96,11 +96,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateChannelQuery(query, user); generateRepliesQuery(query, user); diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts index 83e890d9ad..447a689664 100644 --- a/src/server/api/endpoints/notes/mentions.ts +++ b/src/server/api/endpoints/notes/mentions.ts @@ -63,11 +63,11 @@ export default define(meta, async (ps, user) => { .where(`:meId = ANY(note.mentions)`, { meId: user.id }) .orWhere(`:meId = ANY(note.visibleUserIds)`, { meId: user.id }); })) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/renotes.ts b/src/server/api/endpoints/notes/renotes.ts index f528197220..5be8f42a16 100644 --- a/src/server/api/endpoints/notes/renotes.ts +++ b/src/server/api/endpoints/notes/renotes.ts @@ -68,11 +68,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts index 5ac663d77a..0979d2e7e9 100644 --- a/src/server/api/endpoints/notes/replies.ts +++ b/src/server/api/endpoints/notes/replies.ts @@ -59,11 +59,11 @@ export const meta = { export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere('note.replyId = :replyId', { replyId: ps.noteId }) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts index d878f379c3..af84db1745 100644 --- a/src/server/api/endpoints/notes/search-by-tag.ts +++ b/src/server/api/endpoints/notes/search-by-tag.ts @@ -95,11 +95,11 @@ export const meta = { export default define(meta, async (ps, me) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts index ae0e9242a6..58aabcc22c 100644 --- a/src/server/api/endpoints/notes/search.ts +++ b/src/server/api/endpoints/notes/search.ts @@ -79,11 +79,11 @@ export default define(meta, async (ps, me) => { query .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index a158bcd3f0..e8cda654c1 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -120,11 +120,11 @@ export default define(meta, async (ps, user) => { .where('note.userId = :meId', { meId: user.id }); if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); })) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts index 040f017fd5..1e9af55f1d 100644 --- a/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/src/server/api/endpoints/notes/user-list-timeline.ts @@ -130,11 +130,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.userId IN (${ listQuery.getQuery() })`) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser') .setParameters(listQuery.getParameters()); generateVisibilityQuery(query, user); diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts index 91d1d7f4dd..98c9f10308 100644 --- a/src/server/api/endpoints/users/notes.ts +++ b/src/server/api/endpoints/users/notes.ts @@ -131,11 +131,11 @@ export default define(meta, async (ps, me) => { //#region Construct query const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.userId = :userId', { userId: user.id }) - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .innerJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.reply', 'reply') + .innerJoinAndSelect('note.renote', 'renote') + .innerJoinAndSelect('reply.user', 'replyUser') + .innerJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me, user); -- cgit v1.2.3-freya From e987a50e9fc7bee1b86840cee15a6c86d2d1525d Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 10:41:21 +0900 Subject: perf(server): Improve following/followers API performance Related #6813 --- src/server/api/endpoints/users/followers.ts | 3 ++- src/server/api/endpoints/users/following.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/server/api/endpoints/users/followers.ts b/src/server/api/endpoints/users/followers.ts index bd4a2739c6..fb83d7beb8 100644 --- a/src/server/api/endpoints/users/followers.ts +++ b/src/server/api/endpoints/users/followers.ts @@ -76,7 +76,8 @@ export default define(meta, async (ps, me) => { } const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere(`following.followeeId = :userId`, { userId: user.id }); + .andWhere(`following.followeeId = :userId`, { userId: user.id }) + .innerJoinAndSelect('following.follower', 'follower'); const followings = await query .take(ps.limit!) diff --git a/src/server/api/endpoints/users/following.ts b/src/server/api/endpoints/users/following.ts index 9efb8bfc93..d5e8dc1f92 100644 --- a/src/server/api/endpoints/users/following.ts +++ b/src/server/api/endpoints/users/following.ts @@ -76,7 +76,8 @@ export default define(meta, async (ps, me) => { } const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere(`following.followerId = :userId`, { userId: user.id }); + .andWhere(`following.followerId = :userId`, { userId: user.id }) + .innerJoinAndSelect('following.followee', 'followee'); const followings = await query .take(ps.limit!) -- cgit v1.2.3-freya From c52b50414094e2d44aaea3ab78ef17d04566db80 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 12:31:56 +0900 Subject: Revert "fix(server): Use inner join" This reverts commit d7e7848c9206b68ab86d2d566ec4247db87827c0. --- src/server/api/common/inject-featured.ts | 2 +- src/server/api/endpoints/antennas/notes.ts | 10 +++++----- src/server/api/endpoints/channels/timeline.ts | 10 +++++----- src/server/api/endpoints/clips/notes.ts | 10 +++++----- src/server/api/endpoints/i/notifications.ts | 10 +++++----- src/server/api/endpoints/notes.ts | 10 +++++----- src/server/api/endpoints/notes/children.ts | 10 +++++----- src/server/api/endpoints/notes/featured.ts | 10 +++++----- src/server/api/endpoints/notes/global-timeline.ts | 10 +++++----- src/server/api/endpoints/notes/hybrid-timeline.ts | 10 +++++----- src/server/api/endpoints/notes/local-timeline.ts | 10 +++++----- src/server/api/endpoints/notes/mentions.ts | 10 +++++----- src/server/api/endpoints/notes/renotes.ts | 10 +++++----- src/server/api/endpoints/notes/replies.ts | 10 +++++----- src/server/api/endpoints/notes/search-by-tag.ts | 10 +++++----- src/server/api/endpoints/notes/search.ts | 10 +++++----- src/server/api/endpoints/notes/timeline.ts | 10 +++++----- src/server/api/endpoints/notes/user-list-timeline.ts | 10 +++++----- src/server/api/endpoints/users/notes.ts | 10 +++++----- 19 files changed, 91 insertions(+), 91 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/server/api/common/inject-featured.ts b/src/server/api/common/inject-featured.ts index bbed7f69cb..3f47c13385 100644 --- a/src/server/api/common/inject-featured.ts +++ b/src/server/api/common/inject-featured.ts @@ -23,7 +23,7 @@ export async function injectFeatured(timeline: Note[], user?: User | null) { .andWhere(`note.score > 0`) .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .innerJoinAndSelect('note.user', 'user'); + .leftJoinAndSelect('note.user', 'user'); if (user) { query.andWhere('note.userId != :userId', { userId: user.id }); diff --git a/src/server/api/endpoints/antennas/notes.ts b/src/server/api/endpoints/antennas/notes.ts index 8025ecc66b..2ea3e43745 100644 --- a/src/server/api/endpoints/antennas/notes.ts +++ b/src/server/api/endpoints/antennas/notes.ts @@ -73,11 +73,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ antennaQuery.getQuery() })`) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(antennaQuery.getParameters()); generateVisibilityQuery(query, user); diff --git a/src/server/api/endpoints/channels/timeline.ts b/src/server/api/endpoints/channels/timeline.ts index 33dcb24144..292f21b63d 100644 --- a/src/server/api/endpoints/channels/timeline.ts +++ b/src/server/api/endpoints/channels/timeline.ts @@ -87,11 +87,11 @@ export default define(meta, async (ps, user) => { //#region Construct query const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.channelId = :channelId', { channelId: channel.id }) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .leftJoinAndSelect('note.channel', 'channel'); //#endregion diff --git a/src/server/api/endpoints/clips/notes.ts b/src/server/api/endpoints/clips/notes.ts index 12baa2e344..86d1e507f4 100644 --- a/src/server/api/endpoints/clips/notes.ts +++ b/src/server/api/endpoints/clips/notes.ts @@ -71,11 +71,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ clipQuery.getQuery() })`) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(clipQuery.getParameters()); if (user) { diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts index e3091ebb0a..812a4bd1dd 100644 --- a/src/server/api/endpoints/i/notifications.ts +++ b/src/server/api/endpoints/i/notifications.ts @@ -87,11 +87,11 @@ export default define(meta, async (ps, user) => { .andWhere(`notification.notifieeId = :meId`, { meId: user.id }) .leftJoinAndSelect('notification.notifier', 'notifier') .leftJoinAndSelect('notification.note', 'note') - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); query.andWhere(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`); query.setParameters(mutingQuery.getParameters()); diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts index 9fd644dcab..708ce38c0e 100644 --- a/src/server/api/endpoints/notes.ts +++ b/src/server/api/endpoints/notes.ts @@ -76,11 +76,11 @@ export default define(meta, async (ps) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.visibility = 'public'`) .andWhere(`note.localOnly = FALSE`) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); if (ps.local) { query.andWhere('note.userHost IS NULL'); diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts index 4a03ae2d39..a8b239e445 100644 --- a/src/server/api/endpoints/notes/children.ts +++ b/src/server/api/endpoints/notes/children.ts @@ -64,11 +64,11 @@ export default define(meta, async (ps, user) => { })); })); })) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/featured.ts b/src/server/api/endpoints/notes/featured.ts index 74a28f25a4..6c416b1c04 100644 --- a/src/server/api/endpoints/notes/featured.ts +++ b/src/server/api/endpoints/notes/featured.ts @@ -49,11 +49,11 @@ export default define(meta, async (ps, user) => { .andWhere(`note.score > 0`) .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts index e6ad9eeba8..985760bd9d 100644 --- a/src/server/api/endpoints/notes/global-timeline.ts +++ b/src/server/api/endpoints/notes/global-timeline.ts @@ -79,11 +79,11 @@ export default define(meta, async (ps, user) => { ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.visibility = \'public\'') .andWhere('note.channelId IS NULL') - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateRepliesQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index aa09be23d2..69f2a7c107 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -127,11 +127,11 @@ export default define(meta, async (ps, user) => { qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id }) .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); })) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts index cb6f854b05..9e1c081966 100644 --- a/src/server/api/endpoints/notes/local-timeline.ts +++ b/src/server/api/endpoints/notes/local-timeline.ts @@ -96,11 +96,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateChannelQuery(query, user); generateRepliesQuery(query, user); diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts index 447a689664..83e890d9ad 100644 --- a/src/server/api/endpoints/notes/mentions.ts +++ b/src/server/api/endpoints/notes/mentions.ts @@ -63,11 +63,11 @@ export default define(meta, async (ps, user) => { .where(`:meId = ANY(note.mentions)`, { meId: user.id }) .orWhere(`:meId = ANY(note.visibleUserIds)`, { meId: user.id }); })) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/renotes.ts b/src/server/api/endpoints/notes/renotes.ts index 5be8f42a16..f528197220 100644 --- a/src/server/api/endpoints/notes/renotes.ts +++ b/src/server/api/endpoints/notes/renotes.ts @@ -68,11 +68,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts index 0979d2e7e9..5ac663d77a 100644 --- a/src/server/api/endpoints/notes/replies.ts +++ b/src/server/api/endpoints/notes/replies.ts @@ -59,11 +59,11 @@ export const meta = { export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere('note.replyId = :replyId', { replyId: ps.noteId }) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts index af84db1745..d878f379c3 100644 --- a/src/server/api/endpoints/notes/search-by-tag.ts +++ b/src/server/api/endpoints/notes/search-by-tag.ts @@ -95,11 +95,11 @@ export const meta = { export default define(meta, async (ps, me) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts index 58aabcc22c..ae0e9242a6 100644 --- a/src/server/api/endpoints/notes/search.ts +++ b/src/server/api/endpoints/notes/search.ts @@ -79,11 +79,11 @@ export default define(meta, async (ps, me) => { query .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index e8cda654c1..a158bcd3f0 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -120,11 +120,11 @@ export default define(meta, async (ps, user) => { .where('note.userId = :meId', { meId: user.id }); if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); })) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts index 1e9af55f1d..040f017fd5 100644 --- a/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/src/server/api/endpoints/notes/user-list-timeline.ts @@ -130,11 +130,11 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.userId IN (${ listQuery.getQuery() })`) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') .setParameters(listQuery.getParameters()); generateVisibilityQuery(query, user); diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts index 98c9f10308..91d1d7f4dd 100644 --- a/src/server/api/endpoints/users/notes.ts +++ b/src/server/api/endpoints/users/notes.ts @@ -131,11 +131,11 @@ export default define(meta, async (ps, me) => { //#region Construct query const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.userId = :userId', { userId: user.id }) - .innerJoinAndSelect('note.user', 'user') - .innerJoinAndSelect('note.reply', 'reply') - .innerJoinAndSelect('note.renote', 'renote') - .innerJoinAndSelect('reply.user', 'replyUser') - .innerJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me, user); -- cgit v1.2.3-freya From 70b129cc421c10260a298519521ca646cbc59ab8 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 12:33:37 +0900 Subject: fix(server): Use inner join --- src/server/api/common/inject-featured.ts | 2 +- src/server/api/endpoints/antennas/notes.ts | 2 +- src/server/api/endpoints/channels/timeline.ts | 2 +- src/server/api/endpoints/clips/notes.ts | 2 +- src/server/api/endpoints/notes.ts | 2 +- src/server/api/endpoints/notes/children.ts | 2 +- src/server/api/endpoints/notes/featured.ts | 2 +- src/server/api/endpoints/notes/global-timeline.ts | 2 +- src/server/api/endpoints/notes/hybrid-timeline.ts | 2 +- src/server/api/endpoints/notes/local-timeline.ts | 2 +- src/server/api/endpoints/notes/mentions.ts | 2 +- src/server/api/endpoints/notes/renotes.ts | 2 +- src/server/api/endpoints/notes/replies.ts | 2 +- src/server/api/endpoints/notes/search-by-tag.ts | 2 +- src/server/api/endpoints/notes/search.ts | 2 +- src/server/api/endpoints/notes/timeline.ts | 2 +- src/server/api/endpoints/notes/user-list-timeline.ts | 2 +- src/server/api/endpoints/users/notes.ts | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/server/api/common/inject-featured.ts b/src/server/api/common/inject-featured.ts index 3f47c13385..bbed7f69cb 100644 --- a/src/server/api/common/inject-featured.ts +++ b/src/server/api/common/inject-featured.ts @@ -23,7 +23,7 @@ export async function injectFeatured(timeline: Note[], user?: User | null) { .andWhere(`note.score > 0`) .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .leftJoinAndSelect('note.user', 'user'); + .innerJoinAndSelect('note.user', 'user'); if (user) { query.andWhere('note.userId != :userId', { userId: user.id }); diff --git a/src/server/api/endpoints/antennas/notes.ts b/src/server/api/endpoints/antennas/notes.ts index 2ea3e43745..6fd3cf2df5 100644 --- a/src/server/api/endpoints/antennas/notes.ts +++ b/src/server/api/endpoints/antennas/notes.ts @@ -73,7 +73,7 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ antennaQuery.getQuery() })`) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/channels/timeline.ts b/src/server/api/endpoints/channels/timeline.ts index 292f21b63d..00a7cd86d5 100644 --- a/src/server/api/endpoints/channels/timeline.ts +++ b/src/server/api/endpoints/channels/timeline.ts @@ -87,7 +87,7 @@ export default define(meta, async (ps, user) => { //#region Construct query const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.channelId = :channelId', { channelId: channel.id }) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/clips/notes.ts b/src/server/api/endpoints/clips/notes.ts index 86d1e507f4..676629c328 100644 --- a/src/server/api/endpoints/clips/notes.ts +++ b/src/server/api/endpoints/clips/notes.ts @@ -71,7 +71,7 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ clipQuery.getQuery() })`) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts index 708ce38c0e..30e6e92fec 100644 --- a/src/server/api/endpoints/notes.ts +++ b/src/server/api/endpoints/notes.ts @@ -76,7 +76,7 @@ export default define(meta, async (ps) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.visibility = 'public'`) .andWhere(`note.localOnly = FALSE`) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts index a8b239e445..072a25e024 100644 --- a/src/server/api/endpoints/notes/children.ts +++ b/src/server/api/endpoints/notes/children.ts @@ -64,7 +64,7 @@ export default define(meta, async (ps, user) => { })); })); })) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/featured.ts b/src/server/api/endpoints/notes/featured.ts index 6c416b1c04..b3dffa4272 100644 --- a/src/server/api/endpoints/notes/featured.ts +++ b/src/server/api/endpoints/notes/featured.ts @@ -49,7 +49,7 @@ export default define(meta, async (ps, user) => { .andWhere(`note.score > 0`) .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts index 985760bd9d..64fc3cbf6c 100644 --- a/src/server/api/endpoints/notes/global-timeline.ts +++ b/src/server/api/endpoints/notes/global-timeline.ts @@ -79,7 +79,7 @@ export default define(meta, async (ps, user) => { ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.visibility = \'public\'') .andWhere('note.channelId IS NULL') - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index 69f2a7c107..19c4593f5b 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -127,7 +127,7 @@ export default define(meta, async (ps, user) => { qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id }) .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); })) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts index 9e1c081966..546d3619f7 100644 --- a/src/server/api/endpoints/notes/local-timeline.ts +++ b/src/server/api/endpoints/notes/local-timeline.ts @@ -96,7 +96,7 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts index 83e890d9ad..56640ec1ab 100644 --- a/src/server/api/endpoints/notes/mentions.ts +++ b/src/server/api/endpoints/notes/mentions.ts @@ -63,7 +63,7 @@ export default define(meta, async (ps, user) => { .where(`:meId = ANY(note.mentions)`, { meId: user.id }) .orWhere(`:meId = ANY(note.visibleUserIds)`, { meId: user.id }); })) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/renotes.ts b/src/server/api/endpoints/notes/renotes.ts index f528197220..dcda213918 100644 --- a/src/server/api/endpoints/notes/renotes.ts +++ b/src/server/api/endpoints/notes/renotes.ts @@ -68,7 +68,7 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts index 5ac663d77a..6f33e2f233 100644 --- a/src/server/api/endpoints/notes/replies.ts +++ b/src/server/api/endpoints/notes/replies.ts @@ -59,7 +59,7 @@ export const meta = { export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere('note.replyId = :replyId', { replyId: ps.noteId }) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts index d878f379c3..47b41d9294 100644 --- a/src/server/api/endpoints/notes/search-by-tag.ts +++ b/src/server/api/endpoints/notes/search-by-tag.ts @@ -95,7 +95,7 @@ export const meta = { export default define(meta, async (ps, me) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts index ae0e9242a6..230d2b0294 100644 --- a/src/server/api/endpoints/notes/search.ts +++ b/src/server/api/endpoints/notes/search.ts @@ -79,7 +79,7 @@ export default define(meta, async (ps, me) => { query .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index a158bcd3f0..d025944cc2 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -120,7 +120,7 @@ export default define(meta, async (ps, user) => { .where('note.userId = :meId', { meId: user.id }); if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); })) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts index 040f017fd5..9ffb38bddc 100644 --- a/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/src/server/api/endpoints/notes/user-list-timeline.ts @@ -130,7 +130,7 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.userId IN (${ listQuery.getQuery() })`) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts index 91d1d7f4dd..fc5998c378 100644 --- a/src/server/api/endpoints/users/notes.ts +++ b/src/server/api/endpoints/users/notes.ts @@ -131,7 +131,7 @@ export default define(meta, async (ps, me) => { //#region Construct query const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.userId = :userId', { userId: user.id }) - .leftJoinAndSelect('note.user', 'user') + .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') -- cgit v1.2.3-freya From 8050352ad88798be222f735a3217367acaee277f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 15:14:03 +0900 Subject: perf: 各ストリーミング接続ごとにポーリングしないように MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/api/endpoints/channels/follow.ts | 3 ++ src/server/api/endpoints/channels/unfollow.ts | 3 ++ src/server/api/endpoints/i/update.ts | 3 +- src/server/api/endpoints/mute/create.ts | 3 ++ src/server/api/endpoints/mute/delete.ts | 3 ++ src/server/api/stream/index.ts | 57 +++++++++++++++++++-------- src/services/blocking/create.ts | 12 ++++-- src/services/following/create.ts | 7 +++- src/services/following/delete.ts | 7 +++- src/services/following/requests/reject.ts | 7 +++- src/services/stream.ts | 5 +++ 11 files changed, 83 insertions(+), 27 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/server/api/endpoints/channels/follow.ts b/src/server/api/endpoints/channels/follow.ts index bf2f2bbb57..11c6e37ff7 100644 --- a/src/server/api/endpoints/channels/follow.ts +++ b/src/server/api/endpoints/channels/follow.ts @@ -4,6 +4,7 @@ import define from '../../define'; import { ApiError } from '../../error'; import { Channels, ChannelFollowings } from '../../../../models'; import { genId } from '../../../../misc/gen-id'; +import { publishUserEvent } from '../../../../services/stream'; export const meta = { tags: ['channels'], @@ -42,4 +43,6 @@ export default define(meta, async (ps, user) => { followerId: user.id, followeeId: channel.id, }); + + publishUserEvent(user.id, 'followChannel', channel); }); diff --git a/src/server/api/endpoints/channels/unfollow.ts b/src/server/api/endpoints/channels/unfollow.ts index 8cab5c36a6..3eb0f1519b 100644 --- a/src/server/api/endpoints/channels/unfollow.ts +++ b/src/server/api/endpoints/channels/unfollow.ts @@ -3,6 +3,7 @@ import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { ApiError } from '../../error'; import { Channels, ChannelFollowings } from '../../../../models'; +import { publishUserEvent } from '../../../../services/stream'; export const meta = { tags: ['channels'], @@ -39,4 +40,6 @@ export default define(meta, async (ps, user) => { followerId: user.id, followeeId: channel.id, }); + + publishUserEvent(user.id, 'unfollowChannel', channel); }); diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index a1faf8f1c2..92be2e9e6d 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -1,6 +1,6 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; -import { publishMainStream } from '../../../../services/stream'; +import { publishMainStream, publishUserEvent } from '../../../../services/stream'; import acceptAllFollowRequests from '../../../../services/following/requests/accept-all'; import { publishToFollowers } from '../../../../services/i/update'; import define from '../../define'; @@ -317,6 +317,7 @@ export default define(meta, async (ps, user, token) => { // Publish meUpdated event publishMainStream(user.id, 'meUpdated', iObj); + publishUserEvent(user.id, 'updateUserProfile', await UserProfiles.findOne(user.id)); // 鍵垢を解除したとき、溜まっていたフォローリクエストがあるならすべて承認 if (user.isLocked && ps.isLocked === false) { diff --git a/src/server/api/endpoints/mute/create.ts b/src/server/api/endpoints/mute/create.ts index 437ad96107..ebfc6028ed 100644 --- a/src/server/api/endpoints/mute/create.ts +++ b/src/server/api/endpoints/mute/create.ts @@ -6,6 +6,7 @@ import { getUser } from '../../common/getters'; import { genId } from '../../../../misc/gen-id'; import { Mutings, NoteWatchings } from '../../../../models'; import { Muting } from '../../../../models/entities/muting'; +import { publishUserEvent } from '../../../../services/stream'; export const meta = { desc: { @@ -82,6 +83,8 @@ export default define(meta, async (ps, user) => { muteeId: mutee.id, } as Muting); + publishUserEvent(user.id, 'mute', mutee); + NoteWatchings.delete({ userId: muter.id, noteUserId: mutee.id diff --git a/src/server/api/endpoints/mute/delete.ts b/src/server/api/endpoints/mute/delete.ts index 217352acb4..67a59e3ae4 100644 --- a/src/server/api/endpoints/mute/delete.ts +++ b/src/server/api/endpoints/mute/delete.ts @@ -4,6 +4,7 @@ import define from '../../define'; import { ApiError } from '../../error'; import { getUser } from '../../common/getters'; import { Mutings } from '../../../../models'; +import { publishUserEvent } from '../../../../services/stream'; export const meta = { desc: { @@ -76,4 +77,6 @@ export default define(meta, async (ps, user) => { await Mutings.delete({ id: exist.id }); + + publishUserEvent(user.id, 'unmute', mutee); }); diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts index a94923484d..748e894f83 100644 --- a/src/server/api/stream/index.ts +++ b/src/server/api/stream/index.ts @@ -30,10 +30,6 @@ export default class Connection { public subscriber: EventEmitter; private channels: Channel[] = []; private subscribingNotes: any = {}; - private followingClock: ReturnType; - private mutingClock: ReturnType; - private followingChannelsClock: ReturnType; - private userProfileClock: ReturnType; constructor( wsConnection: websocket.connection, @@ -52,19 +48,51 @@ export default class Connection { this.onBroadcastMessage(type, body); }); - // TODO: reidsでイベントをもらうようにし、ポーリングはしないようにする if (this.user) { this.updateFollowing(); - this.followingClock = setInterval(this.updateFollowing, 5000); - this.updateMuting(); - this.mutingClock = setInterval(this.updateMuting, 5000); - this.updateFollowingChannels(); - this.followingChannelsClock = setInterval(this.updateFollowingChannels, 5000); - this.updateUserProfile(); - this.userProfileClock = setInterval(this.updateUserProfile, 5000); + + this.subscriber.on(`user:${this.user.id}`, ({ type, body }) => { + this.onUserEvent(type, body); + }); + } + } + + @autobind + private onUserEvent(type: string, body: any) { + switch (type) { + case 'follow': + this.following.add(body.id); + break; + + case 'unfollow': + this.following.delete(body.id); + break; + + case 'mute': + this.muting.add(body.id); + break; + + case 'unmute': + this.muting.delete(body.id); + break; + + case 'followChannel': + this.followingChannels.add(body.id); + break; + + case 'unfollowChannel': + this.followingChannels.delete(body.id); + break; + + case 'updateUserProfile': + this.userProfile = body; + break; + + default: + break; } } @@ -354,10 +382,5 @@ export default class Connection { for (const c of this.channels.filter(c => c.dispose)) { if (c.dispose) c.dispose(); } - - if (this.followingClock) clearInterval(this.followingClock); - if (this.mutingClock) clearInterval(this.mutingClock); - if (this.followingChannelsClock) clearInterval(this.followingChannelsClock); - if (this.userProfileClock) clearInterval(this.userProfileClock); } } diff --git a/src/services/blocking/create.ts b/src/services/blocking/create.ts index def4f33585..4f0238db91 100644 --- a/src/services/blocking/create.ts +++ b/src/services/blocking/create.ts @@ -1,4 +1,4 @@ -import { publishMainStream } from '../stream'; +import { publishMainStream, publishUserEvent } from '../stream'; import { renderActivity } from '../../remote/activitypub/renderer'; import renderFollow from '../../remote/activitypub/renderer/follow'; import renderUndo from '../../remote/activitypub/renderer/undo'; @@ -55,7 +55,10 @@ async function cancelRequest(follower: User, followee: User) { if (Users.isLocalUser(follower)) { Users.pack(followee, follower, { detail: true - }).then(packed => publishMainStream(follower.id, 'unfollow', packed)); + }).then(packed => { + publishUserEvent(follower.id, 'unfollow', packed); + publishMainStream(follower.id, 'unfollow', packed); + }); } // リモートにフォローリクエストをしていたらUndoFollow送信 @@ -97,7 +100,10 @@ async function unFollow(follower: User, followee: User) { if (Users.isLocalUser(follower)) { Users.pack(followee, follower, { detail: true - }).then(packed => publishMainStream(follower.id, 'unfollow', packed)); + }).then(packed => { + publishUserEvent(follower.id, 'unfollow', packed); + publishMainStream(follower.id, 'unfollow', packed); + }); } // リモートにフォローをしていたらUndoFollow送信 diff --git a/src/services/following/create.ts b/src/services/following/create.ts index 6bc98aee87..eb6699b0bf 100644 --- a/src/services/following/create.ts +++ b/src/services/following/create.ts @@ -1,4 +1,4 @@ -import { publishMainStream } from '../stream'; +import { publishMainStream, publishUserEvent } from '../stream'; import { renderActivity } from '../../remote/activitypub/renderer'; import renderFollow from '../../remote/activitypub/renderer/follow'; import renderAccept from '../../remote/activitypub/renderer/accept'; @@ -88,7 +88,10 @@ export async function insertFollowingDoc(followee: User, follower: User) { if (Users.isLocalUser(follower)) { Users.pack(followee, follower, { detail: true - }).then(packed => publishMainStream(follower.id, 'follow', packed)); + }).then(packed => { + publishUserEvent(follower.id, 'follow', packed); + publishMainStream(follower.id, 'follow', packed); + }); } // Publish followed event diff --git a/src/services/following/delete.ts b/src/services/following/delete.ts index 8821611515..32c47ea7f4 100644 --- a/src/services/following/delete.ts +++ b/src/services/following/delete.ts @@ -1,4 +1,4 @@ -import { publishMainStream } from '../stream'; +import { publishMainStream, publishUserEvent } from '../stream'; import { renderActivity } from '../../remote/activitypub/renderer'; import renderFollow from '../../remote/activitypub/renderer/follow'; import renderUndo from '../../remote/activitypub/renderer/undo'; @@ -30,7 +30,10 @@ export default async function(follower: User, followee: User, silent = false) { if (!silent && Users.isLocalUser(follower)) { Users.pack(followee, follower, { detail: true - }).then(packed => publishMainStream(follower.id, 'unfollow', packed)); + }).then(packed => { + publishUserEvent(follower.id, 'unfollow', packed); + publishMainStream(follower.id, 'unfollow', packed); + }); } if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) { diff --git a/src/services/following/requests/reject.ts b/src/services/following/requests/reject.ts index 9a8b14bbfd..d8d3788088 100644 --- a/src/services/following/requests/reject.ts +++ b/src/services/following/requests/reject.ts @@ -2,7 +2,7 @@ import { renderActivity } from '../../../remote/activitypub/renderer'; import renderFollow from '../../../remote/activitypub/renderer/follow'; import renderReject from '../../../remote/activitypub/renderer/reject'; import { deliver } from '../../../queue'; -import { publishMainStream } from '../../stream'; +import { publishMainStream, publishUserEvent } from '../../stream'; import { User, ILocalUser } from '../../../models/entities/user'; import { Users, FollowRequests, Followings } from '../../../models'; import { decrementFollowing } from '../delete'; @@ -39,5 +39,8 @@ export default async function(followee: User, follower: User) { Users.pack(followee, follower, { detail: true - }).then(packed => publishMainStream(follower.id, 'unfollow', packed)); + }).then(packed => { + publishUserEvent(follower.id, 'unfollow', packed); + publishMainStream(follower.id, 'unfollow', packed); + }); } diff --git a/src/services/stream.ts b/src/services/stream.ts index d833d700fe..75385847ce 100644 --- a/src/services/stream.ts +++ b/src/services/stream.ts @@ -20,6 +20,10 @@ class Publisher { })); } + public publishUserEvent = (userId: User['id'], type: string, value?: any): void => { + this.publish(`user:${userId}`, type, typeof value === 'undefined' ? null : value); + } + public publishBroadcastStream = (type: string, value?: any): void => { this.publish('broadcast', type, typeof value === 'undefined' ? null : value); } @@ -84,6 +88,7 @@ const publisher = new Publisher(); export default publisher; +export const publishUserEvent = publisher.publishUserEvent; export const publishBroadcastStream = publisher.publishBroadcastStream; export const publishMainStream = publisher.publishMainStream; export const publishDriveStream = publisher.publishDriveStream; -- cgit v1.2.3-freya From 630464f38d2524ddc5d11d2abd4fddcccc4240d4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 15:35:02 +0900 Subject: Revert "perf: Reduce database query" This reverts commit 87c8f9ff953499340496e9c5db09c93eaff08851. --- src/client/components/note-detailed.vue | 10 +-- src/client/components/note.vue | 10 +-- src/client/ui/chat/note.vue | 10 +-- src/server/api/endpoints/notes/mentions.ts | 6 +- src/server/api/stream/index.ts | 38 +++-------- src/services/note/read-mention.ts | 29 -------- src/services/note/read-specified-note.ts | 29 -------- src/services/note/read.ts | 105 +++++++++++++++++++++++++++++ 8 files changed, 123 insertions(+), 114 deletions(-) delete mode 100644 src/services/note/read-mention.ts delete mode 100644 src/services/note/read-specified-note.ts create mode 100644 src/services/note/read.ts (limited to 'src/server/api/endpoints') diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue index 4ad3d2d898..1ef3f43389 100644 --- a/src/client/components/note-detailed.vue +++ b/src/client/components/note-detailed.vue @@ -350,15 +350,7 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send('sn', { id: this.appearNote.id }); - if (this.appearNote.userId !== this.$i.id) { - if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) { - this.connection.send('readMention', { id: this.appearNote.id }); - } - if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) { - this.connection.send('readSpecifiedNote', { id: this.appearNote.id }); - } - } + this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/client/components/note.vue b/src/client/components/note.vue index 3b59afd71d..65e09b7802 100644 --- a/src/client/components/note.vue +++ b/src/client/components/note.vue @@ -325,15 +325,7 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send('sn', { id: this.appearNote.id }); - if (this.appearNote.userId !== this.$i.id) { - if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) { - this.connection.send('readMention', { id: this.appearNote.id }); - } - if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) { - this.connection.send('readSpecifiedNote', { id: this.appearNote.id }); - } - } + this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue index 29bc61d9c5..5a4a13d889 100644 --- a/src/client/ui/chat/note.vue +++ b/src/client/ui/chat/note.vue @@ -325,15 +325,7 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send('sn', { id: this.appearNote.id }); - if (this.appearNote.userId !== this.$i.id) { - if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) { - this.connection.send('readMention', { id: this.appearNote.id }); - } - if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) { - this.connection.send('readSpecifiedNote', { id: this.appearNote.id }); - } - } + this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts index 56640ec1ab..30844774e0 100644 --- a/src/server/api/endpoints/notes/mentions.ts +++ b/src/server/api/endpoints/notes/mentions.ts @@ -1,12 +1,12 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; +import read from '../../../../services/note/read'; import { Notes, Followings } from '../../../../models'; import { generateVisibilityQuery } from '../../common/generate-visibility-query'; import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; import { makePaginationQuery } from '../../common/make-pagination-query'; import { Brackets } from 'typeorm'; -import { readMention } from '../../../../services/note/read-mention'; export const meta = { desc: { @@ -83,7 +83,9 @@ export default define(meta, async (ps, user) => { const mentions = await query.take(ps.limit!).getMany(); - readMention(user.id, mentions.map(n => n.id)); + for (const note of mentions) { + read(user.id, note.id); + } return await Notes.packMany(mentions, user); }); diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts index 748e894f83..f67faee1ce 100644 --- a/src/server/api/stream/index.ts +++ b/src/server/api/stream/index.ts @@ -2,6 +2,7 @@ import autobind from 'autobind-decorator'; import * as websocket from 'websocket'; import { readNotification } from '../common/read-notification'; import call from '../call'; +import readNote from '../../../services/note/read'; import Channel from './channel'; import channels from './channels'; import { EventEmitter } from 'events'; @@ -13,8 +14,6 @@ import { AccessToken } from '../../../models/entities/access-token'; import { UserProfile } from '../../../models/entities/user-profile'; import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '../../../services/stream'; import { UserGroup } from '../../../models/entities/user-group'; -import { readMention } from '../../../services/note/read-mention'; -import { readSpecifiedNote } from '../../../services/note/read-specified-note'; /** * Main stream connection @@ -116,10 +115,9 @@ export default class Connection { switch (type) { case 'api': this.onApiRequest(body); break; case 'readNotification': this.onReadNotification(body); break; - case 'readMention': this.onReadMention(body); break; - case 'readSpecifiedNote': this.onReadSpecifiedNote(body); break; - case 'subNote': this.onSubscribeNote(body); break; - case 'sn': this.onSubscribeNote(body); break; // alias + case 'subNote': this.onSubscribeNote(body, true); break; + case 'sn': this.onSubscribeNote(body, true); break; // alias + case 's': this.onSubscribeNote(body, false); break; case 'unsubNote': this.onUnsubscribeNote(body); break; case 'un': this.onUnsubscribeNote(body); break; // alias case 'connect': this.onChannelConnectRequested(body); break; @@ -172,31 +170,11 @@ export default class Connection { readNotification(this.user!.id, [payload.id]); } - @autobind - private onReadMention(payload: any) { - if (!payload.id) return; - if (this.user) { - // TODO: ある程度まとめてreadMentionするようにする - // 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadMentionに渡すような実装にする - readMention(this.user.id, [payload.id]); - } - } - - @autobind - private onReadSpecifiedNote(payload: any) { - if (!payload.id) return; - if (this.user) { - // TODO: ある程度まとめてreadSpecifiedNoteするようにする - // 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadSpecifiedNoteに渡すような実装にする - readSpecifiedNote(this.user.id, [payload.id]); - } - } - /** * 投稿購読要求時 */ @autobind - private onSubscribeNote(payload: any) { + private onSubscribeNote(payload: any, read: boolean) { if (!payload.id) return; if (this.subscribingNotes[payload.id] == null) { @@ -208,6 +186,12 @@ export default class Connection { if (this.subscribingNotes[payload.id] === 1) { this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage); } + + if (this.user && read) { + // TODO: クライアントでタイムライン読み込みなどすると、一度に大量のreadNoteが発生しクエリ数がすごいことになるので、ある程度まとめてreadNoteするようにする + // 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadNoteに渡すような実装にする + readNote(this.user.id, payload.id); + } } /** diff --git a/src/services/note/read-mention.ts b/src/services/note/read-mention.ts deleted file mode 100644 index 2a668ecd6c..0000000000 --- a/src/services/note/read-mention.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { publishMainStream } from '../stream'; -import { Note } from '../../models/entities/note'; -import { User } from '../../models/entities/user'; -import { NoteUnreads } from '../../models'; -import { In } from 'typeorm'; - -/** - * Mark a mention note as read - */ -export async function readMention( - userId: User['id'], - noteIds: Note['id'][] -) { - // Remove the records - await NoteUnreads.delete({ - userId: userId, - noteId: In(noteIds), - }); - - const mentionsCount = await NoteUnreads.count({ - userId: userId, - isMentioned: true - }); - - if (mentionsCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadMentions'); - } -} diff --git a/src/services/note/read-specified-note.ts b/src/services/note/read-specified-note.ts deleted file mode 100644 index 0fcb66bf98..0000000000 --- a/src/services/note/read-specified-note.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { publishMainStream } from '../stream'; -import { Note } from '../../models/entities/note'; -import { User } from '../../models/entities/user'; -import { NoteUnreads } from '../../models'; -import { In } from 'typeorm'; - -/** - * Mark a specified note as read - */ -export async function readSpecifiedNote( - userId: User['id'], - noteIds: Note['id'][] -) { - // Remove the records - await NoteUnreads.delete({ - userId: userId, - noteId: In(noteIds), - }); - - const specifiedCount = await NoteUnreads.count({ - userId: userId, - isSpecified: true - }); - - if (specifiedCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); - } -} diff --git a/src/services/note/read.ts b/src/services/note/read.ts new file mode 100644 index 0000000000..5a39ab30b7 --- /dev/null +++ b/src/services/note/read.ts @@ -0,0 +1,105 @@ +import { publishMainStream } from '../stream'; +import { Note } from '../../models/entities/note'; +import { User } from '../../models/entities/user'; +import { NoteUnreads, Antennas, AntennaNotes, Users } from '../../models'; +import { Not, IsNull } from 'typeorm'; + +/** + * Mark a note as read + */ +export default async function( + userId: User['id'], + noteId: Note['id'] +) { + async function careNoteUnreads() { + const exist = await NoteUnreads.findOne({ + userId: userId, + noteId: noteId, + }); + + if (!exist) return; + + // Remove the record + await NoteUnreads.delete({ + userId: userId, + noteId: noteId, + }); + + if (exist.isMentioned) { + NoteUnreads.count({ + userId: userId, + isMentioned: true + }).then(mentionsCount => { + if (mentionsCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllUnreadMentions'); + } + }); + } + + if (exist.isSpecified) { + NoteUnreads.count({ + userId: userId, + isSpecified: true + }).then(specifiedCount => { + if (specifiedCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); + } + }); + } + + if (exist.noteChannelId) { + NoteUnreads.count({ + userId: userId, + noteChannelId: Not(IsNull()) + }).then(channelNoteCount => { + if (channelNoteCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllChannels'); + } + }); + } + } + + async function careAntenna() { + const beforeUnread = await Users.getHasUnreadAntenna(userId); + if (!beforeUnread) return; + + const antennas = await Antennas.find({ userId }); + + await Promise.all(antennas.map(async antenna => { + const countBefore = await AntennaNotes.count({ + antennaId: antenna.id, + read: false + }); + + if (countBefore === 0) return; + + await AntennaNotes.update({ + antennaId: antenna.id, + noteId: noteId + }, { + read: true + }); + + const countAfter = await AntennaNotes.count({ + antennaId: antenna.id, + read: false + }); + + if (countAfter === 0) { + publishMainStream(userId, 'readAntenna', antenna); + } + })); + + Users.getHasUnreadAntenna(userId).then(unread => { + if (!unread) { + publishMainStream(userId, 'readAllAntennas'); + } + }); + } + + careNoteUnreads(); + careAntenna(); +} -- cgit v1.2.3-freya From 667d58bad4544d6e9dc75cfc4e6216179e2bc1aa Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 17:38:09 +0900 Subject: better note read handling --- src/client/components/note-detailed.vue | 3 +- src/client/components/note.vue | 3 +- src/client/ui/chat/note.vue | 3 +- src/daemons/janitor.ts | 2 + src/server/api/endpoints/notes/mentions.ts | 4 +- src/server/api/stream/channels/antenna.ts | 2 + src/server/api/stream/channels/channel.ts | 2 + src/server/api/stream/channels/global-timeline.ts | 2 + src/server/api/stream/channels/hashtag.ts | 2 + src/server/api/stream/channels/home-timeline.ts | 2 + src/server/api/stream/channels/hybrid-timeline.ts | 2 + src/server/api/stream/channels/local-timeline.ts | 2 + src/server/api/stream/channels/main.ts | 8 ++- src/server/api/stream/index.ts | 58 +++++++++++++--- src/services/note/read.ts | 80 +++++++++-------------- 15 files changed, 109 insertions(+), 66 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue index 1ef3f43389..ea26d31100 100644 --- a/src/client/components/note-detailed.vue +++ b/src/client/components/note-detailed.vue @@ -350,7 +350,8 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); + // TODO: このノートがストリーミング経由で流れてきた場合のみ sr する + this.connection.send(document.body.contains(this.$el) ? 'sr' : 's', { id: this.appearNote.id }); if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/client/components/note.vue b/src/client/components/note.vue index 65e09b7802..70f49fef7e 100644 --- a/src/client/components/note.vue +++ b/src/client/components/note.vue @@ -325,7 +325,8 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); + // TODO: このノートがストリーミング経由で流れてきた場合のみ sr する + this.connection.send(document.body.contains(this.$el) ? 'sr' : 's', { id: this.appearNote.id }); if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue index 5a4a13d889..97275875ca 100644 --- a/src/client/ui/chat/note.vue +++ b/src/client/ui/chat/note.vue @@ -325,7 +325,8 @@ export default defineComponent({ capture(withHandler = false) { if (this.$i) { - this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); + // TODO: このノートがストリーミング経由で流れてきた場合のみ sr する + this.connection.send(document.body.contains(this.$el) ? 'sr' : 's', { id: this.appearNote.id }); if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); } }, diff --git a/src/daemons/janitor.ts b/src/daemons/janitor.ts index 462ebf915c..c079086427 100644 --- a/src/daemons/janitor.ts +++ b/src/daemons/janitor.ts @@ -1,3 +1,5 @@ +// TODO: 消したい + const interval = 30 * 60 * 1000; import { AttestationChallenges } from '../models'; import { LessThan } from 'typeorm'; diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts index 30844774e0..30368ea578 100644 --- a/src/server/api/endpoints/notes/mentions.ts +++ b/src/server/api/endpoints/notes/mentions.ts @@ -83,9 +83,7 @@ export default define(meta, async (ps, user) => { const mentions = await query.take(ps.limit!).getMany(); - for (const note of mentions) { - read(user.id, note.id); - } + read(user.id, mentions.map(note => note.id)); return await Notes.packMany(mentions, user); }); diff --git a/src/server/api/stream/channels/antenna.ts b/src/server/api/stream/channels/antenna.ts index b5a792f814..36a474f2ac 100644 --- a/src/server/api/stream/channels/antenna.ts +++ b/src/server/api/stream/channels/antenna.ts @@ -27,6 +27,8 @@ export default class extends Channel { // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isMutedUserRelated(note, this.muting)) return; + this.connection.cacheNote(note); + this.send('note', note); } else { this.send(type, body); diff --git a/src/server/api/stream/channels/channel.ts b/src/server/api/stream/channels/channel.ts index aa570d1ef4..47a52465b2 100644 --- a/src/server/api/stream/channels/channel.ts +++ b/src/server/api/stream/channels/channel.ts @@ -43,6 +43,8 @@ export default class extends Channel { // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isMutedUserRelated(note, this.muting)) return; + this.connection.cacheNote(note); + this.send('note', note); } diff --git a/src/server/api/stream/channels/global-timeline.ts b/src/server/api/stream/channels/global-timeline.ts index 8c97e67226..8353f45323 100644 --- a/src/server/api/stream/channels/global-timeline.ts +++ b/src/server/api/stream/channels/global-timeline.ts @@ -56,6 +56,8 @@ export default class extends Channel { // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + this.connection.cacheNote(note); + this.send('note', note); } diff --git a/src/server/api/stream/channels/hashtag.ts b/src/server/api/stream/channels/hashtag.ts index 41447039d5..1b7f8efcc1 100644 --- a/src/server/api/stream/channels/hashtag.ts +++ b/src/server/api/stream/channels/hashtag.ts @@ -37,6 +37,8 @@ export default class extends Channel { // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isMutedUserRelated(note, this.muting)) return; + this.connection.cacheNote(note); + this.send('note', note); } diff --git a/src/server/api/stream/channels/home-timeline.ts b/src/server/api/stream/channels/home-timeline.ts index 6cfa6eae7b..59ba31c316 100644 --- a/src/server/api/stream/channels/home-timeline.ts +++ b/src/server/api/stream/channels/home-timeline.ts @@ -64,6 +64,8 @@ export default class extends Channel { // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + this.connection.cacheNote(note); + this.send('note', note); } diff --git a/src/server/api/stream/channels/hybrid-timeline.ts b/src/server/api/stream/channels/hybrid-timeline.ts index a9e577cacb..9715e9973f 100644 --- a/src/server/api/stream/channels/hybrid-timeline.ts +++ b/src/server/api/stream/channels/hybrid-timeline.ts @@ -73,6 +73,8 @@ export default class extends Channel { // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + this.connection.cacheNote(note); + this.send('note', note); } diff --git a/src/server/api/stream/channels/local-timeline.ts b/src/server/api/stream/channels/local-timeline.ts index a3a5e491fc..e159c72d60 100644 --- a/src/server/api/stream/channels/local-timeline.ts +++ b/src/server/api/stream/channels/local-timeline.ts @@ -58,6 +58,8 @@ export default class extends Channel { // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + this.connection.cacheNote(note); + this.send('note', note); } diff --git a/src/server/api/stream/channels/main.ts b/src/server/api/stream/channels/main.ts index b69c2ec355..780bc0b89f 100644 --- a/src/server/api/stream/channels/main.ts +++ b/src/server/api/stream/channels/main.ts @@ -18,18 +18,22 @@ export default class extends Channel { case 'notification': { if (this.muting.has(body.userId)) return; if (body.note && body.note.isHidden) { - body.note = await Notes.pack(body.note.id, this.user, { + const note = await Notes.pack(body.note.id, this.user, { detail: true }); + this.connection.cacheNote(note); + body.note = note; } break; } case 'mention': { if (this.muting.has(body.userId)) return; if (body.isHidden) { - body = await Notes.pack(body.id, this.user, { + const note = await Notes.pack(body.id, this.user, { detail: true }); + this.connection.cacheNote(note); + body = note; } break; } diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts index f67faee1ce..99ae558696 100644 --- a/src/server/api/stream/index.ts +++ b/src/server/api/stream/index.ts @@ -14,6 +14,7 @@ import { AccessToken } from '../../../models/entities/access-token'; 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'; /** * Main stream connection @@ -29,6 +30,7 @@ export default class Connection { public subscriber: EventEmitter; private channels: Channel[] = []; private subscribingNotes: any = {}; + private cachedNotes: PackedNote[] = []; constructor( wsConnection: websocket.connection, @@ -115,9 +117,9 @@ export default class Connection { switch (type) { case 'api': this.onApiRequest(body); break; case 'readNotification': this.onReadNotification(body); break; - case 'subNote': this.onSubscribeNote(body, true); break; - case 'sn': this.onSubscribeNote(body, true); break; // alias - case 's': this.onSubscribeNote(body, false); break; + case 'subNote': this.onSubscribeNote(body); break; + case 's': this.onSubscribeNote(body); break; // alias + case 'sr': this.onSubscribeNote(body); this.readNote(body); break; case 'unsubNote': this.onUnsubscribeNote(body); break; case 'un': this.onUnsubscribeNote(body); break; // alias case 'connect': this.onChannelConnectRequested(body); break; @@ -138,6 +140,48 @@ export default class Connection { this.sendMessageToWs(type, body); } + @autobind + public cacheNote(note: PackedNote) { + const add = (note: PackedNote) => { + const existIndex = this.cachedNotes.findIndex(n => n.id === note.id); + if (existIndex > -1) { + this.cachedNotes[existIndex] = note; + return; + } + + this.cachedNotes.unshift(note); + if (this.cachedNotes.length > 32) { + this.cachedNotes.splice(32); + } + }; + + add(note); + if (note.reply) add(note.reply); + if (note.renote) add(note.renote); + } + + @autobind + private readNote(body: any) { + const id = body.id; + + const note = this.cachedNotes.find(n => n.id === id); + if (note == null) return; + + if (this.user && (note.userId !== this.user.id)) { + if (note.mentions && note.mentions.includes(this.user.id)) { + readNote(this.user.id, [note]); + } else if (note.visibleUserIds && note.visibleUserIds.includes(this.user.id)) { + readNote(this.user.id, [note]); + } + + if (this.followingChannels.has(note.channelId)) { + // TODO + } + + // TODO: アンテナの既読処理 + } + } + /** * APIリクエスト要求時 */ @@ -174,7 +218,7 @@ export default class Connection { * 投稿購読要求時 */ @autobind - private onSubscribeNote(payload: any, read: boolean) { + private onSubscribeNote(payload: any) { if (!payload.id) return; if (this.subscribingNotes[payload.id] == null) { @@ -186,12 +230,6 @@ export default class Connection { if (this.subscribingNotes[payload.id] === 1) { this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage); } - - if (this.user && read) { - // TODO: クライアントでタイムライン読み込みなどすると、一度に大量のreadNoteが発生しクエリ数がすごいことになるので、ある程度まとめてreadNoteするようにする - // 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadNoteに渡すような実装にする - readNote(this.user.id, payload.id); - } } /** diff --git a/src/services/note/read.ts b/src/services/note/read.ts index 5a39ab30b7..35279db411 100644 --- a/src/services/note/read.ts +++ b/src/services/note/read.ts @@ -2,70 +2,54 @@ import { publishMainStream } from '../stream'; import { Note } from '../../models/entities/note'; import { User } from '../../models/entities/user'; import { NoteUnreads, Antennas, AntennaNotes, Users } from '../../models'; -import { Not, IsNull } from 'typeorm'; +import { Not, IsNull, In } from 'typeorm'; /** - * Mark a note as read + * Mark notes as read */ export default async function( userId: User['id'], - noteId: Note['id'] + noteIds: Note['id'][] ) { async function careNoteUnreads() { - const exist = await NoteUnreads.findOne({ - userId: userId, - noteId: noteId, - }); - - if (!exist) return; - // Remove the record await NoteUnreads.delete({ userId: userId, - noteId: noteId, + noteId: In(noteIds), }); - if (exist.isMentioned) { - NoteUnreads.count({ - userId: userId, - isMentioned: true - }).then(mentionsCount => { - if (mentionsCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadMentions'); - } - }); - } + NoteUnreads.count({ + userId: userId, + isMentioned: true + }).then(mentionsCount => { + if (mentionsCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllUnreadMentions'); + } + }); - if (exist.isSpecified) { - NoteUnreads.count({ - userId: userId, - isSpecified: true - }).then(specifiedCount => { - if (specifiedCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); - } - }); - } + NoteUnreads.count({ + userId: userId, + isSpecified: true + }).then(specifiedCount => { + if (specifiedCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); + } + }); - if (exist.noteChannelId) { - NoteUnreads.count({ - userId: userId, - noteChannelId: Not(IsNull()) - }).then(channelNoteCount => { - if (channelNoteCount === 0) { - // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllChannels'); - } - }); - } + NoteUnreads.count({ + userId: userId, + noteChannelId: Not(IsNull()) + }).then(channelNoteCount => { + if (channelNoteCount === 0) { + // 全て既読になったイベントを発行 + publishMainStream(userId, 'readAllChannels'); + } + }); } async function careAntenna() { - const beforeUnread = await Users.getHasUnreadAntenna(userId); - if (!beforeUnread) return; - const antennas = await Antennas.find({ userId }); await Promise.all(antennas.map(async antenna => { @@ -78,7 +62,7 @@ export default async function( await AntennaNotes.update({ antennaId: antenna.id, - noteId: noteId + noteId: In(noteIds) }, { read: true }); -- cgit v1.2.3-freya From c4c20bee7c58ea7330dbc890b9564bd100ac6e25 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 21 Mar 2021 21:27:09 +0900 Subject: wip #6441 --- src/models/entities/note-reaction.ts | 4 ++-- src/server/api/endpoints/admin/invite.ts | 2 +- src/server/api/endpoints/admin/promo/create.ts | 2 +- src/server/api/endpoints/auth/accept.ts | 2 +- src/server/api/endpoints/channels/follow.ts | 2 +- src/server/api/endpoints/clips/add-note.ts | 2 +- src/server/api/endpoints/i/read-announcement.ts | 2 +- src/server/api/endpoints/miauth/gen-token.ts | 2 +- src/server/api/endpoints/notes/favorites/create.ts | 2 +- src/server/api/endpoints/pages/like.ts | 2 +- src/server/api/endpoints/promo/read.ts | 2 +- src/server/api/endpoints/sw/register.ts | 2 +- src/server/api/endpoints/users/groups/create.ts | 2 +- .../api/endpoints/users/groups/invitations/accept.ts | 2 +- src/server/api/private/signin.ts | 4 ++-- src/services/add-note-to-antenna.ts | 2 +- src/services/blocking/create.ts | 2 +- src/services/following/create.ts | 2 +- src/services/i/pin.ts | 2 +- src/services/insert-moderation-log.ts | 2 +- src/services/messages/create.ts | 6 ++++-- src/services/note/create.ts | 2 +- src/services/note/polls/vote.ts | 2 +- src/services/note/reaction/create.ts | 16 ++++++++-------- src/services/note/unread.ts | 6 ++++-- src/services/note/watch.ts | 2 +- src/services/update-hashtag.ts | 4 ++-- src/services/user-list/push.ts | 2 +- 28 files changed, 44 insertions(+), 40 deletions(-) (limited to 'src/server/api/endpoints') diff --git a/src/models/entities/note-reaction.ts b/src/models/entities/note-reaction.ts index 69bb663fd3..674dc3639e 100644 --- a/src/models/entities/note-reaction.ts +++ b/src/models/entities/note-reaction.ts @@ -23,7 +23,7 @@ export class NoteReaction { onDelete: 'CASCADE' }) @JoinColumn() - public user: User | null; + public user?: User | null; @Index() @Column(id()) @@ -33,7 +33,7 @@ export class NoteReaction { onDelete: 'CASCADE' }) @JoinColumn() - public note: Note | null; + public note?: Note | null; // TODO: 対象noteのuserIdを非正規化したい(「受け取ったリアクション一覧」のようなものを(JOIN無しで)実装したいため) diff --git a/src/server/api/endpoints/admin/invite.ts b/src/server/api/endpoints/admin/invite.ts index 4529d16adf..987105791f 100644 --- a/src/server/api/endpoints/admin/invite.ts +++ b/src/server/api/endpoints/admin/invite.ts @@ -38,7 +38,7 @@ export default define(meta, async () => { chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns) }); - await RegistrationTickets.save({ + await RegistrationTickets.insert({ id: genId(), createdAt: new Date(), code, diff --git a/src/server/api/endpoints/admin/promo/create.ts b/src/server/api/endpoints/admin/promo/create.ts index 8b96d563c2..aa22e68ebd 100644 --- a/src/server/api/endpoints/admin/promo/create.ts +++ b/src/server/api/endpoints/admin/promo/create.ts @@ -53,7 +53,7 @@ export default define(meta, async (ps, user) => { throw new ApiError(meta.errors.alreadyPromoted); } - await PromoNotes.save({ + await PromoNotes.insert({ noteId: note.id, createdAt: new Date(), expiresAt: new Date(ps.expiresAt), diff --git a/src/server/api/endpoints/auth/accept.ts b/src/server/api/endpoints/auth/accept.ts index 6d4d31fa1e..444053a946 100644 --- a/src/server/api/endpoints/auth/accept.ts +++ b/src/server/api/endpoints/auth/accept.ts @@ -58,7 +58,7 @@ export default define(meta, async (ps, user) => { const now = new Date(); // Insert access token doc - await AccessTokens.save({ + await AccessTokens.insert({ id: genId(), createdAt: now, lastUsedAt: now, diff --git a/src/server/api/endpoints/channels/follow.ts b/src/server/api/endpoints/channels/follow.ts index 11c6e37ff7..c5976a8a34 100644 --- a/src/server/api/endpoints/channels/follow.ts +++ b/src/server/api/endpoints/channels/follow.ts @@ -37,7 +37,7 @@ export default define(meta, async (ps, user) => { throw new ApiError(meta.errors.noSuchChannel); } - await ChannelFollowings.save({ + await ChannelFollowings.insert({ id: genId(), createdAt: new Date(), followerId: user.id, diff --git a/src/server/api/endpoints/clips/add-note.ts b/src/server/api/endpoints/clips/add-note.ts index 4f5cc649e3..ee6a117b2d 100644 --- a/src/server/api/endpoints/clips/add-note.ts +++ b/src/server/api/endpoints/clips/add-note.ts @@ -68,7 +68,7 @@ export default define(meta, async (ps, user) => { throw new ApiError(meta.errors.alreadyClipped); } - await ClipNotes.save({ + await ClipNotes.insert({ id: genId(), noteId: note.id, clipId: clip.id diff --git a/src/server/api/endpoints/i/read-announcement.ts b/src/server/api/endpoints/i/read-announcement.ts index 4a4a021af9..d6acb3d2e6 100644 --- a/src/server/api/endpoints/i/read-announcement.ts +++ b/src/server/api/endpoints/i/read-announcement.ts @@ -52,7 +52,7 @@ export default define(meta, async (ps, user) => { } // Create read - await AnnouncementReads.save({ + await AnnouncementReads.insert({ id: genId(), createdAt: new Date(), announcementId: ps.announcementId, diff --git a/src/server/api/endpoints/miauth/gen-token.ts b/src/server/api/endpoints/miauth/gen-token.ts index 0634debb1e..401ed16389 100644 --- a/src/server/api/endpoints/miauth/gen-token.ts +++ b/src/server/api/endpoints/miauth/gen-token.ts @@ -52,7 +52,7 @@ export default define(meta, async (ps, user) => { const now = new Date(); // Insert access token doc - await AccessTokens.save({ + await AccessTokens.insert({ id: genId(), createdAt: now, lastUsedAt: now, diff --git a/src/server/api/endpoints/notes/favorites/create.ts b/src/server/api/endpoints/notes/favorites/create.ts index 952bbfd0eb..d66ce37a46 100644 --- a/src/server/api/endpoints/notes/favorites/create.ts +++ b/src/server/api/endpoints/notes/favorites/create.ts @@ -61,7 +61,7 @@ export default define(meta, async (ps, user) => { } // Create favorite - await NoteFavorites.save({ + await NoteFavorites.insert({ id: genId(), createdAt: new Date(), noteId: note.id, diff --git a/src/server/api/endpoints/pages/like.ts b/src/server/api/endpoints/pages/like.ts index 5c7e13f1c8..3fc2b6ca23 100644 --- a/src/server/api/endpoints/pages/like.ts +++ b/src/server/api/endpoints/pages/like.ts @@ -68,7 +68,7 @@ export default define(meta, async (ps, user) => { } // Create like - await PageLikes.save({ + await PageLikes.insert({ id: genId(), createdAt: new Date(), pageId: page.id, diff --git a/src/server/api/endpoints/promo/read.ts b/src/server/api/endpoints/promo/read.ts index 57eb0681e5..63c90e5d7f 100644 --- a/src/server/api/endpoints/promo/read.ts +++ b/src/server/api/endpoints/promo/read.ts @@ -46,7 +46,7 @@ export default define(meta, async (ps, user) => { return; } - await PromoReads.save({ + await PromoReads.insert({ id: genId(), createdAt: new Date(), noteId: note.id, diff --git a/src/server/api/endpoints/sw/register.ts b/src/server/api/endpoints/sw/register.ts index ceb70a9274..9fc70b5609 100644 --- a/src/server/api/endpoints/sw/register.ts +++ b/src/server/api/endpoints/sw/register.ts @@ -58,7 +58,7 @@ export default define(meta, async (ps, user) => { }; } - await SwSubscriptions.save({ + await SwSubscriptions.insert({ id: genId(), createdAt: new Date(), userId: user.id, diff --git a/src/server/api/endpoints/users/groups/create.ts b/src/server/api/endpoints/users/groups/create.ts index ca011d5cd6..78d2714874 100644 --- a/src/server/api/endpoints/users/groups/create.ts +++ b/src/server/api/endpoints/users/groups/create.ts @@ -39,7 +39,7 @@ export default define(meta, async (ps, user) => { } as UserGroup); // Push the owner - await UserGroupJoinings.save({ + await UserGroupJoinings.insert({ id: genId(), createdAt: new Date(), userId: user.id, diff --git a/src/server/api/endpoints/users/groups/invitations/accept.ts b/src/server/api/endpoints/users/groups/invitations/accept.ts index e86709f83b..2fa22bcf7e 100644 --- a/src/server/api/endpoints/users/groups/invitations/accept.ts +++ b/src/server/api/endpoints/users/groups/invitations/accept.ts @@ -52,7 +52,7 @@ export default define(meta, async (ps, user) => { } // Push the user - await UserGroupJoinings.save({ + await UserGroupJoinings.insert({ id: genId(), createdAt: new Date(), userId: user.id, diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts index 7a5efc6cc9..d8f2e6d516 100644 --- a/src/server/api/private/signin.ts +++ b/src/server/api/private/signin.ts @@ -53,7 +53,7 @@ export default async (ctx: Koa.Context) => { async function fail(status?: number, failure?: { error: string }) { // Append signin history - await Signins.save({ + await Signins.insert({ id: genId(), createdAt: new Date(), userId: user.id, @@ -198,7 +198,7 @@ export default async (ctx: Koa.Context) => { const challengeId = genId(); - await AttestationChallenges.save({ + await AttestationChallenges.insert({ userId: user.id, id: challengeId, challenge: hash(Buffer.from(challenge, 'utf-8')).toString('hex'), diff --git a/src/services/add-note-to-antenna.ts b/src/services/add-note-to-antenna.ts index 2c893488c3..3ba3d1eef5 100644 --- a/src/services/add-note-to-antenna.ts +++ b/src/services/add-note-to-antenna.ts @@ -10,7 +10,7 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: U // 通知しない設定になっているか、自分自身の投稿なら既読にする const read = !antenna.notify || (antenna.userId === noteUser.id); - AntennaNotes.save({ + AntennaNotes.insert({ id: genId(), antennaId: antenna.id, noteId: note.id, diff --git a/src/services/blocking/create.ts b/src/services/blocking/create.ts index 4f0238db91..dec48d26de 100644 --- a/src/services/blocking/create.ts +++ b/src/services/blocking/create.ts @@ -18,7 +18,7 @@ export default async function(blocker: User, blockee: User) { unFollow(blockee, blocker) ]); - await Blockings.save({ + await Blockings.insert({ id: genId(), createdAt: new Date(), blockerId: blocker.id, diff --git a/src/services/following/create.ts b/src/services/following/create.ts index eb6699b0bf..1ce75caca0 100644 --- a/src/services/following/create.ts +++ b/src/services/following/create.ts @@ -22,7 +22,7 @@ export async function insertFollowingDoc(followee: User, follower: User) { let alreadyFollowed = false; - await Followings.save({ + await Followings.insert({ id: genId(), createdAt: new Date(), followerId: follower.id, diff --git a/src/services/i/pin.ts b/src/services/i/pin.ts index 1ff5476b40..f727a10fb6 100644 --- a/src/services/i/pin.ts +++ b/src/services/i/pin.ts @@ -37,7 +37,7 @@ export async function addPinned(user: User, noteId: Note['id']) { throw new IdentifiableError('23f0cf4e-59a3-4276-a91d-61a5891c1514', 'That note has already been pinned.'); } - await UserNotePinings.save({ + await UserNotePinings.insert({ id: genId(), createdAt: new Date(), userId: user.id, diff --git a/src/services/insert-moderation-log.ts b/src/services/insert-moderation-log.ts index 33dab97259..87587d3bed 100644 --- a/src/services/insert-moderation-log.ts +++ b/src/services/insert-moderation-log.ts @@ -3,7 +3,7 @@ import { ModerationLogs } from '../models'; import { genId } from '../misc/gen-id'; export async function insertModerationLog(moderator: ILocalUser, type: string, info?: Record) { - await ModerationLogs.save({ + await ModerationLogs.insert({ id: genId(), createdAt: new Date(), userId: moderator.id, diff --git a/src/services/messages/create.ts b/src/services/messages/create.ts index 8646ce37fc..413266d029 100644 --- a/src/services/messages/create.ts +++ b/src/services/messages/create.ts @@ -14,7 +14,7 @@ import { renderActivity } from '../../remote/activitypub/renderer'; import { deliver } from '../../queue'; export async function createMessage(user: User, recipientUser: User | undefined, recipientGroup: UserGroup | undefined, text: string | undefined, file: DriveFile | null, uri?: string) { - const message = await MessagingMessages.save({ + const message = { id: genId(), createdAt: new Date(), fileId: file ? file.id : null, @@ -25,7 +25,9 @@ export async function createMessage(user: User, recipientUser: User | undefined, isRead: false, reads: [] as any[], uri - } as MessagingMessage); + } as MessagingMessage; + + await MessagingMessages.insert(message); const messageObj = await MessagingMessages.pack(message); diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 563eaac758..7c7e8d9a08 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -247,7 +247,7 @@ export default async (user: User, data: Option, silent = false) => new Promise { if (shouldMute) { - MutedNotes.save({ + MutedNotes.insert({ id: genId(), userId: u.userId, noteId: note.id, diff --git a/src/services/note/polls/vote.ts b/src/services/note/polls/vote.ts index bfcaaa09be..b4ce03ab60 100644 --- a/src/services/note/polls/vote.ts +++ b/src/services/note/polls/vote.ts @@ -29,7 +29,7 @@ export default async function(user: User, note: Note, choice: number) { } // Create vote - await PollVotes.save({ + await PollVotes.insert({ id: genId(), createdAt: new Date(), noteId: note.id, diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index 6c0a852f34..897c816de8 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -18,17 +18,17 @@ export default async (user: User, note: Note, reaction?: string) => { // TODO: cache reaction = await toDbReaction(reaction, user.host); - let record: NoteReaction; + let record: NoteReaction = { + id: genId(), + createdAt: new Date(), + noteId: note.id, + userId: user.id, + reaction + }; // Create reaction try { - record = await NoteReactions.save({ - id: genId(), - createdAt: new Date(), - noteId: note.id, - userId: user.id, - reaction - }); + await NoteReactions.insert(record); } catch (e) { if (isDuplicateKeyValueError(e)) { record = await NoteReactions.findOneOrFail({ diff --git a/src/services/note/unread.ts b/src/services/note/unread.ts index 6fd9ee2cfe..8e6fb4abe8 100644 --- a/src/services/note/unread.ts +++ b/src/services/note/unread.ts @@ -17,7 +17,7 @@ export default async function(userId: User['id'], note: Note, params: { if (mute.map(m => m.muteeId).includes(note.userId)) return; //#endregion - const unread = await NoteUnreads.save({ + const unread = { id: genId(), noteId: note.id, userId: userId, @@ -25,7 +25,9 @@ export default async function(userId: User['id'], note: Note, params: { isMentioned: params.isMentioned, noteChannelId: note.channelId, noteUserId: note.userId, - }); + }; + + await NoteUnreads.insert(unread); // 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する setTimeout(async () => { diff --git a/src/services/note/watch.ts b/src/services/note/watch.ts index d3c9553696..966b7f0054 100644 --- a/src/services/note/watch.ts +++ b/src/services/note/watch.ts @@ -10,7 +10,7 @@ export default async (me: User['id'], note: Note) => { return; } - await NoteWatchings.save({ + await NoteWatchings.insert({ id: genId(), createdAt: new Date(), noteId: note.id, diff --git a/src/services/update-hashtag.ts b/src/services/update-hashtag.ts index 1dcb582791..3e22846731 100644 --- a/src/services/update-hashtag.ts +++ b/src/services/update-hashtag.ts @@ -86,7 +86,7 @@ export async function updateHashtag(user: User, tag: string, isUserAttached = fa } } else { if (isUserAttached) { - Hashtags.save({ + Hashtags.insert({ id: genId(), name: tag, mentionedUserIds: [], @@ -103,7 +103,7 @@ export async function updateHashtag(user: User, tag: string, isUserAttached = fa attachedRemoteUsersCount: Users.isRemoteUser(user) ? 1 : 0, } as Hashtag); } else { - Hashtags.save({ + Hashtags.insert({ id: genId(), name: tag, mentionedUserIds: [user.id], diff --git a/src/services/user-list/push.ts b/src/services/user-list/push.ts index e67be4b027..ba54c04475 100644 --- a/src/services/user-list/push.ts +++ b/src/services/user-list/push.ts @@ -8,7 +8,7 @@ import { fetchProxyAccount } from '../../misc/fetch-proxy-account'; import createFollowing from '../following/create'; export async function pushUserToUserList(target: User, list: UserList) { - await UserListJoinings.save({ + await UserListJoinings.insert({ id: genId(), createdAt: new Date(), userId: target.id, -- cgit v1.2.3-freya