From 0c38345bd170a66057c1337cc15ccd9706486fc9 Mon Sep 17 00:00:00 2001 From: dragongoose <19649813+dragongoose@users.noreply.github.com> Date: Fri, 17 Mar 2023 22:58:06 -0400 Subject: [PATCH] Working IRC proxy --- server/routes/proxyRoute.ts | 73 +++++++++++++++++++++++++++++-- server/util/scraping/chat/chat.ts | 9 +++- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/server/routes/proxyRoute.ts b/server/routes/proxyRoute.ts index baa24d4..8206137 100644 --- a/server/routes/proxyRoute.ts +++ b/server/routes/proxyRoute.ts @@ -1,6 +1,7 @@ import { Router, Response, Request, NextFunction } from 'express' import { TwitchAPI } from '../util/scraping/extractor'; -import ws from 'ws'; +import ws, { WebSocket } from 'ws'; +import { TwitchChat } from '../util/scraping/chat/chat'; const proxyRouter = Router(); const twitch = new TwitchAPI() @@ -56,12 +57,76 @@ proxyRouter.get('/hls/:encodedUrl' , async (req: Request, res: Response, next: N // IRC PROXY +interface ExtWebSocket extends WebSocket { + id: string; +} + +const chat = new TwitchChat({ + login: { + username: 'justinfan23423', + password: 'none' + }, + channels: [] +}) +chat.connect() + + const clients : { [k:string]: ExtWebSocket[] } = {} +import { randomUUID } from 'crypto'; + +const findClientsForStreamer = async (streamerName: string) => { + if(!clients[streamerName]) return Promise.reject(new Error('No clients following streamer')) + + return clients[streamerName] +} + export const wsServer = new ws.Server({ noServer: true }); -wsServer.on('connection', (socket: ws.WebSocket) => { - socket.send('Welcome! Send a comma seperated list to get the IRC') - socket.on('message', message => console.log(message.toString())); +wsServer.on('connection', (ws: ExtWebSocket) => { + const socket = ws as ExtWebSocket + socket.on('message', (message) => { + const data = message.toString() + const splitted = data.split(' ') + + if(splitted.length > 2) socket.close() + if(splitted[0] !== 'JOIN') socket.close() + + const streamersToJoin = splitted[1].split(',') + if(streamersToJoin.length > 1) socket.close() + + const id = randomUUID() + for (let streamer of streamersToJoin) { + chat.addStreamer(streamer) + + if(clients[streamer]) { + clients[streamer].push(socket) + } else { + clients[streamer] = [socket] + } + } + socket.id = id + socket.send('OK') + + + }); + + socket.on('close', () => { + if(socket.id) { + } + }) }); +chat.on('PRIVMSG', async (username, type, channel, message) => { + const socketsToSend = await findClientsForStreamer(channel) + for(let socket of socketsToSend) { + let payload = { + username, + type, + channel, + message + } + socket.send(JSON.stringify(payload)) + } +}) + export default proxyRouter \ No newline at end of file diff --git a/server/util/scraping/chat/chat.ts b/server/util/scraping/chat/chat.ts index 8b8e021..5e021ec 100644 --- a/server/util/scraping/chat/chat.ts +++ b/server/util/scraping/chat/chat.ts @@ -11,6 +11,7 @@ export class TwitchChat extends EventEmitter{ public channels: string[] private url = 'wss://irc-ws.chat.twitch.tv:443' private ws: WebSocket | null; + private isConnected: boolean = false constructor(options: TwitchChatOptions) { super() @@ -31,7 +32,7 @@ export class TwitchChat extends EventEmitter{ let parsedMetadata: Metadata = { username: parseUsername(metadata[0]), messageType: metadata[1], - channel: metadata[2], + channel: metadata[2].replace('#', ''), message: message } @@ -45,6 +46,7 @@ export class TwitchChat extends EventEmitter{ public async connect() { this.ws = new WebSocket(this.url) + this.isConnected = true this.ws.on('open', () => { if(this.ws) { @@ -62,4 +64,9 @@ export class TwitchChat extends EventEmitter{ } + public addStreamer(streamerName: string) { + if(!this.isConnected) return; + this.ws!.send(`JOIN #${streamerName}`) + } + }