diff --git a/apps/chat/src/index.ts b/apps/chat/src/index.ts index 50111be..6fc14b1 100644 --- a/apps/chat/src/index.ts +++ b/apps/chat/src/index.ts @@ -7,6 +7,7 @@ import { getCookie } from 'hono/cookie'; import { getPersonalChannel } from './utils/personalChannel.js'; import { getRedisConnection, prisma, type User } from '@hctv/db'; import uFuzzy from '@leeoniya/ufuzzy'; +import { randomString } from './utils/randomString.js'; const redis = getRedisConnection(); const MESSAGE_HISTORY_SIZE = 15; @@ -68,8 +69,6 @@ app.get( return; } - // ignoring user here which might be undefined so - const { username } = c.req.param(); if (dbGrant && dbGrant?.name !== username) { ws.close(); @@ -77,6 +76,7 @@ app.get( } ws.targetUsername = username; ws.user = user; + ws.viewerId = randomString(10); if (ws.raw) { ws.raw.targetUsername = username; // @ts-ignore @@ -96,18 +96,6 @@ app.get( }) ); } - if (token && grant === 'null') { - await prisma.streamInfo.update({ - where: { - username, - }, - data: { - viewers: { - increment: 1, - }, - }, - }); - } }, async onClose(evt, ws) { // if prematurely exiting due to authentication issues @@ -125,18 +113,12 @@ app.get( if (!streamInfo) return; - await prisma.streamInfo.update({ - where: { - username: ws.targetUsername, - }, - data: { - viewers: streamInfo.viewers === 0 ? { set: 0 } : { decrement: 1 }, - }, - }); + await redis.del(`viewer:${ws.targetUsername}:${ws.viewerId}`); }, async onMessage(evt, ws) { const msg = JSON.parse(evt.data.toString()); if (msg.type === 'ping') { + await redis.setex(`viewer:${ws.targetUsername}:${ws.viewerId}`, 30, '1'); ws.send( JSON.stringify({ type: 'pong', diff --git a/apps/chat/src/utils/randomString.ts b/apps/chat/src/utils/randomString.ts new file mode 100644 index 0000000..39097e1 --- /dev/null +++ b/apps/chat/src/utils/randomString.ts @@ -0,0 +1,8 @@ +export function randomString(length: number): string { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + for (let i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; +} \ No newline at end of file diff --git a/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx b/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx index 75e5a47..8940a33 100644 --- a/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx +++ b/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx @@ -621,7 +621,7 @@ export default function ChannelSettingsClient({

Chat overlay

- Add a 300x600 browser source with this and enjoy! + Add a 300x600 browser source with this and enjoy!

diff --git a/apps/web/src/instrumentation.ts b/apps/web/src/instrumentation.ts index 51b80bd..92fc678 100644 --- a/apps/web/src/instrumentation.ts +++ b/apps/web/src/instrumentation.ts @@ -33,4 +33,11 @@ export async function register() { const { emojisWriteRedis } = await import('@/lib/instrumentation/emojisWriteRedis'); await emojisWriteRedis(); } + + if (process.env.NEXT_RUNTIME === 'nodejs') { + const { viewerCountSync } = await import('@/lib/instrumentation/viewerCountSync'); + setInterval(async () => { + await viewerCountSync(); + }, 2000); + } } diff --git a/apps/web/src/lib/instrumentation/viewerCountSync.ts b/apps/web/src/lib/instrumentation/viewerCountSync.ts new file mode 100644 index 0000000..e4fa349 --- /dev/null +++ b/apps/web/src/lib/instrumentation/viewerCountSync.ts @@ -0,0 +1,22 @@ +import { getRedisConnection, prisma } from "@hctv/db"; + +export async function viewerCountSync() { + const streams = await prisma.streamInfo.findMany({ + include: { + channel: true + } + }) + const redis = getRedisConnection(); + + for (const stream of streams) { + const viewerCount = await redis.keys(`viewer:${stream.channel.name}:*`); + await prisma.streamInfo.update({ + where: { + username: stream.username, + }, + data: { + viewers: viewerCount.length, + }, + }); + } +} \ No newline at end of file diff --git a/packages/hono-ws/src/index.ts b/packages/hono-ws/src/index.ts index d2253f4..fcb165e 100644 --- a/packages/hono-ws/src/index.ts +++ b/packages/hono-ws/src/index.ts @@ -248,6 +248,7 @@ interface ModifiedWSContext extends WSContext { targetUsername?: string; user?: any; personalChannel?: any; + viewerId?: string; } export interface ModifiedWebSocket extends WebSocket {