refactor: add ExportResult (fix #12)

main
spacemeowx2 2022-11-26 22:45:44 +08:00 committed by imspace
parent 8d376cfd38
commit aabc9cf733
4 changed files with 108 additions and 49 deletions

View File

@ -35,6 +35,29 @@ type Progress = {
total: number;
};
class StepProgress {
currentUrl?: string;
total: number;
exported: number;
done: number;
skipped: Record<string, number>;
constructor() {
this.total = 1;
this.exported = 0;
this.done = 0;
this.skipped = {};
}
}
function progress({ total, currentUrl, done }: StepProgress): Progress {
return {
total,
currentUrl,
current: done,
};
}
export class App {
profile: Profile;
env: Env;
@ -128,7 +151,7 @@ export class App {
const exporters = await this.getExporters();
const initStats = () =>
Object.fromEntries(
exporters.map((e) => [e.name, 0]),
exporters.map((e) => [e.name, new StepProgress()]),
);
let stats = initStats();
const skipMode = this.getSkipMode();
@ -158,14 +181,11 @@ export class App {
fetcher,
exporter: e,
gameList,
onStep: (progress) => {
redraw(e.name, progress);
stats[e.name] = progress.current;
stepProgress: stats[e.name],
onStep: () => {
redraw(e.name, progress(stats[e.name]));
},
})
.then((count) => {
stats[e.name] = count;
}),
}),
)
.catch((err) => {
errors.push(err);
@ -215,14 +235,11 @@ export class App {
fetcher,
exporter: e,
gameList: coopBattleList,
onStep: (progress) => {
stats[e.name] = progress.current;
redraw(e.name, progress);
stepProgress: stats[e.name],
onStep: () => {
redraw(e.name, progress(stats[e.name]));
},
})
.then((count) => {
stats[e.name] = count;
}),
}),
)
.catch((err) => {
errors.push(err);
@ -295,20 +312,17 @@ export class App {
fetcher,
exporter,
gameList,
stepProgress,
onStep,
}: {
type: Game["type"];
exporter: GameExporter;
fetcher: GameFetcher;
gameList: string[];
onStep: (progress: Progress) => void;
}) {
let exported = 0;
onStep?.({
current: 0,
total: 1,
});
stepProgress: StepProgress;
onStep: () => void;
}): Promise<StepProgress> {
onStep?.();
const workQueue = [
...await exporter.notExported({
@ -320,39 +334,56 @@ export class App {
const step = async (id: string) => {
const detail = await fetcher.fetch(type, id);
const { url } = await exporter.exportGame(detail);
exported += 1;
onStep?.({
currentUrl: url,
current: exported,
total: workQueue.length,
});
const result = await exporter.exportGame(detail);
stepProgress.done += 1;
stepProgress.currentUrl = undefined;
if (result.status === "success") {
stepProgress.exported += 1;
stepProgress.currentUrl = result.url;
} else if (result.status === "skip") {
const { skipped } = stepProgress;
skipped[result.reason] = (skipped[result.reason] ?? 0) + 1;
} else {
const _never: never = result;
}
onStep?.();
};
if (workQueue.length > 0) {
onStep?.({
current: exported,
total: workQueue.length,
});
stepProgress.total = workQueue.length;
onStep?.();
for (const battle of workQueue) {
await step(battle);
}
} else {
onStep?.({
current: 1,
total: 1,
});
stepProgress.done = 1;
onStep?.();
}
return exported;
return stepProgress;
}
printStats(stats: Record<string, number>) {
printStats(stats: Record<string, StepProgress>) {
this.env.logger.log(
`Exported ${
Object.entries(stats)
.map(([name, count]) => `${name}: ${count}`)
.map(([name, { exported }]) => `${name}: ${exported}`)
.join(", ")
}`,
);
if (Object.values(stats).some((i) => Object.keys(i.skipped).length > 0)) {
this.env.logger.log(
`Skipped ${
Object.entries(stats)
.map(([name, { skipped }]) =>
Object.entries(skipped).map(([reason, count]) =>
`${name}: ${reason} (${count})`
).join(", ")
)
}`,
);
}
}
}

View File

@ -1,4 +1,10 @@
import { CoopInfo, Game, GameExporter, VsInfo } from "../types.ts";
import {
CoopInfo,
ExportResult,
Game,
GameExporter,
VsInfo,
} from "../types.ts";
import { path } from "../../deps.ts";
import { NSOAPP_VERSION, S3SI_VERSION } from "../constant.ts";
import { parseHistoryDetailId, urlSimplify } from "../utils.ts";
@ -83,7 +89,7 @@ export class FileExporter implements GameExporter {
},
}));
}
async exportGame(info: Game) {
async exportGame(info: Game): Promise<ExportResult> {
await Deno.mkdir(this.exportPath, { recursive: true });
const filename = this.getFilenameById(info.detail.id);
@ -103,6 +109,7 @@ export class FileExporter implements GameExporter {
);
return {
status: "success",
url: filepath,
};
}

View File

@ -8,6 +8,7 @@ import {
CoopHistoryDetail,
CoopHistoryPlayerResult,
CoopInfo,
ExportResult,
Game,
GameExporter,
Image,
@ -231,10 +232,13 @@ export class StatInkExporter implements GameExporter {
isTriColor({ vsMode }: VsHistoryDetail): boolean {
return vsMode.mode === "FEST" && b64Number(vsMode.id) === 8;
}
async exportGame(game: VsInfo | CoopInfo) {
async exportGame(game: Game): Promise<ExportResult> {
if (game.type === "VsInfo" && this.isTriColor(game.detail)) {
// TODO: support tri-color fest
return {};
return {
status: "skip",
reason: "Tri-color fest is not supported",
};
}
if (game.type === "VsInfo") {
@ -242,6 +246,7 @@ export class StatInkExporter implements GameExporter {
const { url } = await this.api.postBattle(body);
return {
status: "success",
url,
};
} else {
@ -249,6 +254,7 @@ export class StatInkExporter implements GameExporter {
const { url } = await this.api.postCoop(body);
return {
status: "success",
url,
};
}

View File

@ -296,12 +296,27 @@ export type CoopHistoryDetail = {
jobBonus: null | number;
};
export type ExportResult = {
status: "success";
url?: string;
} | {
status: "skip";
reason: string;
};
export type SummaryFetcher = {
fetchSummary<T extends (typeof Queries)[keyof typeof SummaryEnum]>(
type: T,
): Promise<RespMap[T]>;
};
export type GameExporter = {
name: string;
notExported: (
{ type, list }: { type: Game["type"]; list: string[] },
) => Promise<string[]>;
exportGame: (game: Game) => Promise<{ url?: string }>;
exportGame: (game: Game) => Promise<ExportResult>;
exportSummary?: (fetcher: SummaryFetcher) => Promise<ExportResult>;
};
export type BankaraBattleHistories = {
@ -737,7 +752,7 @@ export type RankParam = {
};
export enum SummaryEnum {
ConfigureAnalyticsQuery,
HistoryRecordQuery,
CoopHistoryQuery,
ConfigureAnalyticsQuery = Queries.ConfigureAnalyticsQuery,
HistoryRecordQuery = Queries.HistoryRecordQuery,
CoopHistoryQuery = Queries.CoopHistoryQuery,
}