Skip to content

Commit

Permalink
Replaced ts-rest with Elysia
Browse files Browse the repository at this point in the history
  • Loading branch information
matvp91 committed Oct 10, 2024
1 parent e8cc50a commit 703e5cf
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 163 deletions.
2 changes: 1 addition & 1 deletion packages/dashboard/src/pages/PlayerPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function PlayerPage() {
const [error, setError] = useState<object>();

useEffect(() => {
fetch(`${import.meta.env.PUBLIC_STITCHER_ENDPOINT}/spec.json`)
fetch(`${import.meta.env.PUBLIC_STITCHER_ENDPOINT}/swagger/json`)
.then((response) => response.json())
.then((data) => {
setSchema(
Expand Down
9 changes: 9 additions & 0 deletions packages/player/src/facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,17 @@ export class HlsFacade extends EventEmitter<Events> {
}
};

private tempMediaCache_?: HTMLMediaElement;

private get media_() {
if (this.tempMediaCache_) {
return this.tempMediaCache_;
}
assert(this.hls.media, "Missing media element");

// This is temporary. Until we find a better way to manage (multiple) media elements.
this.tempMediaCache_ = this.hls.media;

return this.hls.media;
}

Expand Down
9 changes: 3 additions & 6 deletions packages/stitcher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@
"typescript": "^5.5.4"
},
"dependencies": {
"@fastify/cors": "^9.0.1",
"@fastify/error": "^4.0.0",
"@elysiajs/cors": "^1.1.1",
"@elysiajs/swagger": "^1.1.5",
"@mixwave/artisan": "workspace:*",
"@mixwave/shared": "workspace:*",
"@ts-rest/core": "^3.49.3",
"@ts-rest/fastify": "^3.49.3",
"@ts-rest/open-api": "^3.49.3",
"@xmldom/xmldom": "^0.8.10",
"dom-parser": "^1.1.5",
"fastify": "^4.28.1",
"elysia": "^1.1.20",
"hh-mm-ss": "^1.2.0",
"lru-cache": "^11.0.1",
"luxon": "^3.5.0",
Expand Down
1 change: 0 additions & 1 deletion packages/stitcher/src/const.ts

This file was deleted.

59 changes: 0 additions & 59 deletions packages/stitcher/src/contract.ts

This file was deleted.

25 changes: 0 additions & 25 deletions packages/stitcher/src/errors.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/stitcher/src/filters.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { FilterResolutionInvalidError } from "./errors";
import type { MasterPlaylist, Variant } from "./parser";
import type { SessionFilter } from "./session";

Expand All @@ -16,7 +15,7 @@ function getResolutionFilter(resolution: string) {
const fn = FILTER_VARIANTS_OPERATOR[operator];

if (Number.isNaN(height) || typeof fn !== "function") {
throw new FilterResolutionInvalidError(resolution);
throw new Error(`Resolution filter with value "${resolution}" is invalid.`);
}

return [height, fn];
Expand Down
124 changes: 76 additions & 48 deletions packages/stitcher/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import Fastify from "fastify";
import cors from "@fastify/cors";
import { initServer } from "@ts-rest/fastify";
import { Elysia, t } from "elysia";
import { cors } from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
import { env } from "./env";
import { contract } from "./contract";
import { openApiSpec } from "./openapi";
import { createSession } from "./session";
import { validateFilter } from "./filters";
import { getMasterUrl } from "./url";
Expand All @@ -13,15 +11,12 @@ import {
formatAssetList,
} from "./playlist";

async function buildServer() {
const app = Fastify();

app.register(cors);

const s = initServer();

const router = s.router(contract, {
postSession: async ({ body }) => {
const app = new Elysia()
.use(cors())
.use(swagger())
.post(
"/session",
async ({ body }) => {
// This'll fail when uri is invalid.
getMasterUrl(body.uri);

Expand All @@ -34,44 +29,77 @@ async function buildServer() {
const session = await createSession(body);

return {
status: 200,
body: {
url: `${env.PUBLIC_STITCHER_ENDPOINT}/session/${session.id}/master.m3u8`,
session,
},
url: `${env.PUBLIC_STITCHER_ENDPOINT}/session/${session.id}/master.m3u8`,
};
},
getMasterPlaylist: async ({ params, reply }) => {
const response = await formatMasterPlaylist(params.sessionId);
return reply.type("application/x-mpegURL").send(response);
{
body: t.Object({
uri: t.String(),
interstitials: t.Optional(
t.Array(
t.Object({
timeOffset: t.Number(),
uri: t.String(),
type: t.Optional(t.Union([t.Literal("ad"), t.Literal("bumper")])),
}),
),
),
filter: t.Optional(
t.Object({
resolution: t.Optional(t.String()),
}),
),
vmap: t.Optional(
t.Object({
url: t.String(),
}),
),
}),
},
getMediaPlaylist: async ({ params, reply }) => {
const response = await formatMediaPlaylist(params.sessionId, params["*"]);
return reply.type("application/x-mpegURL").send(response);
)
.get(
"/session/:sessionId/master.m3u8",
async ({ set, params }) => {
const playlist = await formatMasterPlaylist(params.sessionId);
set.headers["content-type"] = "application/x-mpegURL";
return playlist;
},
getAssetList: async ({ query, params }) => {
return {
status: 200,
body: await formatAssetList(params.sessionId, query.startDate),
};
{
params: t.Object({
sessionId: t.String(),
}),
},
getSpec: async () => {
return {
status: 200,
body: openApiSpec,
};
)
.get(
"/session/:sessionId/*",
async ({ set, params }) => {
const playlist = await formatMediaPlaylist(params.sessionId, params["*"]);
set.headers["content-type"] = "application/x-mpegURL";
return playlist;
},
});

app.register(s.plugin(router));

return app;
}

async function main() {
const app = await buildServer();

await app.listen({ host: env.HOST, port: env.PORT });
}
{
params: t.Object({
sessionId: t.String(),
"*": t.String(),
}),
},
)
.get(
"/session/:sessionId/asset-list.json",
async ({ params, query }) => {
return await formatAssetList(params.sessionId, query.startDate);
},
{
params: t.Object({
sessionId: t.String(),
}),
query: t.Object({
startDate: t.String(),
}),
},
);

main();
app.listen({
port: env.PORT,
hostname: env.HOST,
});
11 changes: 0 additions & 11 deletions packages/stitcher/src/openapi.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/stitcher/src/playlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { filterMaster } from "./filters";
import { fetchVmap } from "./vmap";
import { getSession, updateSession } from "./session";
import { getStaticDateRanges, getAssets, getStaticPDT } from "./interstitials";
import { PlaylistNoVariants } from "./errors";

export async function formatMasterPlaylist(sessionId: string) {
const session = await getSession(sessionId);
Expand All @@ -24,7 +23,7 @@ export async function formatMasterPlaylist(sessionId: string) {
}

if (!master.variants.length) {
throw new PlaylistNoVariants();
throw new Error("Playlist has no variants.");
}

return stringifyMasterPlaylist(master);
Expand Down
3 changes: 1 addition & 2 deletions packages/stitcher/src/session.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { randomUUID } from "crypto";
import { DateTime } from "luxon";
import { client } from "./redis";
import { SessionNotFoundError } from "./errors";
import type { VmapResponse } from "./vmap";

export type Session = {
Expand Down Expand Up @@ -66,7 +65,7 @@ export async function getSession(sessionId: string) {
const data = await client.get(redisKey(sessionId));

if (!data) {
throw new SessionNotFoundError(sessionId);
throw new Error(`No session found with id "${sessionId}".`);
}

if (typeof data !== "string") {
Expand Down
3 changes: 1 addition & 2 deletions packages/stitcher/src/url.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as path from "path";
import { env } from "./env";
import { UriInvalidError } from "./errors";

const uuidRegex = /^[a-z,0-9,-]{36,36}$/;

Expand Down Expand Up @@ -29,7 +28,7 @@ export function getMasterUrl(uri: string) {
return `${env.PUBLIC_S3_ENDPOINT}/package/${assetId}/${prefix}/master.m3u8`;
}

throw new UriInvalidError(uri);
throw new Error(`Invalid uri: "${uri}"`);
}

export function joinPath(base: string, ...paths: string[]) {
Expand Down
3 changes: 2 additions & 1 deletion packages/stitcher/src/vast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { addTranscodeJob } from "@mixwave/artisan/producer";
import { VASTClient } from "vast-client";
import { DOMParser } from "@xmldom/xmldom";
import * as uuid from "uuid";
import { NAMESPACE_UUID_AD } from "./const";
import { getMasterUrl, isUrlAvailable } from "./url";
import type { VastResponse, VastCreativeLinear, VastAd } from "vast-client";
import type { VmapAdBreak } from "./vmap";

const NAMESPACE_UUID_AD = "5b212a7e-d6a2-43bf-bd30-13b1ca1f9b13";

export type AdMedia = {
assetId: string;
fileUrl: string;
Expand Down
Loading

0 comments on commit 703e5cf

Please sign in to comment.