Prevent duplicate user in socket.io

master
Ian Mancini 4 years ago
parent 04dbf7224c
commit 16cde00e23

@ -1212,6 +1212,15 @@
"@types/express": "*" "@types/express": "*"
} }
}, },
"@types/engine.io": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
"integrity": "sha512-98rXVukLD6/ozrQ2O80NAlWDGA4INg+tqsEReWJldqyi2fulC9V7Use/n28SWgROXKm6003ycWV4gZHoF8GA6w==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/express": { "@types/express": {
"version": "4.17.8", "version": "4.17.8",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz",
@ -1335,6 +1344,16 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/socket.io": {
"version": "2.1.11",
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.11.tgz",
"integrity": "sha512-bVprmqPhJMLb9ZCm8g0Xy8kwBFRbnanOWSxzWkDkkIwxTvud5tKMfAJymXX6LQbizUKCS1yima7JM4BeLqjNqA==",
"dev": true,
"requires": {
"@types/engine.io": "*",
"@types/node": "*"
}
},
"@types/winston": { "@types/winston": {
"version": "2.4.4", "version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz", "resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz",
@ -4177,6 +4196,11 @@
"integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
"dev": true "dev": true
}, },
"notepack.io": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz",
"integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw=="
},
"oauth": { "oauth": {
"version": "0.9.15", "version": "0.9.15",
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
@ -5141,11 +5165,6 @@
} }
} }
}, },
"socket-io": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/socket-io/-/socket-io-1.0.0.tgz",
"integrity": "sha1-/FZvTTCmNwIk0H5l3O84a9j10pY="
},
"socket.io": { "socket.io": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.0.1.tgz", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.0.1.tgz",
@ -5203,6 +5222,33 @@
} }
} }
}, },
"socket.io-redis": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/socket.io-redis/-/socket.io-redis-6.0.1.tgz",
"integrity": "sha512-RvxAhVSsDQJfDUEXUER9MvsE99XZurXkAVORjym1FTReqWlvmPVjyAnrpLlH3RxvPFdFa9sN4kmaTtyzjOtRRA==",
"requires": {
"debug": "~4.1.0",
"notepack.io": "~2.2.0",
"redis": "^3.0.0",
"socket.io-adapter": "~2.0.0",
"uid2": "0.0.3"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"source-map": { "source-map": {
"version": "0.5.7", "version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",

@ -26,6 +26,7 @@
"@types/node": "^14.14.3", "@types/node": "^14.14.3",
"@types/passport": "^1.0.4", "@types/passport": "^1.0.4",
"@types/redis": "^2.8.28", "@types/redis": "^2.8.28",
"@types/socket.io": "^2.1.11",
"@types/winston": "^2.4.4", "@types/winston": "^2.4.4",
"eslint": "^7.12.0", "eslint": "^7.12.0",
"eslint-config-prettier": "^6.14.0", "eslint-config-prettier": "^6.14.0",
@ -51,8 +52,8 @@
"passport.socketio": "^3.7.0", "passport.socketio": "^3.7.0",
"redis": "^3.0.2", "redis": "^3.0.2",
"regenerator-runtime": "^0.13.7", "regenerator-runtime": "^0.13.7",
"socket-io": "^1.0.0",
"socket.io": "^3.0.1", "socket.io": "^3.0.1",
"socket.io-redis": "^6.0.1",
"winston": "^3.3.3" "winston": "^3.3.3"
} }
} }

@ -10,10 +10,10 @@ import proxy from 'express-http-proxy'
import bodyParser from 'body-parser' import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser' import cookieParser from 'cookie-parser'
import session from 'express-session' import session from 'express-session'
import redis from 'redis'
import connectRedis from 'connect-redis' import connectRedis from 'connect-redis'
import connectSocketIO from 'socket.io' import { Server as SocketIO } from 'socket.io'
import { createAdapter } from 'socket.io-redis'
import passportSocketIo from 'passport.socketio' import passportSocketIo from 'passport.socketio'
import morgan from 'morgan' import morgan from 'morgan'
@ -23,23 +23,11 @@ import logger, { morganStream } from './logger'
import passport from 'passport' import passport from 'passport'
import mongoose from 'mongoose' import mongoose from 'mongoose'
import redisClient, { asyncHEXISTS, asyncHGET, asyncHSET, asyncHDEL } from './redis'
import { authRouter, initPassport } from './auth/passport' import { authRouter, initPassport } from './auth/passport'
const RedisStore = connectRedis(session) const RedisStore = connectRedis(session)
const redisClient = redis.createClient({
host: '127.0.0.1',
port: 6379,
password: process.env.REDIS_PASSWORD,
})
redisClient.on('error', (error) => {
console.error(error)
})
redisClient.on('connect', () => {
console.log('Connection to Redis has been established successfully.')
})
mongoose.connect( mongoose.connect(
'mongodb://localhost:27017', 'mongodb://localhost:27017',
@ -52,15 +40,23 @@ mongoose.connect(
dbName: 'museum', dbName: 'museum',
}, },
() => { () => {
console.log('Connection to MongoDB has been established successfully.') logger.info('Connection to MongoDB has been established successfully.')
}, },
) )
const app = express() const app = express()
app.set('trust proxy', 1) app.set('trust proxy', 1)
const server = http.createServer(app) const server = http.createServer(app)
// @ts-ignore const io = new SocketIO(server, { serveClient: false })
const io = connectSocketIO(server)
const pubClient = redisClient
const subClient = pubClient.duplicate()
io.adapter(
createAdapter({
pubClient,
subClient,
}),
)
app.use(bodyParser.json()) app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.urlencoded({ extended: false }))
@ -81,17 +77,31 @@ app.use('/auth', authRouter)
app.use(morgan('short', { stream: morganStream })) app.use(morgan('short', { stream: morganStream }))
function onAuthorizeSuccess(data, accept) { async function onAuthorizeSuccess(data, accept) {
// console.log(data.user) if (data.user._id) {
logger.debug( const userExists = await asyncHEXISTS('socket', String(data.user._id))
`Successful connection to socket.io from ${data.user._id} (${data.user.email})`,
) if (userExists === 1) {
accept(null, true) logger.debug(
`${data.user._id} (${data.user.email}) is already logged in. Kicking...`,
)
const socketId = await asyncHGET('socket', String(data.user._id))
const socket = io.of('/').sockets.get(socketId)
if (socket) {
logger.debug(`Disconnecting ${socketId}`)
socket.disconnect()
}
}
logger.debug(
`Successful connection to socket.io from ${data.user._id} (${data.user.email})`,
)
accept(null, true)
}
} }
function onAuthorizeFail(_, message, error, accept) { function onAuthorizeFail(_, message, error, accept) {
if (error) throw new Error(message) if (error) throw new Error(message)
logger.debug('failed connection to socket.io:', message) logger.debug('Failed to connect to socket.io:', message)
accept(null, false) accept(null, false)
} }
@ -106,11 +116,16 @@ io.use(
}), }),
) )
io.on('connection', (socket) => { io.on('connection', async (socket) => {
logger.debug('a user connected') await asyncHSET('socket', String(socket.request.user._id), String(socket.id))
//console.log(socket.request.user) logger.debug(`Assigned ${socket.id} to ${socket.request.user._id}`)
socket.on('disconnect', () => {
logger.debug('a user connected') socket.on('kick', () => {
console.log('kicking')
})
socket.on('disconnect', async () => {
logger.debug(`User with id ${socket.id} disconnected`)
await asyncHDEL('socket', String(socket.request.user._id), String(socket.id))
}) })
}) })
@ -121,5 +136,5 @@ if (process.env.NODE_ENV !== 'PRODUCTION') {
} }
server.listen(3000, () => { server.listen(3000, () => {
console.log('> Ready on http://localhost:3000') logger.info('Server ready on http://localhost:3000')
}) })

@ -15,7 +15,7 @@ const logger = createLogger({
level: 'debug', level: 'debug',
format: combine(format.colorize(), splat(), timestamp(), myFormat), format: combine(format.colorize(), splat(), timestamp(), myFormat),
transports: [ transports: [
new transports.Console({ level: 'http' }), new transports.Console({ level: 'info' }),
new transports.File({ filename: path.join(__dirname, '../log'), level: 'debug' }), new transports.File({ filename: path.join(__dirname, '../log'), level: 'debug' }),
], ],

@ -0,0 +1,29 @@
import path from 'path'
import dotenv from 'dotenv'
dotenv.config({ path: path.join(__dirname, '../.env') })
import { promisify } from 'util'
import redis from 'redis'
import logger from './logger'
const client = redis.createClient({
host: '127.0.0.1',
port: 6379,
password: process.env.REDIS_PASSWORD,
})
client.on('error', (error) => {
logger.error(error)
})
client.on('connect', () => {
logger.info('Connection to Redis has been established successfully.')
})
export const asyncHEXISTS = promisify(client.HEXISTS).bind(client)
export const asyncHGET = promisify(client.HGET).bind(client)
export const asyncHSET = promisify(client.HSET).bind(client)
export const asyncHDEL = promisify(client.HDEL).bind(client)
export default client
Loading…
Cancel
Save