Skip to content

Commit

Permalink
feat: add live worker (#3860)
Browse files Browse the repository at this point in the history
  • Loading branch information
bigint committed Oct 3, 2023
2 parents 8a8d1d2 + fffb11e commit d08e878
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/workers/live/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
LIVEPEER_API_KEY=""
6 changes: 6 additions & 0 deletions packages/workers/live/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
extends: [require.resolve('@hey/config/eslint/base.js')],
rules: {
'import/no-anonymous-default-export': 'off'
}
};
1 change: 1 addition & 0 deletions packages/workers/live/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Live worker
29 changes: 29 additions & 0 deletions packages/workers/live/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@workers/live",
"version": "0.0.0",
"private": true,
"license": "AGPL-3.0",
"scripts": {
"dev": "wrangler dev --port 8096",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --fix --ext .ts",
"prettier": "prettier --check \"**/*.{js,ts,tsx,md}\" --cache",
"prettier:fix": "prettier --write \"**/*.{js,ts,tsx,md}\" --cache",
"start": "pnpm dev",
"typecheck": "tsc --pretty",
"worker:deploy": "wrangler deploy --var RELEASE:\"$(git rev-parse HEAD)\""
},
"dependencies": {
"@hey/data": "workspace:*",
"@hey/lib": "workspace:*",
"@tsndr/cloudflare-worker-jwt": "^2.2.2",
"itty-router": "^4.0.23",
"zod": "^3.22.2"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20230922.0",
"@hey/config": "workspace:*",
"typescript": "^5.2.2",
"wrangler": "^3.10.1"
}
}
72 changes: 72 additions & 0 deletions packages/workers/live/src/handlers/createStream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Errors } from '@hey/data/errors';
import hasOwnedLensProfiles from '@hey/lib/hasOwnedLensProfiles';
import response from '@hey/lib/response';
import validateLensAccount from '@hey/lib/validateLensAccount';
import jwt from '@tsndr/cloudflare-worker-jwt';
import { boolean, object, string } from 'zod';

import type { WorkerRequest } from '../types';

type ExtensionRequest = {
id: string;
isMainnet: boolean;
};

const validationSchema = object({
id: string(),
isMainnet: boolean()
});

export default async (request: WorkerRequest) => {
const body = await request.json();
if (!body) {
return response({ success: false, error: Errors.NoBody });
}

const accessToken = request.headers.get('X-Access-Token');
if (!accessToken) {
return response({ success: false, error: Errors.NoAccessToken });
}

const validation = validationSchema.safeParse(body);

if (!validation.success) {
return response({ success: false, error: validation.error.issues });
}

const { id, isMainnet } = body as ExtensionRequest;

try {
const isAuthenticated = await validateLensAccount(accessToken, isMainnet);
if (!isAuthenticated) {
return response({ success: false, error: Errors.InvalidAccesstoken });
}

const { payload } = jwt.decode(accessToken);
const hasOwned = await hasOwnedLensProfiles(payload.id, id, isMainnet);
if (!hasOwned) {
return response({ success: false, error: Errors.InvalidProfileId });
}

const livepeerResponse = await fetch('https://livepeer.studio/api/stream', {
method: 'POST',
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${request.env.LIVEPEER_API_KEY}`
},
body: JSON.stringify({
name: `${id}-${crypto.randomUUID()}`,
profiles: [
{ name: '480p0', fps: 0, bitrate: 1600000, width: 854, height: 480 },
{ name: '720p0', fps: 0, bitrate: 3000000, width: 1280, height: 720 }
]
})
});

const result = await livepeerResponse.json();

return response({ success: true, result: result });
} catch (error) {
throw error;
}
};
16 changes: 16 additions & 0 deletions packages/workers/live/src/helpers/buildRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Env, WorkerRequest } from '../types';

const buildRequest = (
request: Request,
env: Env,
ctx: ExecutionContext
): WorkerRequest => {
const temp: WorkerRequest = request as WorkerRequest;
temp.req = request;
temp.env = env;
temp.ctx = ctx;

return temp;
};

export default buildRequest;
43 changes: 43 additions & 0 deletions packages/workers/live/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Errors } from '@hey/data/errors';
import response from '@hey/lib/response';
import { createCors, error, Router, status } from 'itty-router';

import createStream from './handlers/createStream';
import buildRequest from './helpers/buildRequest';
import type { Env, WorkerRequest } from './types';

const { preflight, corsify } = createCors({
origins: ['*'],
methods: ['HEAD', 'GET', 'POST']
});

const router = Router();

router
.all('*', preflight)
.head('*', () => status(200))
.get('/', (request: WorkerRequest) =>
response({
message: 'gm, to live service 👋',
version: request.env.RELEASE ?? 'unknown'
})
)
.post('/create', createStream)
.all('*', () => error(404));

export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const incomingRequest = buildRequest(request, env, ctx);

return await router
.handle(incomingRequest)
.then(corsify)
.catch(() => {
return error(500, Errors.InternalServerError);
});
}
};
12 changes: 12 additions & 0 deletions packages/workers/live/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { IRequestStrict } from 'itty-router';

export interface Env {
RELEASE: string;
LIVEPEER_API_KEY: string;
}

export type WorkerRequest = {
req: Request;
env: Env;
ctx: ExecutionContext;
} & IRequestStrict;
6 changes: 6 additions & 0 deletions packages/workers/live/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "@hey/config/base.tsconfig.json",
"compilerOptions": {
"types": ["@cloudflare/workers-types"]
}
}
16 changes: 16 additions & 0 deletions packages/workers/live/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name = "live"
main = "src/index.ts"
compatibility_date = "2023-01-25"
keep_vars = true
node_compat = true

routes = [
{ pattern = "live.hey.xyz", custom_domain = true }
]

[placement]
mode = "smart"

[env.production.vars]
RELEASE = ""
LIVEPEER_API_KEY = ""
31 changes: 31 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 comments on commit d08e878

@vercel
Copy link

@vercel vercel bot commented on d08e878 Oct 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

prerender – ./apps/prerender

prerender-git-main-heyxyz.vercel.app
prerender-heyxyz.vercel.app
prerender.hey.xyz

@vercel
Copy link

@vercel vercel bot commented on d08e878 Oct 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

web – ./apps/web

web-heyxyz.vercel.app
heyxyz.vercel.app
web-git-main-heyxyz.vercel.app
hey.xyz

Please sign in to comment.