diff --git a/packages/socketio/src/index.ts b/packages/socketio/src/index.ts index 5ca37702c3..d502cade9f 100644 --- a/packages/socketio/src/index.ts +++ b/packages/socketio/src/index.ts @@ -1,7 +1,7 @@ import http from 'http' import { Server, ServerOptions } from 'socket.io' import { createDebug } from '@feathersjs/commons' -import { Application } from '@feathersjs/feathers' +import { Application, RealTimeConnection } from '@feathersjs/feathers' import { socket } from '@feathersjs/transport-commons' import { disconnect, params, authentication, FeathersSocket } from './middleware' @@ -42,7 +42,7 @@ function configureSocketio(port?: any, options?: any, config?: any) { // Function that gets the connection const getParams = (socket: FeathersSocket) => socket.feathers // A mapping from connection to socket instance - const socketMap = new WeakMap() + const socketMap = new WeakMap() // Promise that resolves with the Socket.io `io` instance // when `setup` has been called (with a server) const done = new Promise((resolve) => { @@ -67,7 +67,7 @@ function configureSocketio(port?: any, options?: any, config?: any) { if (!this.io) { const io = (this.io = new Server(port || server, options)) - io.use(disconnect(app, getParams)) + io.use(disconnect(app, getParams, socketMap)) io.use(params(app, socketMap)) io.use(authentication(app, getParams)) diff --git a/packages/socketio/src/middleware.ts b/packages/socketio/src/middleware.ts index 33e3362615..a16fdc8339 100644 --- a/packages/socketio/src/middleware.ts +++ b/packages/socketio/src/middleware.ts @@ -1,4 +1,4 @@ -import { Application, Params } from '@feathersjs/feathers' +import { Application, Params, RealTimeConnection } from '@feathersjs/feathers' import { createDebug } from '@feathersjs/commons' import { Socket } from 'socket.io' @@ -10,14 +10,27 @@ export interface FeathersSocket extends Socket { feathers?: Params & { [key: string]: any } } -export const disconnect = - (app: Application, getParams: ParamsGetter) => (socket: FeathersSocket, next: NextFunction) => { +export const disconnect = ( + app: Application, + getParams: ParamsGetter, + socketMap: WeakMap +) => { + app.on('disconnect', (connection: RealTimeConnection) => { + const socket = socketMap.get(connection) + if (socket && socket.connected) { + socket.disconnect() + } + }) + + return (socket: FeathersSocket, next: NextFunction) => { socket.on('disconnect', () => app.emit('disconnect', getParams(socket))) next() } +} export const params = - (_app: Application, socketMap: WeakMap) => (socket: FeathersSocket, next: NextFunction) => { + (_app: Application, socketMap: WeakMap) => + (socket: FeathersSocket, next: NextFunction) => { socket.feathers = { provider: 'socketio', headers: socket.handshake.headers diff --git a/packages/socketio/test/index.test.ts b/packages/socketio/test/index.test.ts index 0e7a9e7b56..32a14449e7 100644 --- a/packages/socketio/test/index.test.ts +++ b/packages/socketio/test/index.test.ts @@ -241,6 +241,18 @@ describe('@feathersjs/socketio', () => { assert.ok(mySocket) }) + it('app `disconnect` event disconnects socket (#2754)', (done) => { + const mySocket = io('http://localhost:7886?channel=dctest') + + app.once('connection', (connection) => { + assert.strictEqual(connection.channel, 'dctest') + mySocket.once('disconnect', () => done()) + app.emit('disconnect', connection) + }) + + assert.ok(mySocket) + }) + it('missing parameters in socket call works (#88)', (done) => { socket.emit('find', 'verify', (error: any, data: any) => { assert.ok(!error)