realtime twitch overlay update
Answered
JCo posted this in #help-forum
JCoOP
If I have a next site with an api on it that is triggered by an app, discord bot or game action separate of the site, but it live updates a twitch overlay (expected behaviour), what is the best way to keep the overlay up to date? Webhooks based on the player id? Or something else?
32 Replies
JCoOP
import { getSession } from "@/lib/dbFunctions/session";
import { getDivision } from "@/lib/utils";
interface OverlayPageProps {
params: {
id: string;
};
}
const getStats = async (discordId: string) => {
const session = await getSession(
discordId,
Number(process.env.CURR_SEASON!)
);
if (!session)
return {
w: 0,
l: 0,
sr: 0,
division: "Bronze 1",
};
const division = getDivision(session.currentSr);
return {
w: session.wins,
l: session.losses,
sr: session.currentSr,
division,
};
};
const OverlayPage = async ({ params }: OverlayPageProps) => {
const { id } = params;
const { w, l, sr, division } = await getStats(id);
return id === "415067295715557376" ? (
<div className="flex flex-row text-6xl gap-0 w-full ">
<div className="p-4 flex flex-col">
<p>
W: {w} / L: {l}
</p>
<p>SR: {sr}</p>
<p>{division}</p>
</div>
</div>
) : (
<div className="flex flex-row text-6xl gap-3">Coming Soon</div>
);
};
export default OverlayPage;
This is the code for the page, tracking the stats etc. But I don't know the best way to modify this so that it updates in near realtime. I asked ChatGPT and it said SSE and Websockets. But which is the better option for this usecase?If the twitch overlay data is something you can put into nextjs unstable cache
Then your webhook can invalidate that cache key
JCoOP
I don’t think it is. It makes a db call to get the session, then when it’s changed I want it to re-fetch the data from the db then update what’s displayed. So websockets?
@linesofcode If the twitch overlay data is something you can put into nextjs unstable cache
JCoOP
Is this a good solution or would you recommend a better option? given a discord bot currently runs the update session route on the api, then the data needs to update on the overlay for the correct user.
where is the data from the twitch overlay coming from
JCoOP
A database call
then the solution I provided above will work
JCoOP
export const getSession = async (
discordId: Session["userId"],
season: Session["season"]
) => {
const session = await db.session.findFirst({
where: {
userId: discordId,
season,
},
});
return session;
};
discordId: Session["userId"],
season: Session["season"]
) => {
const session = await db.session.findFirst({
where: {
userId: discordId,
season,
},
});
return session;
};
if you put it through a caching layer
JCoOP
Do you have any docs I can review to understand that concept?
what chatgpt says about polling will work too
but if you care about your traffic and need realtime it's not a feasible solution
websockets will work too but not if you're deploying to a serverless infrastracture
JCoOP
Need realtime
unless you spin up a websocket server
JCoOP
And I deploy to vercel
personally
I would just do polling
JCoOP
To call my getSession() function?
if your traffic is negligble
JCoOP
probably 1000 users at max as its a paid feature of a new discord bot.
But I want to build ahead to scalability, which is unstable_cache I presume?
if you want to build something scalable
then you need websockets
and a dedicated websocket server(s)
you can also checkout a service called pusher
Answer
which is websockets as a service
JCoOP
I’ll use pusher then
JCoOP
"use client";
import { getSession } from "@/lib/dbFunctions/session";
import { pusherClient } from "@/lib/pusher/client";
import { getDivision } from "@/lib/utils";
import { useEffect, useState } from "react";
interface OverlayPageProps {
params: {
id: string;
};
}
const OverlayPage = async ({ params }: OverlayPageProps) => {
const { id } = params;
const [stats, setStats] = useState({
w: 0,
l: 0,
sr: 0,
division: "Bronze 1",
});
const getStats = async (discordId: string) => {
const session = await getSession(
discordId,
Number(process.env.CURR_SEASON!)
);
if (session) {
setStats({
w: session.wins,
l: session.losses,
sr: session.currentSr,
division: getDivision(session.currentSr),
});
}
};
useEffect(() => {
// Fetch initial stats
getStats(id);
// Subscribe to a channel specific to the user
const channel = pusherClient.subscribe(`user-${id}`);
// Listen for an event with updated stats
channel.bind(
"stats-updated",
(data: { w: number; l: number; sr: number }) => {
setStats({
w: data.w,
l: data.l,
sr: data.sr,
division: getDivision(data.sr),
});
}
);
return () => {
channel.unsubscribe();
pusherClient.disconnect();
};
}, [id]);
return id === "415067295715557376" ? (
<div className="flex flex-row text-6xl gap-0 w-full ">
<div className="p-4 flex flex-col">
<p>
W: {stats.w} / L: {stats.l}
</p>
<p>SR: {stats.sr}</p>
<p>{stats.division}</p>
</div>
</div>
) : (
<div className="flex flex-row text-6xl gap-3">Coming Soon</div>
);
};
export default OverlayPage;
Seems to work