Browse Source

feat: check stream key

vlc was not cooperating with me so the actual stream might be broken rn

the backend will deny any key that doesn't exist and also look up the
user for future use, though
pull/9/head
auctumnus 4 weeks ago
parent
commit
273f0b7081
Signed by: autumn GPG Key ID: 4E7B627467259C47
  1. 2
      backend.Dockerfile
  2. 2
      frontend.Dockerfile
  3. 17
      nginx.conf.template
  4. 8
      src/server/server.ts
  5. 73
      src/server/webhooks/index.ts

2
backend.Dockerfile

@ -3,7 +3,7 @@ FROM node:12-alpine
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install
EXPOSE 4000
CMD yarn run:server /conf/config.json

2
frontend.Dockerfile

@ -3,7 +3,7 @@ FROM node:12-alpine
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install
RUN NEXT_PUBLIC_API_URL=http://localhost:1337/api/graphql yarn build:client:docker
EXPOSE 3000
CMD yarn run:client

17
nginx.conf.template

@ -33,20 +33,21 @@ rtmp {
live on;
record off;
# Deny listening to this endpoint for non-localhost.
allow play 127.0.0.1;
deny play all;
exec_push /usr/local/bin/ffmpeg -i rtmp://localhost:1935/$app/$name -async 1 -vsync -1
# Callback for when a stream begins.
# On 2xx: Allows streaming.
# On 3xx: Redirects? Not sure what that would be, honestly.
# On 4xx: Denies streaming.
on_publish http://miracle-backend:4000/hook/on_publish;
on_publish "http://miracle-backend:4000/api/hook/on_publish?name=$uri";
# Callback for when a stream stops.
on_publish_done http://miracle-backend:4000/hook/on_publish_done;
on_publish_done http://miracle-backend:4000/api/hook/on_publish_done;
# Deny listening to this endpoint for non-localhost.
allow play 127.0.0.1;
deny play all;
exec_push /usr/local/bin/ffmpeg -i rtmp://localhost:1935/$app/$name -async 1 -vsync -1;
}
# Application for receiving.

8
src/server/server.ts

@ -4,6 +4,7 @@ import { setupDB } from "miracle-tv-server/db/setup-db";
import { graphqlUploadExpress } from "graphql-upload";
import config from "miracle-tv-server/config";
import { green } from "chalk";
import webhooks from "miracle-tv-server/webhooks";
const { pathPrefix, dataDir } = config;
// app.get("/", (_, res) => res.send("FUCK!"));
@ -15,11 +16,14 @@ const main = async () => {
await setupDB();
await graphqlEndpoint.start();
const app = Express();
const prefix = pathPrefix ? `/${pathPrefix}/` : '/'
app.use(Express.urlencoded())
const prefix = pathPrefix ? `/${pathPrefix}/` : '/';
app.use(graphqlUploadExpress());
app.use(`${prefix}media/`, Express.static(`${dataDir}/media`));
app.use(`${prefix}hook/`, webhooks)
const graphqlPath = prefix + 'graphql'
graphqlEndpoint.applyMiddleware({ app, path: prefix + 'graphql' });
graphqlEndpoint.applyMiddleware({ app, path: graphqlPath });
app.listen(
config.server?.port || 4000,
config.server?.hostname || "0.0.0.0",

73
src/server/webhooks/index.ts

@ -1,13 +1,72 @@
import { Router } from "express";
import { Request, Response, Router } from "express";
import {StreamKeysModel} from "miracle-tv-server/db/models/StreamKeys";
import {UsersModel} from "miracle-tv-server/db/models/Users";
import { connection } from "miracle-tv-server/db/setup-db"
import { ChanelsModel } from "miracle-tv-server/db/models/Channels"
export const webhooks = Router();
const webhooks = Router();
webhooks.all('on_publish', (req, res) => {
console.log('on_publish')
res.status(200).send()
const getStreamKey = async (req: Request, res: Response) => {
const { body } = req
if(!body || !body.name || !(typeof body.name === 'string')) {
res.status(400).send()
return undefined
}
// This is the ID of the stream key.
const { name } = body
// database setup
const con = await connection;
const streamKeys = new StreamKeysModel(con);
const result = await streamKeys.getStreamKeyById(name)
// The result comes in a `StreamKey`, which is generated from the GraphQL
// schema. The GraphQL schema doesn't match what comes from the database,
// so this cast should be safe.
return (result as unknown) as ReturnedKey | undefined
}
const getUser = async (id: string) => {
const con = await connection;
const users = new UsersModel(con)
return await users.getUserById(id)
}
const getChannel = async (id: string) => {
const con = await connection;
const channels = new ChanelsModel(con);
return await channels.getChannelById(id)
}
interface ReturnedKey {
id: string
channelId: string
userId: string
}
webhooks.post('/on_publish', async (req, res) => {
const streamKey = await getStreamKey(req, res)
// If there's no stream key, deny the stream.
if(!streamKey) {
res.status(403).send()
return undefined
}
// const user = getUser(streamKey.userId)
//const channel = await getChannel(streamKey.channelId)
// We need to redirect the stream to a location that doesn't include the stream
// key. This may not be the right way to do it; TODO: ensure the stream still works
res
.header('Location', streamKey.channelId)
.status(300)
.send()
})
webhooks.all('on_publish_done', (req, res) => {
console.log('on_publish_done')
webhooks.post('/on_publish_done', async (req, res) => {
const streamKey = await getStreamKey(req, res)
res.status(200).send()
})
export default webhooks
Loading…
Cancel
Save