refactor: create abstract class

This commit is contained in:
kawamataryo 2024-11-20 20:07:44 +09:00
parent 20b04b9322
commit a14e5395e5
3 changed files with 61 additions and 38 deletions

View File

@ -2,11 +2,25 @@ import type { AtpSessionData } from "@atproto/api";
import { Storage } from "@plasmohq/storage"; import { Storage } from "@plasmohq/storage";
import { useStorage } from "@plasmohq/storage/hook"; import { useStorage } from "@plasmohq/storage/hook";
import React from "react"; import React from "react";
import { match, P } from "ts-pattern";
import { BskyServiceWorkerClient } from "~lib/bskyServiceWorkerClient"; import { BskyServiceWorkerClient } from "~lib/bskyServiceWorkerClient";
import { type MESSAGE_NAMES, STORAGE_KEYS } from "~lib/constants"; import { MESSAGE_NAMES, STORAGE_KEYS } from "~lib/constants";
import { searchBskyUser } from "~lib/searchBskyUsers"; import { searchBskyUser } from "~lib/searchBskyUsers";
import { XService } from "~lib/services/x"; import type { AbstractService } from "~lib/services/abstractService";
import type { BskyUser, CrawledUserInfo } from "~types"; import { XService } from "~lib/services/xService";
import type { BskyUser, CrawledUserInfo, MessageName } from "~types";
const getService = (messageName: string): AbstractService => {
return match(messageName)
.with(P.when((name) => [
MESSAGE_NAMES.SEARCH_BSKY_USER_ON_FOLLOW_PAGE,
MESSAGE_NAMES.SEARCH_BSKY_USER_ON_LIST_MEMBERS_PAGE,
MESSAGE_NAMES.SEARCH_BSKY_USER_ON_BLOCK_PAGE,
].includes(name as MessageName)),
() => new XService(messageName),
)
.otherwise(() => new XService(messageName));
};
export const useRetrieveBskyUsers = () => { export const useRetrieveBskyUsers = () => {
const bskyClient = React.useRef<BskyServiceWorkerClient | null>(null); const bskyClient = React.useRef<BskyServiceWorkerClient | null>(null);
@ -75,7 +89,7 @@ export const useRetrieveBskyUsers = () => {
let index = 0; let index = 0;
const xService = new XService(messageName); const service = getService(messageName);
// loop until we get to the bottom // loop until we get to the bottom
while (!isBottomReached) { while (!isBottomReached) {
@ -83,10 +97,10 @@ export const useRetrieveBskyUsers = () => {
break; break;
} }
const data = xService.getCrawledUsers(); const data = service.getCrawledUsers();
await retrieveBskyUsers(data); await retrieveBskyUsers(data);
const isEnd = await xService.performScrollAndCheckEnd(); const isEnd = await service.performScrollAndCheckEnd();
if (isEnd) { if (isEnd) {
setIsBottomReached(true); setIsBottomReached(true);

View File

@ -0,0 +1,37 @@
import { MESSAGE_NAME_TO_QUERY_PARAM_MAP } from "~lib/constants";
import type { CrawledUserInfo, MessageName } from "~types";
export abstract class AbstractService {
messageName: MessageName;
crawledUsers: Set<string>;
constructor(messageName: string) {
this.messageName = messageName as MessageName;
this.crawledUsers = new Set();
}
abstract extractUserData(userCell: Element): CrawledUserInfo;
getCrawledUsers(): CrawledUserInfo[] {
const userCells = Array.from(
document.querySelectorAll(
MESSAGE_NAME_TO_QUERY_PARAM_MAP[this.messageName],
),
);
const users = Array.from(userCells).map((userCell) =>
this.extractUserData(userCell),
)
.filter((user) => {
const isNewUser = !this.crawledUsers.has(user.accountName);
if (isNewUser) {
this.crawledUsers.add(user.accountName);
}
return isNewUser;
});
return users;
}
abstract performScrollAndCheckEnd(): Promise<boolean>;
}

View File

@ -1,20 +1,11 @@
import { MESSAGE_NAMES } from "~lib/constants"; import { MESSAGE_NAMES } from "~lib/constants";
import { BSKY_DOMAIN, MESSAGE_NAME_TO_QUERY_PARAM_MAP } from "~lib/constants"; import { BSKY_DOMAIN, MESSAGE_NAME_TO_QUERY_PARAM_MAP } from "~lib/constants";
import { wait } from "~lib/utils"; import { wait } from "~lib/utils";
import type { CrawledUserInfo, MessageName } from "~types"; import { AbstractService } from "./abstractService";
import type { CrawledUserInfo } from "~types";
export class XService { export class XService extends AbstractService {
// 対象のdomを取得する処理 extractUserData(userCell: Element): CrawledUserInfo {
messageName: MessageName;
crawledUsers: Set<string>;
constructor(messageName: string) {
// TODO: add type check
this.messageName = messageName as MessageName;
this.crawledUsers = new Set();
}
private extractUserData(userCell: Element): CrawledUserInfo {
const anchors = Array.from(userCell.querySelectorAll("a")); const anchors = Array.from(userCell.querySelectorAll("a"));
const [avatarEl, displayNameEl] = anchors; const [avatarEl, displayNameEl] = anchors;
const accountName = avatarEl?.getAttribute("href")?.replace("/", ""); const accountName = avatarEl?.getAttribute("href")?.replace("/", "");
@ -39,25 +30,6 @@ export class XService {
}; };
} }
getCrawledUsers(): CrawledUserInfo[] {
const userCells = Array.from(
document.querySelectorAll(
MESSAGE_NAME_TO_QUERY_PARAM_MAP[this.messageName],
),
);
const users = userCells
.map((userCell) => this.extractUserData(userCell))
.filter((user) => !this.crawledUsers.has(user.accountName));
this.crawledUsers = new Set([
...this.crawledUsers,
...users.map((user) => user.accountName),
]);
return users;
}
async performScrollAndCheckEnd(): Promise<boolean> { async performScrollAndCheckEnd(): Promise<boolean> {
const isListMembersPage = const isListMembersPage =
this.messageName === MESSAGE_NAMES.SEARCH_BSKY_USER_ON_LIST_MEMBERS_PAGE; this.messageName === MESSAGE_NAMES.SEARCH_BSKY_USER_ON_LIST_MEMBERS_PAGE;