diff --git a/package.json b/package.json index 85f6c07..4820956 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "react-dom": "19", "react-hook-form": "^7.54.2", "sonner": "^1.4.41", + "swr": "^2.3.0", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7", "valtio": "^2.1.2", diff --git a/src/app/(protected)/api/livekit/broadcasterToken/route.ts b/src/app/(protected)/api/livekit/broadcasterToken/route.ts index d248867..ee0f1b1 100644 --- a/src/app/(protected)/api/livekit/broadcasterToken/route.ts +++ b/src/app/(protected)/api/livekit/broadcasterToken/route.ts @@ -1,25 +1,38 @@ +import { validateRequest } from '@/lib/auth'; import { ingressClient, roomService } from '@/lib/services/livekit'; import { IngressInput } from 'livekit-server-sdk'; -export async function GET(request: Request) { - const { searchParams } = new URL(request.url); - const room = searchParams.get('room'); +export async function GET() { + const { user } = await validateRequest(); - if (!room) { - return new Response('Missing room', { status: 400 }); + if (!user) { + return new Response('Unauthorized', { status: 401 }); } + // delete all ingresses, deprecation should be fine :clueless: + const ingresses = await ingressClient.listIngress(); + const userIngresses = ingresses.filter(ingress => ingress.name === user.username); + + for (const ingress of userIngresses) { + await ingressClient.deleteIngress(ingress.ingressId); + } + + // dleete and recreate room + const room = (await roomService.listRooms()).filter((r) => r.name === user.username)[0]; + if (room) { + await roomService.deleteRoom(room.name); + } + await roomService.createRoom({ - name: room, - }) - const ingress = await ingressClient.createIngress( - IngressInput.RTMP_INPUT, - { - name: room, - roomName: room, - participantIdentity: 'streamer', - } - ) + name: user.username, + }); + + // create new ingress + const ingress = await ingressClient.createIngress(IngressInput.RTMP_INPUT, { + name: user.username, + roomName: user.username, + participantIdentity: 'streamer', + }); return Response.json({ key: ingress.streamKey }); } \ No newline at end of file diff --git a/src/components/app/EditLivestream/EditLivestream.tsx b/src/components/app/EditLivestream/EditLivestream.tsx index 21826e2..9ce89c4 100644 --- a/src/components/app/EditLivestream/EditLivestream.tsx +++ b/src/components/app/EditLivestream/EditLivestream.tsx @@ -12,6 +12,7 @@ import prisma from '@/lib/db'; import { roomService } from '@/lib/services/livekit'; import { UniversalForm } from '../UniversalForm/UniversalForm'; import { editStreamInfo } from '@/lib/form/actions'; +import RegenerateKey from '../RegenerateKey/RegenerateKey'; export default async function EditLivestream() { const { user } = await validateRequest(); @@ -55,6 +56,9 @@ export default async function EditLivestream() { action={editStreamInfo} submitButtonDivClassname="float-right" submitText="Save" + otherSubmitButton={ + + } key={streamInfo?.id} /> diff --git a/src/components/app/RegenerateKey/RegenerateKey.tsx b/src/components/app/RegenerateKey/RegenerateKey.tsx new file mode 100644 index 0000000..7c258ab --- /dev/null +++ b/src/components/app/RegenerateKey/RegenerateKey.tsx @@ -0,0 +1,37 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { fetcher as defaultFetcher } from '@/lib/services/swr'; +import React from 'react'; +import { toast } from 'sonner'; +import useSWR from 'swr/mutation'; + +export default function RegenerateKey() { + const { error, isMutating, trigger } = useSWR('/api/livekit/broadcasterToken', async (url) => + defaultFetcher(url) + ); + + React.useEffect(() => { + if (error) { + toast.error(error); + } + }, [error]); + + return ( + + ); +} diff --git a/src/lib/services/swr.ts b/src/lib/services/swr.ts new file mode 100644 index 0000000..ee9c742 --- /dev/null +++ b/src/lib/services/swr.ts @@ -0,0 +1,3 @@ +type FetcherArgs = Parameters; + +export const fetcher = (...args: FetcherArgs): Promise => fetch(...args).then(res => res.json()); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 93b0366..f582b52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1807,6 +1807,11 @@ define-properties@^1.1.3, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + detect-libc@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" @@ -4255,6 +4260,14 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +swr@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/swr/-/swr-2.3.0.tgz#66fa45023efd4199f4e7ce608c255709a135943d" + integrity sha512-NyZ76wA4yElZWBHzSgEJc28a0u6QZvhb6w0azeL2k7+Q1gAzVK+IqQYXhVOC/mzi+HZIozrZvBVeSeOZNR2bqA== + dependencies: + dequal "^2.0.3" + use-sync-external-store "^1.4.0" + tailwind-merge@^2.2.2: version "2.6.0" resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.6.0.tgz#ac5fb7e227910c038d458f396b7400d93a3142d5" @@ -4500,6 +4513,11 @@ use-sidecar@^1.1.2: detect-node-es "^1.1.0" tslib "^2.0.0" +use-sync-external-store@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz#adbc795d8eeb47029963016cefdf89dc799fcebc" + integrity sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw== + usehooks-ts@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-3.1.0.tgz#156119f36efc85f1b1952616c02580f140950eca"