feat: improve error handling for authentication flow
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { graphql } from "gql.tada";
|
||||
import { GraphQLClient } from "graphql-request";
|
||||
|
||||
import { sleep } from "~/libs/sleep";
|
||||
|
||||
const GetWatchingTitlesQuery = graphql(`
|
||||
query GetWatchingTitles($userName: String!, $page: Int!) {
|
||||
Page(page: $page, perPage: 50) {
|
||||
@@ -55,8 +57,7 @@ export function getWatchingTitles(
|
||||
username: string,
|
||||
page: number,
|
||||
aniListToken: string,
|
||||
executionCtx: ExecutionContext,
|
||||
) {
|
||||
): Promise<GetWatchingTitles> {
|
||||
const client = new GraphQLClient("https://graphql.anilist.co/");
|
||||
|
||||
return client
|
||||
@@ -73,16 +74,67 @@ export function getWatchingTitles(
|
||||
const response = err.response;
|
||||
if (response.status === 429) {
|
||||
console.log("429, retrying in", response.headers.get("Retry-After"));
|
||||
executionCtx.waitUntil(
|
||||
sleep(Number(response.headers.get("Retry-After")!) * 1000),
|
||||
return sleep(Number(response.headers.get("Retry-After")!) * 1000).then(
|
||||
() => getWatchingTitles(username, page, aniListToken),
|
||||
);
|
||||
return getWatchingTitles(username, page, aniListToken, executionCtx);
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
type GetWatchingTitles = {
|
||||
mediaList:
|
||||
| ({
|
||||
media: {
|
||||
id: number;
|
||||
idMal: number | null;
|
||||
title: {
|
||||
english: string | null;
|
||||
userPreferred: string | null;
|
||||
} | null;
|
||||
description: string | null;
|
||||
episodes: number | null;
|
||||
genres: (string | null)[] | null;
|
||||
status:
|
||||
| "FINISHED"
|
||||
| "RELEASING"
|
||||
| "NOT_YET_RELEASED"
|
||||
| "CANCELLED"
|
||||
| "HIATUS"
|
||||
| null;
|
||||
bannerImage: string | null;
|
||||
averageScore: number | null;
|
||||
coverImage: {
|
||||
extraLarge: string | null;
|
||||
large: string | null;
|
||||
medium: string | null;
|
||||
} | null;
|
||||
countryOfOrigin: unknown;
|
||||
mediaListEntry: {
|
||||
id: number;
|
||||
progress: number | null;
|
||||
status:
|
||||
| "CURRENT"
|
||||
| "REPEATING"
|
||||
| "PLANNING"
|
||||
| "COMPLETED"
|
||||
| "DROPPED"
|
||||
| "PAUSED"
|
||||
| null;
|
||||
} | null;
|
||||
nextAiringEpisode: {
|
||||
timeUntilAiring: number;
|
||||
airingAt: number;
|
||||
episode: number;
|
||||
} | null;
|
||||
} | null;
|
||||
} | null)[]
|
||||
| null;
|
||||
pageInfo: {
|
||||
currentPage: number | null;
|
||||
hasNextPage: boolean | null;
|
||||
perPage: number | null;
|
||||
total: number | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
@@ -4,11 +4,11 @@ import { streamSSE } from "hono/streaming";
|
||||
|
||||
import { fetchEpisodes } from "~/controllers/episodes/getByAniListId";
|
||||
import { maybeScheduleNextAiringEpisode } from "~/libs/maybeScheduleNextAiringEpisode";
|
||||
import { readEnvVariable } from "~/libs/readEnvVariable";
|
||||
import { sleep } from "~/libs/sleep";
|
||||
import { associateDeviceIdWithUsername } from "~/models/token";
|
||||
import { setWatchStatus } from "~/models/watchStatus";
|
||||
import type { Env } from "~/types/env";
|
||||
import { EpisodesResponseSchema } from "~/types/episode";
|
||||
import { Episode, EpisodesResponseSchema } from "~/types/episode";
|
||||
import { ErrorResponse, ErrorResponseSchema } from "~/types/schema";
|
||||
import { Title } from "~/types/title";
|
||||
|
||||
@@ -137,7 +137,6 @@ app.openapi(route, async (c) => {
|
||||
user.name!,
|
||||
currentPage++,
|
||||
aniListToken,
|
||||
c.executionCtx,
|
||||
);
|
||||
if (!mediaList) {
|
||||
break;
|
||||
@@ -151,7 +150,7 @@ app.openapi(route, async (c) => {
|
||||
}
|
||||
|
||||
for (const mediaObj of mediaList) {
|
||||
const media = mediaObj?.media!;
|
||||
const media = mediaObj?.media;
|
||||
if (!media) {
|
||||
continue;
|
||||
}
|
||||
@@ -189,8 +188,14 @@ app.openapi(route, async (c) => {
|
||||
|
||||
await fetchEpisodes(
|
||||
media.id,
|
||||
readEnvVariable<boolean>(c.env, "ENABLE_ANIFY"),
|
||||
).then(({ result: { episodes } }) => {
|
||||
{ ...env(c, "workerd"), ENABLE_ANIFY: "false" },
|
||||
true,
|
||||
).then(({ result: episodesResult }) => {
|
||||
const episodes = episodesResult?.episodes;
|
||||
if (!episodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
stream.writeSSE({
|
||||
event: "title",
|
||||
data: JSON.stringify({ title: media, episodes }),
|
||||
@@ -199,15 +204,13 @@ app.openapi(route, async (c) => {
|
||||
});
|
||||
}
|
||||
|
||||
hasNextPage = pageInfo?.hasNextPage ?? false;
|
||||
hasNextPage = pageInfo?.hasNextPage ?? false;
|
||||
console.log(hasNextPage);
|
||||
hasNextPage = pageInfo?.hasNextPage ?? false;
|
||||
console.log(hasNextPage);
|
||||
} while (hasNextPage);
|
||||
|
||||
// send end event instead of closing the connection to let the client know that the stream didn't end abruptly
|
||||
await stream.writeSSE({ event: "end", data: "end" });
|
||||
console.log("completed");
|
||||
},
|
||||
async (err, stream) => {
|
||||
console.error("Error occurred in SSE");
|
||||
|
||||
Reference in New Issue
Block a user