diff --git a/server/v2.js b/server/v2.js deleted file mode 100644 index f815969..0000000 --- a/server/v2.js +++ /dev/null @@ -1,299 +0,0 @@ -import Net from "net"; -import "dotenv/config"; -import { setup as dbSetup, runPrepQuery, numRows } from "./Utility/db.js"; -import { Err, Log, Debug, Warn } from "./Utility/loggerUtility.js"; -import crypto from "crypto"; - -import { botSetup, client } from "./Utility/discordClient.js"; -import { event } from "./Utility/eventHandler.js"; -import fsConfig from "./config.json" assert { type: "json" }; -import { loadModelFromDB, createNewLS } from "./Utility/lsModel.js"; -import { listen } from "./webserver.js"; -import { getUserFromJwt, setUserSocket, loadUsersFromDB } from "./Utility/userModel.js"; -import { getLSModel } from "./Utility/lsModel.js"; -import { link, write } from "fs"; - - - -const token = fsConfig.token; -Log("Connecting to MySQL DB..."); -dbSetup(fsConfig.db); - -event.on("DATABASE_CONNECTED", async () => { - Log("Ready!"); - await loadUsersFromDB(); - await loadModelFromDB(); - botSetup(); - listen(); -}); - -event.on("MYSQL_FAILED_TO_CONNECT", () => { - Err( - "Failed to launch LinkCloud. Unable to connect to MySQL database. Please check database connection parameters and try again." - ); - process.exit(); -}); - -const server = Net.createServer(); -const discordPacketBuffer = []; -const lsPacketBuffer = [] -const sockets = []; -const discordWebhookQueue = [] -const checkTime = (theirTime) => { - const myTime = Math.floor(Date.now() / 1000); - return Number(theirTime - myTime); -}; -const hashPacketData = (packet) => { - let base = packet.type; - base += packet.metaData.gameTime; - base += packet.metaData.server; - base += packet.payload.name.replace(/[\n\r]/g, '').trim(); - base += packet.payload.message.replace(/[\n\r]/g, '').trim(); - base += packet.metaData.platform; - if (packet.payload?.linkshellname) { - base += packet.payload?.linkshellname; - } else if (packet.payload?.area) { - base += packet.payload?.area; - } - return crypto.createHash("md5").update(base).digest("hex"); -}; -const addToDiscordBuffer = (packet) => { - for (const idx in discordPacketBuffer) { - if (discordPacketBuffer[idx].hash == packet.hash) { - //Debug(`${packet.hash} exists, skipping...`); - return false; - } - } - //Debug(`New hash created ${packet.hash}`) - discordPacketBuffer.push(packet); - if(discordPacketBuffer.length > 1000) { - discordPacketBuffer.shift() - } -}; -server.on("connection", (sock) => { - //Debug("CONNECTED: " + sock.remoteAddress + ":" + sock.remotePort); - sock.on("data", async (data) => { - const response = { - error: false, - }; - try { - const packets = data.toString().split("\n"); - for (const p in packets) { - if (packets[p]) { - const packet = JSON.parse(packets[p]); - - const differential = checkTime(packet?.metaData?.clientTime); - let isLsMessage = false; - if (differential <= process.env.MAX_CLOCK_SYNC_MISMATCH_SECONDS) { - response.type = packet?.type?.toUpperCase(); - response.packetId = packet?.packetId; - switch (response.type) { - case "HANDSHAKE": - const authed = AuthenticateSocket(packet, sock); - if(!authed) { - response.error = true; - response.errorMsg = "AUTH_FAIL"; - response.errorDetails = `You shall not pass!`; - } - response.payload = authed ? "ACCEPTED" : "REJECTED"; - response.disconnect = true - Log(`[${sock.remoteAddress}] connection ${response.payload}.`); - break; - case "HEARTBEAT": - response.payload = "PONG"; - break; - case "LINKSHELL_MESSAGE": - console.log(packet) - packet.hash = hashPacketData(packet); - ProcessLSMessage(packet, sock) - break; - case "LINKSHELL_UPDATE": - console.log(packet) - ProcessLSUpdate(packet, sock) - break; - case "SHOUT": - packet.hash = hashPacketData(packet); - addToDiscordBuffer(packet); - break; - case "OTHER": - break; - case "ADD_LINKSHELL": - ProcessAddLinkshell(packet, sock); - break; - default: - response.error = true; - response.errorMsg = "UNKNOWN_PACKET_TYPE"; - response.errorDetails = `UNKNOWN PACKET TYPE`; - return; - } - } else { - response.error = true; - response.errorMsg = "CLOCK_OUT_OF_SYNC"; - response.errorDetails = `This system and the servers clocks are out of sync by ${String( - differential - )} second(s).`; - } - if (sock) writeToClientSocket(sock,JSON.stringify(response) + "\n\r"); - if (response.error) { - console.log(data) - console.log(packet) - sock.resetAndDestroy(); - } - } - } - - //Debug(`TO ${sock.remoteAddress} ${JSON.stringify(response)}`) - } catch (ex) { - Err("Unexpected packet format, unable to parse."); - console.log(ex); - console.log(data.toString()); - } - - }); - sock.on("timeout", (data) => { - removeSocketFromPool(sock) - Debug("TIMEOUT: " + sock.remoteAddress + " " + sock.remotePort); - }) - sock.on("close", (data) => { - removeSocketFromPool(sock) - Debug("CLOSED: " + sock.remoteAddress + " " + sock.remotePort); - }); - writeToClientSocket(sock,"CHALLENGE\n"); - sockets.push(sock); -}); -const removeSocketFromPool = (sock) => { - const index = sockets.findIndex(function (o) { - return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort; - }); - if (index !== -1) sockets.splice(index, 1); -} -server.listen(process.env.TCP_LISTEN_PORT, () => { - Log(`Server Bound to ${process.env.BIND_ADDRESS} on port ${process.env.TCP_LISTEN_PORT}.`); -}); -const writeToClientSocket = (socket, data, retry = 0) => { - if(!socket?.destroyed && socket?.readyState === 'open') { - socket.write(data, (err) => { - if(err) { - Debug(`Failed to write to socket`) - console.log(err) - } - }) - } else { - if(socket?.destroyed) { - Debug(`The socket is dead and cant be written to`) - } else { - if(retry < 5) { - Debug(`Retrying to send packet ${data}`) - setTimeout(() => {writeToClientSocket(socket, data, retry + 1)}, 1000) - } - } - } -} -const ProcessLSMessage = (packet, socket) => { - for (const idx in lsPacketBuffer) { - if (lsPacketBuffer[idx].hash == packet.hash) { - //Debug(`${packet.hash} exists, skipping...`); - return false; - } - } - //Debug(`New hash created ${packet.hash}`) - lsPacketBuffer.push(packet); - if(lsPacketBuffer.length > 1000) { - lsPacketBuffer.shift() - } - const linkshell = ProcessLSUpdate(packet, socket) - if(!linkshell.channels) return false; - const re = /^(\[.+\] .+)/ - if(!packet.payload.message.match(re)){ - linkshell.webhookQueue.push({ - linkshell, - packet - }) - } -} - -const ProcessLSUpdate = (packet, socket) => { - const linkshell = getLSModel(packet.payload?.linkshellname, packet.metaData.platform, packet.metaData.server); - if(linkshell) { - linkshell.socket = socket - Log(`Linkshell "${packet.payload.linkshellname}" Registered By ${packet.metaData.character}`) - } - return linkshell -} - - -const sendMessageToClient = (socket, message, error = false) => { - const packet = {}; - packet.type = "SYSTEM_MESSAGE"; - packet.payload = {}; - packet.payload.isError = error; - packet.payload.message = message; - if (socket) writeToClientSocket(socket,JSON.stringify(packet) + "\n\r"); -}; -const sendLSMessage = (socket, message, from, ls) => { - const packet = {}; - packet.type = "LS_ECHO"; - packet.payload = {}; - packet.payload.from = from.trim(); - packet.payload.message = message.trim(); - packet.payload.linkshell = ls - if (socket) writeToClientSocket(socket,JSON.stringify(packet) + "\n\r"); -} -const AuthenticateSocket = (packet, socket) => { - const authId = packet.payload.authId; - const user = getUserFromJwt(authId); - if (user) { - setUserSocket(socket, user.userId) - return true; - } else { - return false; - } -}; - -const ProcessAddLinkshell = (packet, socket) => { - const linkId = packet.payload.linkId.replace("\r", "").replace("\n", ""); - const serverId = packet.metaData.server; - const lsName = packet.payload.lsName; - const result = runPrepQuery("SELECT * FROM pendinglinks WHERE linkId = ? LIMIT 0,1", [linkId], async (r, f, e) => { - if (numRows(r)) { - const ffxiver = r[0].ffxiver; - const userId = r[0].userId; - const discordUser = client.users.cache.get(userId); - console.log({ linkId, serverId, lsName, ffxiver, userId }); - const newLs = await createNewLS(lsName, serverId, ffxiver, userId).catch((e) => { - console.log(e); - sendMessageToClient(socket, "An error occured. Contact Support. [0x10]", true); - }); - if (newLs) { - discordUser.send( - `# Success!\nYour Linkshell ${lsName} has been added to LinkCloud!\n\n## What's Next?\n- Set up the chat echo channel in your discord server using the \`/lccreateecho\` command in the channel you want to use for the chat echo.\n- Encourage LS members to use the \`/lcjoin\` command to get started streaming data to LinkCloud. The more streamers you have, the more reliable the echo will be.` - ); - Log(`New Linkshell "${lsName}" has been created!`); - sendMessageToClient( - socket, - `Linkshell ${lsName} added successfully to LinkCloud. Check discord for further instruction.` - ); - } else { - Err(`Failed to create Linkshell "${lsName}".`); - sendMessageToClient( - socket, - "An error occured. This is most likely because this Linkshell already exists.", - true - ); - console.log(e); - discordUser.send( - `# Uh-oh!\nYour Linkshell ${lsName} seems to already exist in our database.\n\n## Need Help?\nYou can reach out to support via discord.\nhttps://discord.gg/n5VYHSQbhA` - ); - } - } else { - sendMessageToClient(socket, "An error occured. The supplied token is not valid.", true); - } - }); -}; - -event.on('NEW_DISCORD_ECHO_RECEIVED', message => { - const linkshell = getLSModel(message.lsName, message.platform, message.server) - if(linkshell.socket) { - sendLSMessage(linkshell.socket, message.message, message.from, message.lsName) - } -}) \ No newline at end of file