Skip to content

Commit

Permalink
kill FetchWithError (#98)
Browse files Browse the repository at this point in the history
just use plain fetch type
  • Loading branch information
wydengyre authored Feb 25, 2024
1 parent ae5af79 commit cf5b30e
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 122 deletions.
2 changes: 1 addition & 1 deletion packages/cf/worker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async function rssFeedRai404() {

const resp = await servers.worker.fetch("/programmi/404.xml");
assert(!resp.ok);
assert.strictEqual(resp.status, 404);
assert.strictEqual(resp.status, 500);
}

async function rssFeedRai500() {
Expand Down
32 changes: 15 additions & 17 deletions packages/rai/feed.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { strict as assert } from "node:assert";
import test from "node:test";
import { json } from "itty-router";
import { error, json } from "itty-router";
import { RssConvertConf, feedToRss } from "./feed.js";
import { FetchWithErr, NotOk, OkResponse } from "./fetch.js";
import feedJson from "./test/lastoriaingiallo.json" with { type: "json" };
import expectedJson from "./test/lastoriaingiallo.parsed.json" with {
type: "json",
Expand All @@ -23,8 +22,9 @@ test("feed", async (t) => {
const raiBaseUrl = new URL("https://rai.dev/");
const poolSize = 5; // arbitrary

const mediaFetchFn: FetchWithErr = (input) =>
const mediaFetchFn: typeof fetch = (input) =>
Promise.resolve({
ok: true,
url: input
.toString()
.replace(/.+cont=(.*)/, (_, cont) => `https://media.dev/${cont}.mp3`),
Expand All @@ -33,44 +33,42 @@ const mediaFetchFn: FetchWithErr = (input) =>
"content-type": "audio/mpeg",
"content-length": "123456789",
}),
} as OkResponse);
} as Response);

async function convertFeedSuccess() {
const fetchWithErr: FetchWithErr = async (input) => {
const fetch: typeof globalThis.fetch = async (input) => {
return input.toString().endsWith("foo.json")
? Promise.resolve(json(feedJson) as OkResponse)
? Promise.resolve(json(feedJson))
: mediaFetchFn(input);
};
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetchWithErr };
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetch };
const feed = await feedToRss(conf, "programmi/foo.json");
const parsed = parseFeed(feed);
assert.deepStrictEqual(parsed, expectedJson);
}

async function convertFeed610Success() {
const fetchWithErr: FetchWithErr = async (input) => {
const fetch: typeof globalThis.fetch = async (input) => {
return input.toString().endsWith("foo.json")
? Promise.resolve(json(feedJson610) as OkResponse)
? Promise.resolve(json(feedJson610))
: mediaFetchFn(input);
};
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetchWithErr };
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetch };
const feed = await feedToRss(conf, "programmi/foo.json");
const parsed = parseFeed(feed);
assert.deepStrictEqual(parsed, expectedJson610);
}

async function convertFeed404() {
const url = new URL("https://rai.dev/programmi/foo.json");
const notFound = new NotOk(url, 404, "Not Found");
const fetchWithErr = () => Promise.reject(notFound);
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetchWithErr };
await assert.rejects(feedToRss(conf, "programmi/foo.json"), notFound);
const fetch = () => Promise.resolve(error(404));
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetch };
await assert.rejects(feedToRss(conf, "programmi/foo.json"));
}

async function convertFeedNonCompliantJson() {
const fetchWithErr = () =>
Promise.resolve(json({ foo: "bar" }) as OkResponse);
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetchWithErr };
const fetch = () => Promise.resolve(json({ foo: "bar" }));
const conf: RssConvertConf = { raiBaseUrl, poolSize, fetch };
const expectedErr = /^Error: failed to parse feed JSON/;
await assert.rejects(feedToRss(conf, "programmi/foo.json"), expectedErr);
}
7 changes: 3 additions & 4 deletions packages/rai/feed.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { PromisePool } from "@supercharge/promise-pool";
import { z } from "zod";
import { FetchWithErr } from "./fetch.js";
import * as media from "./media.js";

export { RssConvertConf, feedToRss };
Expand Down Expand Up @@ -32,17 +31,17 @@ const schema = z.object({
type RssConvertConf = {
raiBaseUrl: URL;
poolSize: number;
fetchWithErr: FetchWithErr;
fetch: typeof fetch;
};
async function feedToRss(c: RssConvertConf, relUrl: string): Promise<string> {
const fetchInfo = media.mkFetchInfo(c.fetchWithErr);
const fetchInfo = media.mkFetchInfo(c.fetch);
const convertor = new RssConvertor({
raiBaseUrl: c.raiBaseUrl,
poolSize: c.poolSize,
fetchInfo,
});
const url = new URL(relUrl, c.raiBaseUrl);
const resp = await c.fetchWithErr(url);
const resp = await c.fetch(url);
const json = await resp.json();
return convertor.convert(json);
}
Expand Down
51 changes: 0 additions & 51 deletions packages/rai/fetch.ts

This file was deleted.

6 changes: 3 additions & 3 deletions packages/rai/media.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { strict as assert } from "node:assert";
import test from "node:test";
import { FetchWithErr, OkResponse } from "./fetch.js";
import { mkFetchInfo } from "./media.js";

test("media", (t) => {
Expand All @@ -11,15 +10,16 @@ async function fetchInfoSuccess() {
const url =
"https://mediapolisvod.rai.it/relinker/relinkerServlet.htm?cont=PE3wc6etKfssSlashNKfaoXssSlashpWcgeeqqEEqualeeqqEEqual";
const mediaUrl = new URL("https://test.dev/foo.mp3");
const fetch: FetchWithErr = async () =>
const fetch = async () =>
({
ok: true,
url: mediaUrl.toString(),
status: 200,
headers: new Headers({
"content-type": "audio/mpeg",
"content-length": "123456789",
}),
}) as OkResponse;
}) as Response;
const fetchInfo = mkFetchInfo(fetch);

const info = await fetchInfo(url);
Expand Down
10 changes: 6 additions & 4 deletions packages/rai/media.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { FetchWithErr } from "./fetch.js";

export { FetchInfo, MediaInfo, MediaUrl, mkFetchInfo };

type FetchInfo = (url: string) => Promise<MediaInfo>;
Expand All @@ -15,7 +13,7 @@ type MediaInfo = {
const relinkerRe = /^\?cont=[a-zA-Z0-9]+$/;

const mkFetchInfo =
(fetchWithErr: FetchWithErr): FetchInfo =>
(fetch: typeof globalThis.fetch): FetchInfo =>
async (url) => {
const mediaUrl = mkMediaUrl(url);
if (typeof mediaUrl === "string") {
Expand All @@ -31,7 +29,11 @@ const mkFetchInfo =
"User-Agent": chromeAgent,
},
};
const resp = await fetchWithErr(url, chromeHeadInit);

const resp = await fetch(url, chromeHeadInit);
if (!resp.ok) {
throw new Error(`Failed to fetch: ${resp.status} ${resp.statusText}`);
}

const contentLength = resp.headers.get("content-length");
const length = Number(contentLength);
Expand Down
24 changes: 12 additions & 12 deletions packages/server/feed-handler.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { strict as assert } from "node:assert";
import test from "node:test";
import { FetchWithErr, NotOk, OkResponse } from "@raiplayrss/rai/fetch.js";
import feedJson from "@raiplayrss/rai/test/lastoriaingiallo.json";
import expectedJson from "@raiplayrss/rai/test/lastoriaingiallo.parsed.json" with {
type: "json",
};
import { json } from "itty-router";
import { json, status } from "itty-router";
import { parseFeed } from "../rai/test/parse-feed.js";
import { feedHandler } from "./feed-handler.js";
import * as logger from "./logger.js";
Expand All @@ -21,22 +20,22 @@ test("feed-handler", async (t) => {
const raiBaseUrl = new URL("https://rai.dev/");
const mediaBaseUrl = new URL("https://media.dev/");

const confWithFetch = (fetchWithErr: FetchWithErr) => ({
const confWithFetch = (fetch: typeof globalThis.fetch) => ({
raiBaseUrl,
poolSize: 5,
fetchWithErr,
fetch,
logger: logger.disabled,
});

async function rssFeedSuccess() {
const req = new Request("https://test.dev/programmi/lastoriaingiallo.xml");
const fetchMock: FetchWithErr = async (input, init) => {
const fetchMock: typeof fetch = async (input) => {
const requestUrlStr = input.toString();
const url = new URL(requestUrlStr);
const { pathname, search } = url;

if (pathname === "/programmi/lastoriaingiallo.json") {
return json(feedJson) as OkResponse;
return json(feedJson);
}

const relinkerRel = "/relinker/relinkerServlet.htm";
Expand All @@ -48,12 +47,13 @@ async function rssFeedSuccess() {
);
const url = `${urlStart}.mp3`;
return {
ok: true,
url: url,
headers: new Headers({
"Content-Type": "audio/mpeg",
"Content-Length": "123456789",
}),
} as OkResponse;
} as Response;
}

throw new Error(`unexpected request: ${requestUrlStr}`);
Expand All @@ -71,22 +71,22 @@ async function rssFeedSuccess() {
async function rssFeedFail404() {
const url = new URL("https://test.dev/programmi/nonexistent.xml");
const req = new Request(url);
const fetchMock = () => Promise.reject(new NotOk(url, 404, "not found"));
const fetchMock = async () => status(404);
const conf = confWithFetch(fetchMock);
const resp = await feedHandler(conf, req);
assert.strictEqual(resp.status, 404);
assert.strictEqual(resp.status, 500);
assert.strictEqual(resp.headers.get("Content-Type"), "application/xml");
const text = await resp.text();
assert.strictEqual(
text,
"<error><code>404</code><message>not found</message></error>",
"<error><code>500</code><message>server error</message></error>",
);
}

async function rssFeedFail500() {
const url = new URL("https://test.dev/programmi/500.xml");
const req = new Request(url);
const fetchMock = () => Promise.reject(new NotOk(url, 500, "server error"));
const fetchMock = async () => status(500);
const conf = confWithFetch(fetchMock);
const resp = await feedHandler(conf, req);
assert.strictEqual(resp.status, 500);
Expand All @@ -100,7 +100,7 @@ async function rssFeedFail500() {

async function rssFeedFailNonCompliantJson() {
const req = new Request("https://test.dev/programmi/corrupt.xml");
const fetchMock = () => Promise.resolve(json({ foo: "bar" }) as OkResponse);
const fetchMock = async () => json({ foo: "bar" });

const conf = confWithFetch(fetchMock);
const resp = await feedHandler(conf, req);
Expand Down
11 changes: 3 additions & 8 deletions packages/server/feed-handler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { feedToRss } from "@raiplayrss/rai/feed.js";
import { FetchWithErr, NotOk } from "@raiplayrss/rai/fetch.js";
import { createResponse } from "itty-router";
import { Logger } from "./logger.js";

Expand All @@ -8,7 +7,7 @@ export { Config, feedHandler };
type Config = {
raiBaseUrl: URL;
poolSize: number;
fetchWithErr: FetchWithErr;
fetch: typeof fetch;
logger: Logger;
};
async function feedHandler(conf: Config, request: Request): Promise<Response> {
Expand All @@ -23,12 +22,8 @@ async function feedHandler(conf: Config, request: Request): Promise<Response> {
conf.logger.error("error converting feed", jsonPath, e);
const contentType = "application/xml";
const headers = new Headers({ "Content-Type": contentType });
let status = 500;
let body = "<error><code>500</code><message>server error</message></error>";
if (e instanceof NotOk && e.status === 404) {
status = e.status;
body = "<error><code>404</code><message>not found</message></error>";
}
const status = 500;
const body = `<error><code>${status}</code><message>server error</message></error>`;
return new Response(body, { status, headers });
}
const rss = createResponse("application/rss+xml");
Expand Down
6 changes: 3 additions & 3 deletions packages/server/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ async function rssFeedSuccess() {

async function rssFeedFail404() {
const req = new Request("arbitrary://arbitrary/programmi/nonexistent.xml");
const fetchMock = () => Promise.resolve(error(404, "not found"));
const fetchMock = async () => error(404, "not found");
const fetchHandler = fetchHandlerWithMock(fetchMock);
const resp = await fetchHandler(req);

assert.strictEqual(resp.status, 404);
assert.strictEqual(resp.status, 500);
const text = await resp.text();
assert.strictEqual(
text,
"<error><code>404</code><message>not found</message></error>",
"<error><code>500</code><message>server error</message></error>",
);
}

Expand Down
22 changes: 3 additions & 19 deletions packages/server/handler.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
import { mkFetchWithErr } from "@raiplayrss/rai/fetch.js";
import { Router, error, html } from "itty-router";
import { Router, error } from "itty-router";
import { feedHandler } from "./feed-handler.js";
import { Logger } from "./logger.js";
import type { Config } from "./feed-handler.js";

export { Config, FetchHandler, mkFetchHandler };

type Config = {
raiBaseUrl: URL;
poolSize: number;
fetch: typeof fetch;
logger: Logger;
};

type FetchHandler = (req: Request) => Promise<Response>;
function mkFetchHandler(conf: Config): FetchHandler {
const fetchWithErr = mkFetchWithErr(conf.fetch);

const fetchFeedConf = {
raiBaseUrl: conf.raiBaseUrl,
poolSize: conf.poolSize,
fetchWithErr,
logger: conf.logger,
};
const fetchFeed = (request: Request) => feedHandler(fetchFeedConf, request);
const fetchFeed = (request: Request) => feedHandler(conf, request);

const router = Router()
.get("/programmi/:feed.xml", fetchFeed)
Expand Down

0 comments on commit cf5b30e

Please sign in to comment.