fix: refactor antennas and fix bugs

This commit is contained in:
naskya 2023-10-16 03:50:41 +09:00
parent 958c6678f9
commit 1694b82154
Signed by: naskya
GPG key ID: 164DFF24E2D40139
9 changed files with 41 additions and 106 deletions

View file

@ -1,29 +1,20 @@
import type { Antenna } from "@/models/entities/antenna.js"; import type { Antenna } from "@/models/entities/antenna.js";
import type { Note } from "@/models/entities/note.js"; import type { Note } from "@/models/entities/note.js";
import type { User } from "@/models/entities/user.js"; import type { User } from "@/models/entities/user.js";
import { import { Blockings, UserProfiles } from "@/models/index.js";
UserListJoinings,
UserGroupJoinings,
Blockings,
} from "@/models/index.js";
import { getFullApAccount } from "./convert-host.js"; import { getFullApAccount } from "./convert-host.js";
import * as Acct from "@/misc/acct.js"; import * as Acct from "@/misc/acct.js";
import type { Packed } from "./schema.js"; import type { Packed } from "./schema.js";
import { Cache } from "./cache.js"; import { Cache } from "./cache.js";
import { getWordHardMute } from "./check-word-mute.js";
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5); const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
// NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている
/**
* noteUserFollowers / antennaUserFollowing
*/
export async function checkHitAntenna( export async function checkHitAntenna(
antenna: Antenna, antenna: Antenna,
note: Note | Packed<"Note">, note: Note | Packed<"Note">,
noteUser: { id: User["id"]; username: string; host: string | null }, noteUser: { id: User["id"]; username: string; host: string | null },
noteUserFollowers?: User["id"][], antennaUserFollowing: User["id"][],
antennaUserFollowing?: User["id"][],
): Promise<boolean> { ): Promise<boolean> {
if (note.visibility === "specified") return false; if (note.visibility === "specified") return false;
@ -35,41 +26,25 @@ export async function checkHitAntenna(
); );
if (blockings.some((blocking) => blocking === antenna.userId)) return false; if (blockings.some((blocking) => blocking === antenna.userId)) return false;
if (
await getWordHardMute(
note,
antenna.userId,
(
await UserProfiles.findOneBy({ userId: antenna.userId })
)?.mutedWords,
)
)
return false;
if (note.visibility === "followers" || note.visibility === "home") { if (note.visibility === "followers" || note.visibility === "home") {
if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId))
return false;
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId)) if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
return false; return false;
} }
if (!antenna.withReplies && note.replyId != null) return false; if (!antenna.withReplies && note.replyId != null) return false;
if (antenna.src === "home") { if (antenna.src === "users") {
if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId))
return false;
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
return false;
} else if (antenna.src === "list") {
const listUsers = (
await UserListJoinings.findBy({
userListId: antenna.userListId!,
})
).map((x) => x.userId);
if (!listUsers.includes(note.userId)) return false;
} else if (antenna.src === "group") {
const joining = await UserGroupJoinings.findOneByOrFail({
id: antenna.userGroupJoiningId!,
});
const groupUsers = (
await UserGroupJoinings.findBy({
userGroupId: joining.userGroupId,
})
).map((x) => x.userId);
if (!groupUsers.includes(note.userId)) return false;
} else if (antenna.src === "users") {
const accts = antenna.users.map((x) => { const accts = antenna.users.map((x) => {
const { username, host } = Acct.parse(x); const { username, host } = Acct.parse(x);
return getFullApAccount(username, host).toLowerCase(); return getFullApAccount(username, host).toLowerCase();

View file

@ -1,6 +1,5 @@
import RE2 from "re2"; import RE2 from "re2";
import type { Note } from "@/models/entities/note.js"; import type { Note } from "@/models/entities/note.js";
import type { User } from "@/models/entities/user.js";
type NoteLike = { type NoteLike = {
userId: Note["userId"]; userId: Note["userId"];
@ -9,10 +8,6 @@ type NoteLike = {
cw?: Note["cw"]; cw?: Note["cw"];
}; };
type UserLike = {
id: User["id"];
};
function checkWordMute( function checkWordMute(
note: NoteLike, note: NoteLike,
mutedWords: Array<string | string[]>, mutedWords: Array<string | string[]>,
@ -61,11 +56,11 @@ function checkWordMute(
export async function getWordHardMute( export async function getWordHardMute(
note: NoteLike, note: NoteLike,
me: UserLike | null | undefined, meId: string | null | undefined,
mutedWords: Array<string | string[]>, mutedWords?: Array<string | string[]>,
): Promise<boolean> { ): Promise<boolean> {
// 自分自身 // 自分自身
if (me && note.userId === me.id) { if (note.userId === meId || mutedWords == null) {
return false; return false;
} }

View file

@ -67,8 +67,9 @@ export default class extends Channel {
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる // そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
if ( if (
this.user &&
this.userProfile && this.userProfile &&
(await getWordHardMute(note, this.user, this.userProfile.mutedWords)) (await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
) )
return; return;

View file

@ -66,8 +66,9 @@ export default class extends Channel {
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる // そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
if ( if (
this.user &&
this.userProfile && this.userProfile &&
(await getWordHardMute(note, this.user, this.userProfile.mutedWords)) (await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
) )
return; return;

View file

@ -83,8 +83,9 @@ export default class extends Channel {
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる // そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
if ( if (
this.user &&
this.userProfile && this.userProfile &&
(await getWordHardMute(note, this.user, this.userProfile.mutedWords)) (await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
) )
return; return;

View file

@ -59,8 +59,9 @@ export default class extends Channel {
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる // そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
if ( if (
this.user &&
this.userProfile && this.userProfile &&
(await getWordHardMute(note, this.user, this.userProfile.mutedWords)) (await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
) )
return; return;

View file

@ -81,8 +81,9 @@ export default class extends Channel {
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる // そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
if ( if (
this.user &&
this.userProfile && this.userProfile &&
(await getWordHardMute(note, this.user, this.userProfile.mutedWords)) (await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
) )
return; return;

View file

@ -23,6 +23,7 @@ import { extractHashtags } from "@/misc/extract-hashtags.js";
import type { IMentionedRemoteUsers } from "@/models/entities/note.js"; import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
import { Note } from "@/models/entities/note.js"; import { Note } from "@/models/entities/note.js";
import { import {
Followings,
Mutings, Mutings,
Users, Users,
NoteWatchings, NoteWatchings,
@ -370,7 +371,7 @@ export default async (
) )
.then((us) => { .then((us) => {
for (const u of us) { for (const u of us) {
getWordHardMute(data, { id: u.userId }, u.mutedWords).then( getWordHardMute(data, u.userId, u.mutedWords).then(
(shouldMute) => { (shouldMute) => {
if (shouldMute) { if (shouldMute) {
MutedNotes.insert({ MutedNotes.insert({
@ -387,7 +388,17 @@ export default async (
// Antenna // Antenna
for (const antenna of await getAntennas()) { for (const antenna of await getAntennas()) {
checkHitAntenna(antenna, note, user).then((hit) => { checkHitAntenna(
antenna,
note,
user,
(
await Followings.find({
where: { followerId: user.id },
select: ["followeeId"],
})
).map((x) => x.followeeId),
).then((hit) => {
if (hit) { if (hit) {
addNoteToAntenna(antenna, note, user); addNoteToAntenna(antenna, note, user);
} }

View file

@ -9,8 +9,6 @@ import {
} from "@/models/index.js"; } from "@/models/index.js";
import { Not, IsNull, In } from "typeorm"; import { Not, IsNull, In } from "typeorm";
import type { Channel } from "@/models/entities/channel.js"; import type { Channel } from "@/models/entities/channel.js";
import { checkHitAntenna } from "@/misc/check-hit-antenna.js";
import { getAntennas } from "@/misc/antenna-cache.js";
import { readNotificationByQuery } from "@/server/api/common/read-notification.js"; import { readNotificationByQuery } from "@/server/api/common/read-notification.js";
import type { Packed } from "@/misc/schema.js"; import type { Packed } from "@/misc/schema.js";
@ -50,11 +48,9 @@ export default async function (
).map((x) => x.followeeId), ).map((x) => x.followeeId),
); );
// const myAntennas = (await getAntennas()).filter((a) => a.userId === userId);
const readMentions: (Note | Packed<"Note">)[] = []; const readMentions: (Note | Packed<"Note">)[] = [];
const readSpecifiedNotes: (Note | Packed<"Note">)[] = []; const readSpecifiedNotes: (Note | Packed<"Note">)[] = [];
const readChannelNotes: (Note | Packed<"Note">)[] = []; const readChannelNotes: (Note | Packed<"Note">)[] = [];
// const readAntennaNotes: (Note | Packed<"Note">)[] = [];
for (const note of notes) { for (const note of notes) {
if (note.mentions?.includes(userId)) { if (note.mentions?.includes(userId)) {
@ -66,23 +62,6 @@ export default async function (
if (note.channelId && followingChannels.has(note.channelId)) { if (note.channelId && followingChannels.has(note.channelId)) {
readChannelNotes.push(note); readChannelNotes.push(note);
} }
// if (note.user != null) {
// // たぶんnullになることは無いはずだけど一応
// for (const antenna of myAntennas) {
// if (
// await checkHitAntenna(
// antenna,
// note,
// note.user,
// undefined,
// Array.from(following),
// )
// ) {
// readAntennaNotes.push(note);
// }
// }
// }
} }
if ( if (
@ -139,34 +118,4 @@ export default async function (
]), ]),
}); });
} }
// if (readAntennaNotes.length > 0) {
// await AntennaNotes.update(
// {
// antennaId: In(myAntennas.map((a) => a.id)),
// noteId: In(readAntennaNotes.map((n) => n.id)),
// },
// {
// read: true,
// },
// );
// // TODO: まとめてクエリしたい
// for (const antenna of myAntennas) {
// const count = await AntennaNotes.countBy({
// antennaId: antenna.id,
// read: false,
// });
// if (count === 0) {
// publishMainStream(userId, "readAntenna", antenna);
// }
// }
// Users.getHasUnreadAntenna(userId).then((unread) => {
// if (!unread) {
// publishMainStream(userId, "readAllAntennas");
// }
// });
// }
} }