feat: improved viewercount

This commit is contained in:
2025-08-09 20:36:58 +02:00
parent 1fa8c59c33
commit 2dc28ae8d9
6 changed files with 43 additions and 23 deletions

View File

@@ -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',

View File

@@ -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;
}

View File

@@ -621,7 +621,7 @@ export default function ChannelSettingsClient({
<div>
<h3 className="text-lg font-semibold mb-2">Chat overlay</h3>
<p className="text-sm text-mantle-foreground mb-4">
Add a 300x600 browser source with this and enjoy!
Add a 300x600 browser source with this and enjoy!
</p>
<div className="flex items-center gap-2">
<div className="relative flex-1">

View File

@@ -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);
}
}

View File

@@ -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,
},
});
}
}

View File

@@ -248,6 +248,7 @@ interface ModifiedWSContext extends WSContext<ModifiedWebSocket> {
targetUsername?: string;
user?: any;
personalChannel?: any;
viewerId?: string;
}
export interface ModifiedWebSocket extends WebSocket {