diff --git a/src/backend/helpers/chatClient.ts b/src/backend/helpers/chatClient.ts index 69391da..77cf489 100644 --- a/src/backend/helpers/chatClient.ts +++ b/src/backend/helpers/chatClient.ts @@ -7,10 +7,10 @@ import { start } from "./scheduledActions"; let chatClient: ChatClient; export { - chatClient, - connect, - handleClientAction, - say + chatClient, + connect, + handleClientAction, + say }; // TODO: clean/refactor code @@ -18,76 +18,88 @@ export { const LOG_PREFIX = "[ChatClient] "; async function connect(channels: Array): Promise { - const authProvider = await getAuthProvider(); + const authProvider = await getAuthProvider(); - if ( + if ( chatClient && ( - chatClient.isConnecting || - chatClient.isConnected + chatClient.isConnecting || + chatClient.isConnected ) ) { - return; - } + return; + } - chatClient = new ChatClient(authProvider, { channels: channels }); + chatClient = new ChatClient(authProvider, { channels: channels }); - chatClient.onConnect(onConnect); + chatClient.onConnect(onConnect); - chatClient.onDisconnect((e: any) => { - console.log(`${LOG_PREFIX}Disconnected ${e.message}`); - }); + chatClient.onDisconnect((e: any) => { + console.log(`${LOG_PREFIX}Disconnected ${e.message}`); + }); - chatClient.onNoPermission((channel, message) => { - console.log(`${LOG_PREFIX}No permission on ${channel}: ${message}`); - }); + chatClient.onNoPermission((channel, message) => { + console.log(`${LOG_PREFIX}No permission on ${channel}: ${message}`); + }); - await chatClient.connect(); + await chatClient.connect(); } async function onConnect(): Promise { - console.log(`${LOG_PREFIX}Connected`); + console.log(`${LOG_PREFIX}Connected`); - start(); + start(); } async function handleClientAction(action: any): Promise { - if (action.channel && !isNaN(action.channel)) { - action.channel = await getUsernameFromId(parseInt(action.channel)); - } - if (action.username && !isNaN(action.username)) { - action.username = await getUsernameFromId(parseInt(action.username)); - } + if ( + action.channel && + !isNaN(action.channel) + ) { + action.channel = await getUsernameFromId(parseInt(action.channel)); + } - // TODO: create a interface for action messages - if (!action.channel) { - action.channel = "alexbcberio"; - } + if ( + action.username && + !isNaN(action.username) + ) { + action.username = await getUsernameFromId(parseInt(action.username)); + } + + // TODO: create a interface for action messages + if (!action.channel) { + action.channel = "alexbcberio"; + } switch (action.action) { - case "say": - say(action.channel, action.message); - break; - case "timeout": - await timeout(action.channel, action.username, action.time, action.reason); - break; - case "broadcast": - broadcast(action.message); - break; - case "addVip": - await addVip(action.channel, action.username); - break; - case "removeVip": - await removeVip(action.channel, action.username); - break; - default: - console.log(`${[LOG_PREFIX]}Couldn't handle action:`, action); - } + case "say": + say(action.channel, action.message); + break; + case "timeout": + await timeout( + action.channel, + action.username, + action.time, + action.reason + ); + break; + case "broadcast": + broadcast(action.message); + break; + case "addVip": + await addVip(action.channel, action.username); + break; + case "removeVip": + await removeVip(action.channel, action.username); + break; + default: + console.log(`${[LOG_PREFIX]}Couldn't handle action:`, action); + } } // send a chat message async function say(channel: string, message: string): Promise { - await chatClient.say(channel, message); + await chatClient.say(channel, message); } // timeouts a user in a channel @@ -97,37 +109,45 @@ async function timeout( time?: number, reason?: string ): Promise { - if (!time) { - time = 60; - } + if (!time) { + time = 60; + } - if (!reason) { - reason = ""; - } + if (!reason) { + reason = ""; + } - try { - await chatClient.timeout(channel, username, time, reason); - } catch (e) { - // user cannot be timed out - } + try { + await chatClient.timeout(channel, username, time, reason); + } catch (e) { + // user cannot be timed out + } } // adds a user to vips -async function addVip(channel: string, username: string, message?: string): Promise { - if (!message) { - message = `Otorgado VIP a @${username}.`; - } +async function addVip( + channel: string, + username: string, + message?: string +): Promise { + if (!message) { + message = `Otorgado VIP a @${username}.`; + } - await chatClient.addVip(channel, username); - say(channel, message); + await chatClient.addVip(channel, username); + say(channel, message); } // removes a user from vips -async function removeVip(channel: string, username: string, message?: string): Promise { - if (!message) { - message = `VIP de @${username} eliminado.`; - } +async function removeVip( + channel: string, + username: string, + message?: string +): Promise { + if (!message) { + message = `VIP de @${username} eliminado.`; + } - await chatClient.removeVip(channel, username); - say(channel, message); -} \ No newline at end of file + await chatClient.removeVip(channel, username); + say(channel, message); +} diff --git a/src/backend/helpers/pubSubClient.ts b/src/backend/helpers/pubSubClient.ts index 5cfd058..8bb44f1 100644 --- a/src/backend/helpers/pubSubClient.ts +++ b/src/backend/helpers/pubSubClient.ts @@ -7,59 +7,59 @@ import { UserIdResolvable } from "twitch"; import { broadcast } from "./webServer"; export { - registerUserListener -} + registerUserListener +}; // TODO: clean/refactor code const LOG_PREFIX = "[PubSub] "; async function registerUserListener(user: UserIdResolvable) { - const apiClient = await getApiClient(); + const apiClient = await getApiClient(); - const pubSubClient = new PubSubClient(); - const userId = await pubSubClient.registerUserListener(apiClient, user); + const pubSubClient = new PubSubClient(); + const userId = await pubSubClient.registerUserListener(apiClient, user); /*const listener = */ await pubSubClient.onRedemption(userId, onRedemption); - console.log(`${LOG_PREFIX}Connected & registered`); + console.log(`${LOG_PREFIX}Connected & registered`); } async function onRedemption(message: PubSubRedemptionMessage) { console.log( `${LOG_PREFIX}Reward: "${message.rewardName}" (${message.rewardId}) redeemed by ${message.userDisplayName}` ); - // @ts-ignore - const reward = message._data.data.redemption.reward; + // @ts-ignore + const reward = message._data.data.redemption.reward; - const msg = { - id: message.id, - channelId: message.channelId, - rewardId: message.rewardId, - rewardName: message.rewardName, + const msg = { + id: message.id, + channelId: message.channelId, + rewardId: message.rewardId, + rewardName: message.rewardName, rewardImage: message.rewardImage ? message.rewardImage.url_4x : "https://static-cdn.jtvnw.net/custom-reward-images/default-4.png", - message: message.message, - userDisplayName: message.userDisplayName, - // non directly available values from PubSubRedemptionMessage - backgroundColor: reward.background_color - }; + message: message.message, + userDisplayName: message.userDisplayName, + // non directly available values from PubSubRedemptionMessage + backgroundColor: reward.background_color + }; switch (msg.rewardId) { - // robar vip - case "ac750bd6-fb4c-4259-b06d-56953601243b": - if (await stealVip(msg)) { - msg.message = `@${msg.userDisplayName} ha robado el VIP a @${msg.message}.`; + // robar vip + case "ac750bd6-fb4c-4259-b06d-56953601243b": + if (await stealVip(msg)) { + msg.message = `@${msg.userDisplayName} ha robado el VIP a @${msg.message}.`; - broadcast(JSON.stringify(msg)); - } - break; - default: - console.log(LOG_PREFIX, msg); + broadcast(JSON.stringify(msg)); + } + break; + default: + console.log(LOG_PREFIX, msg); - broadcast(JSON.stringify(msg)); - break; - } + broadcast(JSON.stringify(msg)); + break; + } } // TODO: extract methods @@ -70,61 +70,69 @@ async function stealVip(msg: { userDisplayName: string; message: string; }): Promise { - const channel = await getUsernameFromId(parseInt(msg.channelId)); + const channel = await getUsernameFromId(parseInt(msg.channelId)); - if (!channel) { - console.log(`${LOG_PREFIX}No channel found`); + if (!channel) { + console.log(`${LOG_PREFIX}No channel found`); - return false; - } + return false; + } - const addVipUser = msg.userDisplayName; - const removeVipUser = msg.message; + const addVipUser = msg.userDisplayName; + const removeVipUser = msg.message; - if (await hasVip(channel, removeVipUser)) { - await removeVip(channel, removeVipUser); - await addVip(channel, addVipUser); + if (await hasVip(channel, removeVipUser)) { + await removeVip(channel, removeVipUser); + await addVip(channel, addVipUser); const scheduledRemoveVipIndex = scheduledActions.findIndex( s => s.action === "removeVip" && s.username === removeVipUser ); - if (scheduledRemoveVipIndex > -1) { - scheduledActions[scheduledRemoveVipIndex].username = addVipUser; - saveScheduledActions(); - } + if (scheduledRemoveVipIndex > -1) { + scheduledActions[scheduledRemoveVipIndex].username = addVipUser; + saveScheduledActions(); + } - return true; - } + return true; + } - return false; + return false; } // adds a user to vips -async function addVip(channel: string, username: string, message?: string): Promise { - if (!message) { - message = `Otorgado VIP a @${username}.`; - } +async function addVip( + channel: string, + username: string, + message?: string +): Promise { + if (!message) { + message = `Otorgado VIP a @${username}.`; + } - await chatClient.addVip(channel, username); - say(channel, message); + await chatClient.addVip(channel, username); + say(channel, message); } async function hasVip(channel: string, username: string): Promise { - if (!username) { - return false; - } + if (!username) { + return false; + } - const vips = await chatClient.getVips(channel); - return vips.includes(username); + const vips = await chatClient.getVips(channel); + return vips.includes(username); } // removes a user from vips -async function removeVip(channel: string, username: string, message?: string): Promise { - if (!message) { - message = `Se ha acabado el chollo, VIP de @${username} eliminado.`; - } +async function removeVip( + channel: string, + username: string, + message?: string +): Promise { + if (!message) { + message = `Se ha acabado el chollo, VIP de @${username} eliminado.`; + } - await chatClient.removeVip(channel, username); - say(channel, message); -} \ No newline at end of file + await chatClient.removeVip(channel, username); + say(channel, message); +} diff --git a/src/backend/helpers/scheduledActions.ts b/src/backend/helpers/scheduledActions.ts index 52633ba..5b2351f 100644 --- a/src/backend/helpers/scheduledActions.ts +++ b/src/backend/helpers/scheduledActions.ts @@ -3,10 +3,10 @@ import { handleClientAction } from "./chatClient"; import { resolve } from "path"; export { - start, - scheduledActions, - checkScheduledActions, - saveScheduledActions + start, + scheduledActions, + checkScheduledActions, + saveScheduledActions }; const LOG_PREFIX = "[Scheduled] "; @@ -44,7 +44,7 @@ async function start(): Promise { async function checkScheduledActions(): Promise { if (checkingScheduled) { return; - }; + } checkingScheduled = true; diff --git a/src/backend/helpers/tokenData.ts b/src/backend/helpers/tokenData.ts index c95648f..e55104c 100644 --- a/src/backend/helpers/tokenData.ts +++ b/src/backend/helpers/tokenData.ts @@ -1,5 +1,5 @@ import { TokenData } from "../../interfaces/TokenData"; -import {promises as fs} from "fs"; +import { promises as fs } from "fs"; import { resolve } from "path"; const TOKENS_FILE = "tokens.json"; @@ -8,44 +8,45 @@ const LOG_PREFIX = "[TokenData] "; export { getTokenData, saveTokenData -} +}; function getTokenDataFilePath(): string { - return resolve(process.cwd(), TOKENS_FILE); + return resolve(process.cwd(), TOKENS_FILE); } async function getTokenData(): Promise { - const tokenDataFilePath = getTokenDataFilePath(); - let buffer: Buffer; + const tokenDataFilePath = getTokenDataFilePath(); + let buffer: Buffer; - try { - buffer = await fs.readFile(tokenDataFilePath); - } catch (e) { - console.error(`${LOG_PREFIX}${TOKENS_FILE} not found on ${tokenDataFilePath}.`); - process.exit(1); - } + try { + buffer = await fs.readFile(tokenDataFilePath); + } catch (e) { + console.error( + `${LOG_PREFIX}${TOKENS_FILE} not found on ${tokenDataFilePath}.` + ); + process.exit(1); + } - const tokenData = await JSON.parse(buffer.toString()); + const tokenData = await JSON.parse(buffer.toString()); - checkTokenData(tokenData); + checkTokenData(tokenData); - return tokenData; + return tokenData; } async function saveTokenData(tokenData: TokenData): Promise { - const tokenDataFilePath = getTokenDataFilePath(); - const jsonTokenData = JSON.stringify(tokenData); + const tokenDataFilePath = getTokenDataFilePath(); + const jsonTokenData = JSON.stringify(tokenData); - await fs.writeFile(tokenDataFilePath, jsonTokenData); - console.log(`${LOG_PREFIX}Token data saved`); + await fs.writeFile(tokenDataFilePath, jsonTokenData); + console.log(`${LOG_PREFIX}Token data saved`); } function checkTokenData(tokenData: TokenData): void { - if ( - !tokenData.access_token || - !tokenData.refresh_token - ) { - console.error(`${LOG_PREFIX}Missing refresh_token or access_token in ${TOKENS_FILE}.`); - process.exit(1); - } -} \ No newline at end of file + if (!tokenData.access_token || !tokenData.refresh_token) { + console.error( + `${LOG_PREFIX}Missing refresh_token or access_token in ${TOKENS_FILE}.` + ); + process.exit(1); + } +} diff --git a/src/backend/helpers/twitch.ts b/src/backend/helpers/twitch.ts index 66a9698..e6e6727 100644 --- a/src/backend/helpers/twitch.ts +++ b/src/backend/helpers/twitch.ts @@ -1,4 +1,8 @@ -import { AccessToken, RefreshableAuthProvider, StaticAuthProvider } from "twitch-auth"; +import { + AccessToken, + RefreshableAuthProvider, + StaticAuthProvider +} from "twitch-auth"; import { getTokenData, saveTokenData } from "./tokenData"; import { ApiClient } from "twitch"; @@ -13,92 +17,91 @@ export { getAuthProvider, getApiClient, getUsernameFromId -} +}; function getClientCredentials(): ClientCredentials { - if ( - !process.env.TWITCH_CLIENT_ID || - !process.env.TWITCH_CLIENT_SECRET - ) { + if ( + !process.env.TWITCH_CLIENT_ID || + !process.env.TWITCH_CLIENT_SECRET + ) { console.error( `${LOG_PREFIX}Missing environment parameters TWITCH_CLIENT_ID or TWITCH_CLIENT_SECRET` ); - process.exit(1); - } + process.exit(1); + } - return { - clientId: process.env.TWITCH_CLIENT_ID, - clientSecret: process.env.TWITCH_CLIENT_SECRET - }; + return { + clientId: process.env.TWITCH_CLIENT_ID, + clientSecret: process.env.TWITCH_CLIENT_SECRET + }; } async function createStaticAuthProvider(): Promise { - let tokenData = await getTokenData(); - const credentials = getClientCredentials(); + let tokenData = await getTokenData(); + const credentials = getClientCredentials(); - return new StaticAuthProvider( - credentials.clientId, - tokenData.access_token - ); + return new StaticAuthProvider(credentials.clientId, tokenData.access_token); } async function getAuthProvider(): Promise { - if (refreshAuthProvider) { - return refreshAuthProvider; - } + if (refreshAuthProvider) { + return refreshAuthProvider; + } - let tokenData = await getTokenData(); + let tokenData = await getTokenData(); - const staticAuthProvider = await createStaticAuthProvider(); - const credentials = getClientCredentials(); + const staticAuthProvider = await createStaticAuthProvider(); + const credentials = getClientCredentials(); - const expiry = tokenData.expiryTimestamp === null - ? null - : new Date(tokenData.expiryTimestamp); + const expiry = + tokenData.expiryTimestamp === null + ? null + : new Date(tokenData.expiryTimestamp); - refreshAuthProvider = new RefreshableAuthProvider( - staticAuthProvider, - { - clientSecret: credentials.clientSecret, - refreshToken: tokenData.refresh_token, - expiry, - onRefresh: onRefresh - } - ); + refreshAuthProvider = new RefreshableAuthProvider(staticAuthProvider, { + clientSecret: credentials.clientSecret, + refreshToken: tokenData.refresh_token, + expiry, + onRefresh: onRefresh + }); - return refreshAuthProvider; + return refreshAuthProvider; } async function onRefresh(refreshData: AccessToken): Promise { - const { accessToken, refreshToken, expiryDate } = refreshData; - console.log(`${LOG_PREFIX}Tokens refreshed`); + const { + accessToken, + refreshToken, + expiryDate + } = refreshData; + console.log(`${LOG_PREFIX}Tokens refreshed`); - const expiryTimestamp = expiryDate === null - ? 0 - : expiryDate.getTime() + const expiryTimestamp = expiryDate === null + ? 0 + : expiryDate.getTime(); - const newTokenData: TokenData = { - access_token: accessToken, - refresh_token: refreshToken, - expiryTimestamp - }; + const newTokenData: TokenData = { + access_token: accessToken, + refresh_token: refreshToken, + expiryTimestamp + }; - await saveTokenData(newTokenData); + await saveTokenData(newTokenData); } async function getApiClient(): Promise { - const authProvider = await getAuthProvider(); + const authProvider = await getAuthProvider(); - return await new ApiClient({ authProvider }); + return await new ApiClient({ authProvider }); } async function getUsernameFromId(userId: number): Promise { - const apiClient = await getApiClient(); - const user = await apiClient.helix.users.getUserById(userId); + const apiClient = await getApiClient(); + const user = await apiClient.helix.users.getUserById(userId); - if (!user) { - return null; - } + if (!user) { + return null; + } - return user.displayName; -} \ No newline at end of file + return user.displayName; +} diff --git a/src/backend/helpers/webServer.ts b/src/backend/helpers/webServer.ts index 6560a2c..9073fa9 100644 --- a/src/backend/helpers/webServer.ts +++ b/src/backend/helpers/webServer.ts @@ -22,40 +22,44 @@ const wsServer = new WebSocket.Server({ let server: Server; export { - listen, + listen, broadcast -} +}; wsServer.on("connection", onConnection); app.use(express.static(join(process.cwd(), "client"))); function listen() { - if (server) { - console.log(`${LOG_PREFIX_HTTP}Server is already running`); - return; - } + if (server) { + console.log(`${LOG_PREFIX_HTTP}Server is already running`); + return; + } - server = app.listen(!isDevelopment ? 8080 : 8081, "0.0.0.0"); + server = app.listen(!isDevelopment ? 8080 : 8081, "0.0.0.0"); - server.on("listening", onListening); - server.on("upgrade", onUpgrade); + server.on("listening", onListening); + server.on("upgrade", onUpgrade); } function onListening() { - console.log( - `${LOG_PREFIX_HTTP}Listening on port ${(server.address() as AddressInfo).port}` - ); + console.log( + `${LOG_PREFIX_HTTP}Listening on port ${ + (server.address() as AddressInfo).port + }` + ); } function onUpgrade(req: IncomingMessage, socket: Socket, head: Buffer) { - wsServer.handleUpgrade(req, socket, head, socket => { - wsServer.emit("connection", socket, req); - }); + wsServer.handleUpgrade(req, socket, head, socket => { + wsServer.emit("connection", socket, req); + }); } function onConnection(socket: WebSocket, req: IncomingMessage) { - console.log(`${LOG_PREFIX_WS}${req.socket.remoteAddress} New connection established`); + console.log( + `${LOG_PREFIX_WS}${req.socket.remoteAddress} New connection established` + ); sockets.push(socket); socket.send( JSON.stringify({ @@ -69,11 +73,11 @@ function onConnection(socket: WebSocket, req: IncomingMessage) { // broadcast a message to all clients function broadcast(msg: string, socket?: any) { - const filteredSockets = socket - ? sockets.filter(s => s !== socket) - : sockets; + const filteredSockets = socket + ? sockets.filter(s => s !== socket) + : sockets; - filteredSockets.forEach(s => s.send(msg)); + filteredSockets.forEach(s => s.send(msg)); } async function onMessage(msg: string) { @@ -81,7 +85,10 @@ async function onMessage(msg: string) { const socket = this as WebSocket; const data = JSON.parse(msg); - if (!data.actions || data.actions.length === 0) { + if ( + !data.actions || + data.actions.length === 0 + ) { broadcast(msg, socket); return; } @@ -96,14 +103,17 @@ async function onMessage(msg: string) { } } - console.log(`${LOG_PREFIX_WS}Received message with ${data.actions.length} actions:`, data); + console.log( + `${LOG_PREFIX_WS}Received message with ${data.actions.length} actions:`, + data + ); } function onClose() { // @ts-ignore const socket: WebSocket = this as WebSocket; - const socketIdx = sockets.indexOf(socket); - sockets.splice(socketIdx, 1); - console.log(`${LOG_PREFIX_WS}Connection closed`); -} \ No newline at end of file + const socketIdx = sockets.indexOf(socket); + sockets.splice(socketIdx, 1); + console.log(`${LOG_PREFIX_WS}Connection closed`); +}