Untitled
unknown
plain_text
2 years ago
44 kB
3
Indexable
//Import modules const express = require('express'); const mongoose = require('mongoose'); const cors = require('cors'); const webPush = require('web-push'); const socket = require('socket.io'); const admin = require('firebase-admin'); const helmet = require('helmet'); const Authenticate = require('./routes/authentication/auth.js'); const User = require('./models/user.js'); const router = require('./routes/index.js'); const Token = require('./models/jwt.js'); const Challenge = require('./models/challenge.js'); const changeBallance = require('./routes/admin/changeballance.js'); const History = require('./models/history.js'); const Setting = require('./models/setting.js'); const Log = require('./models/log'); const BlockedIps = require('./models/blockedIp'); const GameResult = require('./models/gameResult.js'); const validateUserBalance = require('./helper/validateUserBalance'); const { RateLimiterMemory } = require('rate-limiter-flexible'); const getRoomCode = require('./helper/getRoomCode.js'); const { leftGame, cancelGame } = require('./routes/admin/settleChallenge.js'); require('dotenv').config(); const { logBadBallance, logToChannel, logFrequentLost, logCORSDefaulter, logRateLimit, logToChannelIdisUndefined, } = require('./helper/tgBot'); const { PUBLIC_VAPID_KEY, PRIVATE_VAPID_KEY, DB_URI_LOCAL, DB_URI_ATLAS, ROOM_SRV_URL, IS_DEV, } = require('./config.js'); const createHistory = require('./helper/createHistory.js'); const { verifyFromPGWebHook } = require('./routes/user/buyChipsPG.js'); const logThisToDb = require('./helper/logThisToDb.js'); const { getSiteStatus } = require('./routes/siteStatesCache.js'); const DEVLOPMENT = IS_DEV; const ENABLE_REQUEST_LOG = true; //setting vapid details //test comment //test 2 webPush.setVapidDetails( 'mailto:test@test.com', PUBLIC_VAPID_KEY, PRIVATE_VAPID_KEY ); //constants const PORT = 5000; //Initializing express app const app = express(); app.use(helmet()); app.use( express.urlencoded({ limit: '50mb', extended: true, parameterLimit: 50000, }) ); // parse application/json app.use(express.json({ limit: '50mb' })); app.options('*', cors()); app.post( '/pg-webhook', cors({ origin: '*', }), verifyFromPGWebHook() ); app.post( '/whfbweghfebrhebfehwgrwhfbehjfehfvrh', cors({ origin: '*', }), leftGame() ); app.get( '/logout-user/:id', cors({ origin: '*', }), async (req, res) => { io.to(req.params.id).emit('logout'); return res.send('OK'); } ); var whitelist = [ 'https://ludoplayers.com', 'https://admin.ludoplayers.com', 'https://test.ludoplayers.com', 'https://www.ludoplayers.com', 'https://uberki.com', 'https://admin.uberki.com', 'https://test.uberki.com', 'https://www.uberki.com', ]; var corsOptions = DEVLOPMENT ? { origin: '*', } : { origin: function (origin, callback) { if (whitelist.indexOf(origin) !== -1) { callback(null, true); } else { callback(`Not allowed by CORS: ${origin}`); } }, }; let BLOCKED_IPS = []; let connectedUsers = []; app.get('/get-connected-users', (req, res) => { res.json({ 'No of connectedUsers': connectedUsers.length, 'No of connections': io.engine.clientsCount, connectedUsers, connections: io.sockets.sockets.keys(), }); }); async function getBlockedIps() { const res = await BlockedIps.findOne({}); BLOCKED_IPS = res.ip; return BLOCKED_IPS; } getBlockedIps(); app.get('/refresh-blocked-ip', async (req, res) => { BLOCKED_IPS = await getBlockedIps(); res.json(BLOCKED_IPS); }); if (ENABLE_REQUEST_LOG) { app.use( require('morgan')(function (tokens, req, res) { const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; const id = req.headers['id']; const userPhone = req.headers['user-phone']; return [ tokens.method(req, res), tokens.url(req, res), tokens.status(req, res), '-', tokens['response-time'](req, res), 'ms', '-', userPhone, '-', ip, ].join(' '); }) ); } app.use((req, res, next) => { if (DEVLOPMENT) { return next(); } const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; const url = req?.baseUrl + req?.path; if (BLOCKED_IPS.includes(ip)) { console.log('[BLOCKED_IPS]', ip + ' ' + url); res.status(403).send('Forbidden'); return; } var origin = req.get('origin'); if (whitelist.indexOf(origin) == -1) { const shouldAllow = url.includes('redirect') || url.includes('logo') || url.includes('favicon') || url.includes('robots'); if (!shouldAllow) { logCORSDefaulter(req.headers['id'], { url, origin, ip, }); return res.status(403).send('Forbidden'); } } next(); }); app.get('/redirect/:ref', cors(), (req, res) => { res.redirect(`https://ludoplayers.com/#/register/${req.params.ref}`); }); app.get('/redirect/', cors(), (req, res) => { res.redirect(`https://ludoplayers.com/#/register/`); }); app.use(cors(corsOptions)); const dev = true; if (dev) { mongoose .connect(DB_URI_LOCAL, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false, }) .catch((err) => { console.error('107@index.js', err.message); }); } else { mongoose .connect(DB_URI_ATLAS, { useNewUrlParser: true, useUnifiedTopology: true, user: 'ludoplayers', pass: '3aiMsQ61WtlmFtCR', authMechanism: 'SCRAM-SHA-1', }) .catch((err) => { console.error('123@index.js', err.message); }); } let db = mongoose.connection; db.on('error', (err) => console.error('Line 96:', err)); //Using coustom middlewares app.use(Authenticate(User)); //Connected to database db.once('open', async (err) => { if (err) { console.error(err); } }); //not responding to all the users that are blocked app.use((req, res, next) => { if (req.user) { if (req.user.isBlocked) { console.log(`User is blocked ${req.user._id} ${req.user.username}`); res.json({ err: 'something went wrong' }); return; } } next(); }); //Setting express router app.use('/api', router); const server = app.listen(PORT, (err) => { if (!err) { console.info(`server started at port ${PORT}`); return; } console.error('error starting server on port:' + PORT); }); //passing server to socket.io var io = socket(server, { cors: { origin: DEVLOPMENT ? '*' : ['https://ludoplayers.com', 'https://test.ludoplayers.com'], methods: ['GET', 'POST'], }, }); const rateLimiter = new RateLimiterMemory({ points: 120, duration: 60, }); io.use(async (socket, next) => { if (DEVLOPMENT) { return next(); } const { id, key, now, userPhone } = socket.handshake.query; const ip = socket?.request?.headers['x-forwarded-for'] || socket?.request?.connection.remoteAddress; if (BLOCKED_IPS.includes(ip)) { return socket.disconnect(true); } if (ENABLE_REQUEST_LOG) { console.log('socket init by phone:', userPhone); } if (!now) { console.log('connecting socket outside website', ip); logToChannel( `connecting to socket outside website! blocking this IP ${ip}`, true ); const newBlockedIps = await BlockedIps.findOneAndUpdate( {}, { $push: { ip: ip, }, }, { new: true, } ); BLOCKED_IPS = newBlockedIps.ip; return socket.disconnect(true); } let userToken = false; if (!id) { console.log('no id', ip); logToChannel(`no id ${ip}`, true); return socket.disconnect(true); } else if (id === 'undefined' || id === 'null') { console.log('id is undefined', ip); logToChannelIdisUndefined(ip); return socket.disconnect(true); } else { try { userToken = await Token.findById(id).populate('userId'); } catch (err) { console.error('io connection error:', err); } } if (!userToken) { console.error('token not found in db', ip); // logToChannel(`token not found in db ${ip}`, true); socket.emit('logout'); return socket.disconnect(true); } try { await rateLimiter.consume(ip); } catch (err) { console.error( `Rate limit exceeded for ip: ${ip} ${userToken?.userId?.username}` ); // if (userToken?.userId?.isBlocked) { // const newBlockedIps = await BlockedIps.findOneAndUpdate( // {}, // { // $push: { // ip: ip, // }, // }, // { // new: true, // } // ); // BLOCKED_IPS = newBlockedIps.ip; // } } const alreadyConnected = connectedUsers.find( (user) => user?.id == userToken?.userId?._id.toString() ); if (alreadyConnected) { try { if (io.sockets.sockets.has(alreadyConnected.id)) { console.log('disconnecting socket', alreadyConnected.username); io.sockets.sockets[alreadyConnected.socketId].disconnect(); } connectedUsers = connectedUsers.filter( (user) => user.id !== userToken?.userId?._id.toString() ); } catch (err) { console.error('error disconnecting socket:', err); } } connectedUsers.push({ id: userToken?.userId?._id.toString(), username: userToken?.userId?.username, socketId: socket.id, }); next(); }); const scammers = ['62dd01ee8be85abd773ba8b0']; io.on('connection', async (socket) => { let user; //initialization event let inited = false; socket.on('terminate', async () => { socket.disconnect(true); }); socket.on('init', async (data) => { inited = true; setTimeout(() => { inited = false; }, 50 * 1000); //authentication const token = await Token.findById(data.id); if (!token) { return; } user = await User.findById(token.userId); //delete challenges await DeleteChallenges(); //join this user to a room that is named after his id so we can uniqely send messages to him socket.join(token.userId.toString()); //sending the initialization your challenges sendAllNonPlayingChallenges(socket); //all running challenge sendPlayableChallanges(socket); //running challenges sendRunningChallenges(socket); }); //create challenge event socket.on('create', async ({ amount, test }) => { if (!user) return; if ( Number(amount) % 50 != 0 || Number(amount) < 49 || Number(amount) > 10001 ) { return; } const isPlayEnabled = await getSiteStatus(); if ( !test && (isPlayEnabled?.playPage == false || isPlayEnabled?.playPage == 'false') ) { socket.emit('error', { message: 'Playing Challenge is Currently Disabled as Website is Under Maintenance. Please try again later', }); return; } //check if user has enough ballance let fuckingUser = await User.findById(user._id); if (scammers.includes(fuckingUser.id)) { logToChannel( `[Scammer] ${fuckingUser.username} tried creating a game!` ); return; } if (fuckingUser.isBlocked) { socket.emit('error', { message: 'You are banned' }); return; } if (fuckingUser.wallet - amount < 0) { socket.emit('error', { message: "You don't have Enough Chips ", }); return; } const userOtherchallneges = await Challenge.find({ creator: user._id, state: { $in: ['open', 'requested'] }, }).countDocuments(); if (userOtherchallneges === 3) { socket.emit('error', { message: 'You can Set Maximum 3 Challenge at a time', }); return; } //check if same amount challenge exists let challenge = await Challenge.findOne({ creator: user._id, amount: amount, state: { $in: ['open', 'requested'] }, }); if (challenge) { //emmit an error event socket.emit('error', { message: 'Same Amount Challenge Already exists', }); return; } //check if user hasn't updated results in a challenge challenge = await Challenge.findOne({ $or: [ { creator: fuckingUser._id, 'results.creator': null }, { player: fuckingUser._id, 'results.player': null }, ], state: { $in: ['playing', 'hold'] }, }); if (challenge) { socket.emit('error', { message: 'Update Your Result In Previous Match First', }); return; } //create a challenge challenge = new Challenge(); challenge.creator = user._id; challenge.creatorUsername = user.username; challenge.amount = amount; await challenge.save(); //send non playing challenges in other words challenges that are in state open or requested //I dont fucking know why I named this function sendAllNonPlayingChallenges :| sendAllNonPlayingChallenges(socket); //send challenges of state open or requested but with a different category :| sendPlayableChallanges(io); //send notification to everyone try { if (!test) { await admin.messaging().send({ topic: 'ludoplayers_user', webpush: { notification: { title: `Ludo Players`, body: `New Challenge Of ₹${amount}`, icon: 'https://ludoplayers.com/favicon.ico', //image: data.image, }, fcmOptions: { link: 'http://www.ludoplayers.com', }, }, }); } } catch (err) { console.error('326@index.js' + err); } }); //delete event socket.on('delete', async (id) => { try { if (!user) { return; } if (scammers.includes(user.id)) { logToChannel( `[Scammer] ${user.username} tried deleting a game!` ); return; } let challenge = await Challenge.findById(id); //check if the user is actually the creator if (String(challenge?.creator) !== String(user._id)) { socket.emit('error', { message: 'Error', }); return; } const { state } = challenge; console.log(`deleteing challenge ${id} with state ${state}`); if (['playing', 'hold', 'cancelled', 'resolved'].includes(state)) { logToChannel( `user ${user.username} tried deleting a game in state ${state}` ); return; } //delete the challenge //comment added await Challenge.deleteOne({ _id: id }); sendAllNonPlayingChallenges(socket); sendPlayableChallanges(io); } catch (err) { console.error('socket delete event' + err.message); } }); socket.on('request', async (id) => { try { if (!user) { return; } if (scammers.includes(user.id)) { logToChannel( `[Scammer] ${user.username} tried requesting a game!` ); return; } let challenge = await Challenge.findOne({ $or: [ { creator: user._id, 'results.creator': null }, { player: user._id, 'results.player': null }, ], state: { $in: ['playing', 'hold'] }, }); if (challenge) { socket.emit('error', { message: 'Update Your Result in Previous Match First', }); return; } //check if theres any other challenge on requested state of that player challenge = await Challenge.findOne({ $or: [{ creator: user._id }, { player: user._id }], state: 'requested', }); if (challenge && challenge._id.toString() === id) { //do nothing return; } if (challenge) { //now the max request error needs to be given in a different way socket.emit('max-request', id); return; } //validate the id challenge = await Challenge.findById(id); if (!challenge) { console.error('Invalid Id has been passed:', id); return; } //check if its already challenged if (challenge.player) { //socket.emit("error", { message: "Someone already challanged" }); return; } //check if user has enough ballance let latestUser = await User.findById(user._id); if (latestUser.wallet - challenge.amount < 0) { socket.emit('low-balance', id); return; } // check if user is the creator of the challenge if (String(challenge.creator) === String(user._id)) { socket.emit('error', { message: 'Error: You cannot challenge yourself', }); return; } //update the challenge challenge.player = user._id; challenge.playerUsername = user.username; challenge.state = 'requested'; await challenge.save(); //refresh the challengers your-challenges sendAllNonPlayingChallenges(io); //refresg everyone's playable-challenges sendPlayableChallanges(io); //play audio of the creator io.to(challenge.creator.toString()).emit('play-audio'); } catch (err) { console.error('error in request event:', err.message); } }); socket.on('cancel', async (id) => { try { if (!user) { console.error('cancel event: user is not defined'); return; } if (scammers.includes(user.id)) { logToChannel( `[Scammer] ${user.username} tried cancelling a game!` ); return; } //check if user is either creator or player let challenge = await Challenge.findOneAndUpdate( { _id: id, state: 'requested', $or: [{ creator: user._id }, { player: user._id }], }, { player: undefined, playerUsername: undefined, state: 'open' } ); if (!challenge) { console.error('cancel event: challenge not found'); return; } //refresh everyones cancelers playable-challenges sendPlayableChallanges(io); //refresh the creators your-challenges sendAllNonPlayingChallenges(io); //emmit the rejected and or canceled event if (challenge.creator.toString() === user._id.toString()) { io.to(challenge.player.toString()).emit( 'rejected', challenge._id ); } else { //io.to(challenge.creator.toString()).emit("cancelled", challenge._id); io.to(challenge.player.toString()).emit( 'cancelled', challenge._id ); } } catch (err) { console.error('error in cancel event:', err); } }); socket.on('play', async (id) => { //check if the challenge is valid and playable if (!user) { return; } if (scammers.includes(user.id)) { logToChannel(`[Scammer] ${user.username} tried playing a game!`); return; } let challenge = await Challenge.findOne({ $or: [ { creator: user._id, 'results.creator': null }, { player: user._id, 'results.player': null }, ], state: { $in: ['playing', 'hold'] }, }); if (challenge) { socket.emit('error', { message: 'Update Your Result in Previous Match First', }); return; } challenge = await Challenge.findOneAndUpdate( { _id: id, creator: user._id, state: 'requested' }, { state: 'playing' } ); if (!challenge || !user) { return; } //check for both users ballance let creator = await User.findById(challenge.creator); let player = await User.findById(challenge.player); if ( creator.wallet - challenge.amount < 0 || player.wallet - challenge.amount < 0 ) { await Challenge.updateOne({ _id: id }, { state: 'requested' }); return; } //check if opoponent is already in a game let opponentsChallenge = await Challenge.findOne({ _id: { $ne: id }, $or: [ { creator: challenge.player, 'results.creator': null }, { player: challenge.player, 'results.player': null }, ], state: { $in: ['playing', 'hold'] }, }); if (opponentsChallenge) { await Challenge.updateOne({ _id: id }, { state: 'requested' }); return; } //update the challenge await Challenge.updateOne({ _id: id }, { state: 'playing' }); await logThisToDb({ scope: '[Wallet balance change]', idx1: challenge.amount, challengeId: challenge._id, user: user._id, msg: `on play event - dec`, info: `${challenge.creator} - ${challenge.player}`, }); //decrease creators ballance await User.updateMany( { $or: [{ _id: challenge.creator }, { _id: challenge.player }], }, { $inc: { wallet: -challenge.amount } } ); // REMOVED FOR NOW // const isCreaterValid = await validateUserBalance(challenge.creator); // const isPlayerValid = await validateUserBalance(challenge.player); // if (!isCreaterValid[0] || !isPlayerValid[0]) { // if (!isCreaterValid[0]) { // logBadBallance( // challenge.creator, // 'requesting challenge', // isCreaterValid[1] // ); // } // if (!isPlayerValid[0]) { // console.log(`${challenge.player} is not valid`); // logBadBallance( // challenge.player, // 'requesting challenge', // isPlayerValid[1] // ); // } // } io.to(challenge.player.toString()).emit('play-audio'); io.to(challenge.player.toString()).emit('start-button', id); //send a update event to everyone for category running-challenges sendRunningChallenges(io); sendAllNonPlayingChallenges(socket); sendPlayableChallanges(io.to(challenge.player)); io.to(challenge.creator.toString()).emit('redirect', { user: 'everyone', to: `/game/${id}`, }); //get the room code try { let roomCode = await getRoomCode(); if (!roomCode) { logToChannel('room code did not came', true); roomCode = await getRoomCode(); } if (!roomCode) { logToChannel('room code did not came in second try'); } if (roomCode.length != 8) { logToChannel( 'room code is not 8 chars long, cancelling this game', true ); await cancelGame(id, 'no room code'); return; } try { const gameResult = new GameResult({ _id: roomCode, gameStartedAt: new Date(), state: 'created', }); await gameResult.save(); } catch (error) { // if duplicate key error if (error.code === 11000) { console.log('duplicate key error'); const copyGame = await GameResult.findById(roomCode).lean(); await GameResult.findByIdAndUpdate(roomCode, { gameStartedAt: new Date(), state: 'created', duplicate: true, $push: { prevGame: copyGame, }, playerOne: { name: '', result: 0, tokensOut: -1, endResult: '', }, playerTwo: { name: '', result: 0, tokensOut: -1, endResult: '', }, gameUpdatedAt: new Date(), gameFinishedAt: new Date(), }); } else { console.error(`[GameResult-created] error`); console.error(error); logToChannel( `[GameResult-created] error: ${error.message}`, true ); } } // logToChannel( // `room code is ${roomCode} for ${creator.username} vs ${player.username}` // ); await Challenge.updateOne( { _id: id, $or: [ { creator: user._id, 'results.creator': null }, { player: user._id, 'results.player': null }, ], }, { code: roomCode } ); io.to(id).emit('code', roomCode); io.to(String(creator._id)).emit( 'update_wallet', creator.wallet - challenge.amount ); return; } catch (err) { console.error('570@index.js' + err); } }); socket.on('view', async (id) => { let challenge = await Challenge.findById(id); const isCreator = challenge.creator.toString() === user?._id.toString(); const isPlayer = challenge.player.toString() === user?._id.toString(); if ( (isCreator && challenge.results.creator) || (isPlayer && challenge.results.player) ) { socket.emit('redirect', { user: user._id, to: `/view/${id}`, viewInfo: { code: challenge.code, result: isCreator ? challenge.results.creator : challenge.results.player, resultScreenshoot: isCreator ? challenge.winnerScreenshoot.creator : challenge.winnerScreenshoot.player, challengeText: `${challenge.creatorUsername} vs ${challenge.playerUsername} for ₹${challenge.amount}`, }, }); return; } if (user) { socket.emit('redirect', { user: user._id, to: `/game/${id}` }); } }); socket.on('refresh', (category) => { if (category === 'your-challenges') { sendAllNonPlayingChallenges(socket); } if (category === 'playable-challenges') { sendPlayableChallanges(io); } }); //send specefic group of challenges async function sendAllNonPlayingChallenges(localSocket) { try { //requested challenges const challenges = await Challenge.find({ state: { $in: ['requested', 'open'], }, }) .select( '-winnerScreenshoot -code -s3WinnerScreenshoot -deleted -isAdminClear -isSus' ) .sort({ createdAt: -1 }); //emit the things and stuffs localSocket.emit('update', { category: 'your-challenges', challenges, }); } catch (err) { console.error('sending all non playing challenges' + err); } } async function sendPlayableChallanges(localSocket) { try { //all playable challenges let challenges = await Challenge.find({ state: { $in: ['open', 'requested'] }, }) .select( '-winnerScreenshoot -code -deleted -isAdminClear -isSus -s3WinnerScreenshoot' ) .sort({ createdAt: -1 }); localSocket.emit('update', { category: 'playable-challenges', challenges: challenges, }); } catch (err) { console.error('sending playable challenges: ' + err); } } async function sendRunningChallenges(localSocket) { try { let challenges = await Challenge.find({ state: { $in: ['playing', 'hold'] }, }).select( '-winnerScreenshoot -code -s3WinnerScreenshoot -deleted -isAdminClear -isSus' ); localSocket.emit('update', { category: 'running-challenges', challenges: challenges, }); } catch (err) { console.error('sending running challenges: ' + err); } } //all the room related shits socket.on('joinRoom', async (id) => { if (!user) { socket.emit('try-again'); return; } let challenge = await Challenge.findById(id); //make sure this user is either the creator or the player if ( challenge?.creator?.toString() !== String(user._id) && challenge?.player?.toString() !== user._id.toString() ) { return; } //emmit redirect_error if the user has updated his result let userState = 'creator'; if (challenge.player.toString() === user._id.toString()) { userState = 'player'; } if (challenge.state === 'resolved') { socket.emit('redirect', { to: '/', }); } if (challenge.results[userState] && challenge.state === 'hold') { socket.emit('redirect_error', { to: '/', message: 'आपका रिज़ल्ट अपलोड हो चुका है ॥ गेम clear होने का 2-5 मिनट इंतज़ार करे ।\n\nYour Result is submitted. Please wait until the Game is Cleared within 2-5 Minutes.', }); return; } //join the socket to a room socket.join(id); //emit some info socket.emit('creator', challenge.creator); socket.emit( 'challenge_text', `${challenge.creatorUsername} vs ${challenge.playerUsername} for ₹${challenge.amount}` ); //check if theres code if there is then emit code otherwise the codeChangable if (challenge.code) { socket.emit('code', challenge.code); } try { // const logThisToDb = new Log({ // scope: 'joinRoom', // msg: `${challenge.creatorUsername} vs ${challenge.playerUsername} for ₹${challenge.amount} room code ${challenge.code}`, // cleared: true, // }); // await logThisToDb.save(); } catch (err) { console.error('joinRoom: ' + err); } }); async function resolveChallange({ id, challenge, userRole, oponentRole, result, }) { const checkWon = await Challenge.findById(id); if ( checkWon.winnerScreenshoot.player && checkWon.winnerScreenshoot.creator ) { return; } if (checkWon.adminHold) { console.log('admin hold'); return; } //get the latest challenge const challenegExists = await Challenge.findOneAndUpdate( { _id: id, state: 'hold', $or: [ { 'results.creator': undefined }, { 'results.player': undefined }, ], }, { state: 'resolved' } ); //run change ballace funtion for the player and his opoponent as this player is winner //change this player's ballance (winner) if (challenegExists) { const userResult = challenge.results[userRole] ? ` (Your Result: ${challenge.results[userRole]})` : null; const oponentResult = challenge.results[oponentRole] ? ` (Your Result: ${challenge.results[oponentRole]})` : null; await changeBallance( challenge[userRole], { amount: challenge.amount, reason: 'win', naration: `Won against ${ challenge[oponentRole + 'Username'] }${userResult ?? ''}`, uniqueId: `${challenge.id}-${ challenge.code || 'no-code' }-win`, }, `${result}@index.js`, id ); //change opponent's ballance (looser) await changeBallance( challenge[oponentRole], { amount: challenge.amount, reason: 'lose', winner: await User.findById(challenge[userRole]), naration: `lost against ${ challenge[userRole + 'Username'] }${oponentResult ?? ''}`, uniqueId: `${challenge.id}-${ challenge.code || 'no-code' }-lose`, }, `${result}@index.js`, id ); } let tempUser = await User.findById(challenge[userRole]); //update users ballance io.to(String(challenge[userRole])).emit( 'update_wallet', tempUser.wallet ); //referesh running challanges of all players sendRunningChallenges(io); return; } async function cancelChallange({ id, challenge, userRole, oponentRole, result, }) { let challenge_on_resolve_time = await Challenge.findById(id); if ( challenge_on_resolve_time.results[oponentRole] || challenge_on_resolve_time.state === 'resolved' ) { return; } //resolve the challange await Challenge.findByIdAndUpdate(id, { state: 'resolved' }); //giving the amount of the challenge back to creator and player because it was dedducted when match started // await User.updateMany( // { // $or: [{ _id: challenge.creator }, { _id: challenge.player }], // }, // { $inc: { wallet: challenge.amount } } // ); const creatorUniqueId = `${challenge.id}-${ challenge.code || 'no-code' }-cancel-creator`; //cancled history for player and creator const creatorHistory = await createHistory( { user: challenge.creator, amount: challenge.amount, historyType: 'cancel', naration: `Cancelled Against ${challenge.playerUsername} (Your Result: ${challenge.results.creator})`, uniqueId: creatorUniqueId, }, 'index.js@cancelChallangeCreator', id ); if (creatorHistory) { await logThisToDb({ scope: '[Wallet balance change]', idx1: challenge.amount, challengeId: challenge._id, user: challenge.creator, msg: `on cancel - inc`, }); await User.findByIdAndUpdate(challenge.creator, { $inc: { wallet: challenge.amount }, }); } else { logToChannel( `skipping changing wallet balance for player ${challenge.creator} of ${challenge.amount} because of double hisory creation. uniqueId: ${creatorUniqueId}`, true ); } const playerUniqueId = `${challenge.id}-${ challenge.code || 'no-code' }-cancel-player`; const playerHistory = await createHistory( { user: challenge.player, amount: challenge.amount, historyType: 'cancel', naration: `Canceled against ${challenge.creatorUsername} (Your Result: ${challenge.results.player})`, uniqueId: playerUniqueId, }, 'index.js@cancelChallangePlayer', id ); if (playerHistory) { await logThisToDb({ scope: '[Wallet balance change]', idx1: challenge.amount, challengeId: challenge._id, user: challenge.player, msg: `on cancel - inc`, }); await User.findByIdAndUpdate(challenge.player, { $inc: { wallet: challenge.amount }, }); } else { logToChannel( `skipping changing wallet balance for player ${challenge.creator} of ${challenge.amount} because of double hisory creation. uniqueId: ${playerUniqueId}`, true ); } //referesh running challanges of all players sendRunningChallenges(io); } socket.on('update_result', async ({ id, result, cancellationReason }) => { try { await logThisToDb( { scope: '[update_result] event', challengeId: id, msg: result, user: user ? user._id : 'null', }, 'index.js@update_result' ); if (!user) { await logThisToDb( { scope: '[update_result] user not found', challengeResult: result, challengeId: id, }, 'index.js@update_result' ); return; } // const isPlayerValid = await validateUserBalance(user._id); // if (!isPlayerValid[0]) { // logBadBallance(user._id, 'update result', isPlayerValid[1]); // } let ogChallenge = await Challenge.findById(id); if (!ogChallenge) { await logThisToDb( { scope: '[update_result] ogChallenge not found', user: user._id, challengeId: id, challengeResult: result, }, 'index.js@update_result' ); return; } await logThisToDb( { scope: '[update_result] ogChallenge found', user: user._id, challengeId: id, challengeResult: result, info: `INIT STATE: ${JSON.stringify( ogChallenge.results )} ${JSON.stringify(ogChallenge.state)}}`, }, 'index.js@update_result' ); //make sure this user is either creator orplayer if ( ogChallenge.player.toString() !== String(user._id) && ogChallenge.creator.toString() !== user._id.toString() ) { await logThisToDb( { scope: '[update_result] user is not creator or player', user: user._id, challengeId: id, challengeResult: result, challengeCode: ogChallenge.code, }, 'index.js@update_result' ); if (ogChallenge.state === 'resolved') { await logThisToDb( { scope: '[update_result] user is not creator or player and challenge is already resolved', user: user._id, challengeId: id, challengeResult: result, challengeCode: ogChallenge.code, }, 'index.js@update_result' ); } else { ogChallenge.state = 'hold'; } await ogChallenge.save(); return; } //get the user role let userRole = 'creator'; let oponentRole = 'player'; if (ogChallenge.player.toString() == user._id.toString()) { userRole = 'player'; oponentRole = 'creator'; } //check if user already updated if (ogChallenge.results[userRole]) { await logThisToDb( { scope: '[update_result] user already updated result', challengeId: id, user: user._id, challengeResult: result, challengeCode: ogChallenge.code, }, 'index.js@update_result' ); return; } let challenge; let ogSus = false; if (result === 'lost') { let updateQuery = {}; if ( ogChallenge.createdAt > new Date().getTime() - 1000 * 60 * 7 ) { console.log('challenge is less than 7 minutes old'); updateQuery = { state: 'hold', isSus: true }; ogSus = true; } else { updateQuery = { state: 'resolved' }; } if (userRole == 'creator') { updateQuery.creatorResultTime = new Date(); updateQuery.isSus = ogSus || ogChallenge.isSus; } else { updateQuery.playerResultTime = new Date(); updateQuery.isSus = ogSus || ogChallenge.isSus; } challenge = await Challenge.findOneAndUpdate( { _id: id, $or: [{ state: 'playing' }, { state: 'hold' }], }, updateQuery ); await logThisToDb( { scope: '[update_result] lost premautre update', challengeId: id, user: user._id, challengeResult: result, challengeCode: ogChallenge.code, info: JSON.stringify(updateQuery), }, 'index.js@update_result' ); } else { challenge = await Challenge.findOne({ _id: id, $or: [{ state: 'playing' }, { state: 'hold' }], }); } if (!challenge || challenge.state === 'resolved') { const scope = !challenge ? 'Redirecting because challenge not found' : 'Redirecting because challenge is resolved'; await logThisToDb( { scope: `[update_result] ${scope}`, challengeId: id, user: user._id, challengeResult: result, challengeCode: ogChallenge.code, }, 'index.js@update_result' ); socket.emit('redirect', { user: user._id, to: '/' }); return; } let isSus = false || ogSus; let updationQuery = { results: challenge.results }; updationQuery.results[userRole] = result; if (result === 'won' && challenge.state !== 'resolved') { updationQuery.state = 'hold'; } else if ( result === 'cancel' && challenge.state !== 'resolved' && challenge.results[oponentRole] !== 'cancel' ) { updationQuery.state = 'hold'; } else if (result === 'lost') { if ( ogChallenge.createdAt > new Date().getTime() - 1000 * 60 * 7 || ogChallenge.results[oponentRole] === 'cancel' ) { console.log('challenge is less than 7 minutes old'); updationQuery.state = 'hold'; isSus = true; } else { updationQuery.state = 'resolved'; } } if ( updationQuery.results.creator === 'cancel' && updationQuery.results.player === 'cancel' ) { updationQuery.state = 'resolved'; } if (result === 'cancel') { updationQuery.cancellationReasons = challenge.cancellationReasons || {}; updationQuery.cancellationReasons[userRole] = cancellationReason; } if (userRole == 'creator') { updationQuery.creatorResultTime = new Date(); updationQuery.isSus = isSus || challenge.isSus; } else { updationQuery.playerResultTime = new Date(); updationQuery.isSus = isSus || challenge.isSus; } await Challenge.updateOne({ _id: id }, updationQuery); await logThisToDb( { scope: '[update_result] updationQuery', challengeId: id, user: user._id, challengeResult: result, challengeCode: challenge.code, msg: `BEFORE UPDATE: ${JSON.stringify( challenge.results )} ${JSON.stringify(challenge.state)}}`, info: JSON.stringify(updationQuery), }, 'index.js@update_result' ); //determine who fuck what if (result === 'lost') { //change ballace for this palyer // const getLastLost = await History.find({ // user: user._id, // historyType: 'lose', // }) // .sort({ createdAt: -1 }) // .limit(1); // const lastLost = getLastLost[0]; // if (lastLost) { // const lastLostDate = new Date(lastLost?.createdAt); // const currentDate = new Date(); // const diff = currentDate.getTime() - lastLostDate.getTime(); // if (lastLost && diff < 4 * 60 * 1000) { // console.log(user._id, ' last lost less than 4 mins'); // logFrequentLost( // user._id, // `last lost was ${(diff / 60000).toFixed( // 2 // )} minutes ago` // ); // } // } if (!isSus) { const userResult = challenge.results[userRole] ? ` (Your Result: ${challenge.results[userRole]})` : null; const oponentResult = challenge.results[oponentRole] ? ` (Your Result: ${challenge.results[oponentRole]})` : null; await changeBallance( user._id, { amount: challenge.amount, reason: 'lose', naration: `Lost against ${ challenge[oponentRole + 'Username'] }${userResult ?? ''}`, winner: await User.findById(challenge[oponentRole]), uniqueId: `${challenge.id}-${ challenge.code || 'no-code' }-lose`, }, `${result}@index.js`, id ); //change the ballace of the oponentRole (which automatically adds a history) await changeBallance( challenge[oponentRole], { amount: challenge.amount, reason: 'win', naration: `Won against ${ challenge[userRole + 'Username'] }${oponentResult ?? ''}`, uniqueId: `${challenge.id}-${ challenge.code || 'no-code' }-win`, }, `${result}@index.js`, id ); } //redirect oponent to homepage io.to(String(challenge[oponentRole])).emit('redirect', { id: String(challenge[oponentRole]), to: '/', }); let tempUser = await User.findById(challenge[oponentRole]); //update users ballance io.to(String(challenge[oponentRole])).emit( 'update_wallet', tempUser.wallet ); } //give them their ballace back if both cancels // TODO if ( updationQuery.results.creator === 'cancel' && updationQuery.results.player === 'cancel' ) { // await User.updateMany( // { // $or: [ // { _id: challenge.creator }, // { _id: challenge.player }, // ], // }, // { $inc: { wallet: challenge.amount } } // ); //add two history's const creatorUniqueId = `${challenge.id}-${ challenge.code || 'no-code' }-cancel-creator`; const creatorHistory = await createHistory( { user: challenge.creator, amount: challenge.amount, historyType: 'cancel', naration: `Cancelled Against ${challenge.playerUsername} (Your Result: ${challenge.results.creator})`, uniqueId: creatorUniqueId, }, 'index.js@cancel-creator', id ); if (creatorHistory) { await logThisToDb({ scope: '[Wallet balance change]', idx1: challenge.amount, challengeId: challenge._id, user: challenge.creator, msg: `on cancel - inc`, }); await User.findByIdAndUpdate(challenge.creator, { $inc: { wallet: challenge.amount }, }); } else { logToChannel( `skipping changing wallet balance for player ${challenge.creator} of ${challenge.amount} because of double hisory creation. uniqueId: ${creatorUniqueId}`, true ); } const playerUniqueId = `${challenge.id}-${ challenge.code || 'no-code' }-cancel-player`; const playerHistory = await createHistory( { user: challenge.player, amount: challenge.amount, historyType: 'cancel', naration: `Cancelled against ${challenge.creatorUsername} (Your Result: ${challenge.results.player})`, uniqueId: playerUniqueId, }, 'index.js@cancel-player', id ); if (playerHistory) { await logThisToDb({ scope: '[Wallet balance change]', idx1: challenge.amount, challengeId: challenge._id, user: challenge.player, msg: `on cancel - inc`, }); await User.findByIdAndUpdate(challenge.player, { $inc: { wallet: challenge.amount }, }); } else { logToChannel( `skipping changing wallet balance for player ${challenge.creator} of ${challenge.amount} because of double hisory creation. uniqueId: ${playerUniqueId}`, true ); } } socket.emit('redirect', { id: user._id, to: '/' }); sendRunningChallenges(io); //some other shits // if (result === 'won') { // setTimeout(() => { // resolveChallange({ // id, // challenge, // userRole, // oponentRole, // result, // }); // }, 15 * 60 * 1000); // } //this function is meant to be called when this player updated cancel and the opponent havent updated result for x mins // if (result === 'cancel') { // setTimeout(() => { // cancelChallange({ // id, // challenge, // userRole, // oponentRole, // result, // }); // }, 15 * 60 * 1000); // } } catch (err) { console.error('976@index.js' + err); } }); async function DeleteChallenges() { if (!user) { return; } //delete all open or requested challenges of this user let deletionQuery = { creator: user._id, state: { $in: ['open', ''] }, }; let response = await Challenge.deleteMany(deletionQuery); //update all the challenges that this user is a player on let secondResponse = await Challenge.updateMany( { state: 'requested', player: user._id }, { state: 'open', player: undefined, playerUsername: undefined } ); //emmit refresh events if (response.deletedCount > 0 || secondResponse.nModified > 0) { sendPlayableChallanges(io); sendAllNonPlayingChallenges(io); } } socket.on('page_change', async () => { await DeleteChallenges(); }); socket.on('disconnect', async () => { if (inited) { return; } connectedUsers = connectedUsers.filter( (_user) => _user.id !== user?._id.toString() ); await DeleteChallenges(); }); });
Editor is loading...