Skip to content
This repository has been archived by the owner on Sep 27, 2021. It is now read-only.

Commit

Permalink
feat(middleware): add support for Adonis style middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Mar 16, 2018
1 parent 4a7ef8c commit f0eaf3d
Show file tree
Hide file tree
Showing 8 changed files with 555 additions and 713 deletions.
1,065 changes: 365 additions & 700 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@
"license": "MIT",
"devDependencies": {
"@adonisjs/fold": "^4.0.7",
"@adonisjs/framework": "^5.0.4",
"@adonisjs/framework": "^5.0.5",
"@adonisjs/sink": "^1.0.16",
"coveralls": "^3.0.0",
"cz-conventional-changelog": "^2.1.0",
"japa": "^1.0.6",
"japa-cli": "^1.0.1",
"nyc": "^11.6.0",
"standard": "^11.0.0",
"standard": "^11.0.1",
"test-console": "^1.1.0"
},
"dependencies": {
"@adonisjs/generic-exceptions": "^2.0.0",
"@adonisjs/middleware-base": "^1.0.0",
"@adonisjs/websocket-packet": "^1.0.6",
"co-compose": "^4.0.0",
"cuid": "^2.1.0",
"debug": "^3.1.0",
"emittery": "^0.3.0",
Expand Down
17 changes: 8 additions & 9 deletions src/Channel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
*/

const GE = require('@adonisjs/generic-exceptions')
const Middleware = require('co-compose')
const debug = require('debug')('adonis:websocket')
const middleware = require('../Middleware')

/**
* Channel class gives a simple way to divide the application
Expand Down Expand Up @@ -54,10 +54,9 @@ class Channel {
this.subscriptions = new Map()

/**
* Middleware to be executed when someone attempts to join
* a topic
* Named middleware defined on the channel
*/
this._middleware = new Middleware()
this._middleware = []

/**
* The method attached as an event listener to each
Expand Down Expand Up @@ -109,10 +108,10 @@ class Channel {
* @private
*/
_executeMiddleware (context) {
if (!this._middleware.list.length) {
return Promise.resolve()
}
return this._middleware.runner().params([context]).run()
return middleware
.composeGlobalAndNamed(this._middleware)
.params([context])
.run()
}

/**
Expand Down Expand Up @@ -253,7 +252,7 @@ class Channel {
*/
middleware (middleware) {
const middlewareList = Array.isArray(middleware) ? middleware : [middleware]
this._middleware.register(middlewareList)
this._middleware = this._middleware.concat(middlewareList)
return this
}

Expand Down
13 changes: 13 additions & 0 deletions src/Middleware/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'

/**
* adonis-websocket
*
* (c) Harminder Virk <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

const MiddlewareBase = require('@adonisjs/middleware-base')
module.exports = new MiddlewareBase('wsHandle')
2 changes: 1 addition & 1 deletion src/Socket/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class Socket {
* @return {void}
*/
serverError (code, reason) {
this.emitter.emit('connection-error', { code, reason })
this.emitter.emit('error', { code, reason })
}

/**
Expand Down
42 changes: 42 additions & 0 deletions src/Ws/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Connection = require('../Connection')
const ClusterHop = require('../ClusterHop')
const ChannelManager = require('../Channel/Manager')
const JsonEncoder = require('../JsonEncoder')
const middleware = require('../Middleware')

/**
* The websocket server is a wrapper over `ws` node library and
Expand Down Expand Up @@ -253,6 +254,47 @@ class Ws {
this._clearTimer()
}
}

/**
* Register an array of global middleware
*
* @method registerGlobal
*
* @param {Array} list
*
* @chainable
*
* @example
* ```js
* Ws.registerGlobal([
* 'Adonis/Middleware/AuthInit'
* ])
* ```
*/
registerGlobal (list) {
middleware.registerGlobal(list)
return this
}

/**
* Register a list of named middleware
*
* @method registerNamed
*
* @param {Object} list
*
* @chainable
*
* ```js
* Ws.registerNamed({
* auth: 'Adonis/Middleware/Auth'
* })
* ```
*/
registerNamed (list) {
middleware.registerNamed(list)
return this
}
}

module.exports = Ws
93 changes: 93 additions & 0 deletions test/unit/channel.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ const { ioc } = require('@adonisjs/fold')
const Channel = require('../../src/Channel')
const Manager = require('../../src/Channel/Manager')
const Socket = require('../../src/Socket')
const middleware = require('../../src/Middleware')

const helpers = require('../helpers')
const FakeConnection = helpers.getFakeConnection()

test.group('Channel', (group) => {
group.beforeEach(() => {
ioc.restore()
middleware._middleware.global = []
middleware._middleware.named = {}
})

group.before(() => {
setupResolver()
})
Expand Down Expand Up @@ -246,6 +253,92 @@ test.group('Channel', (group) => {
}, 200)
})
})

test('pass named middleware reference to channel', (assert, done) => {
const ctx = {
socket: new Socket('foo', new FakeConnection()),
joinStack: []
}

ioc.fake('Adonis/Middleware/Foo', () => {
class Foo {
async wsHandle (__ctx__, next) {
__ctx__.joinStack.push(1)
await next()
}
}
return new Foo()
})

ioc.fake('Adonis/Middleware/Bar', () => {
class Bar {
async wsHandle (__ctx__, next) {
__ctx__.joinStack.push(2)
await next()
}
}
return new Bar()
})

middleware.registerNamed({
foo: 'Adonis/Middleware/Foo',
bar: 'Adonis/Middleware/Bar'
})

const channel = new Channel('foo', function (__ctx__) {
__ctx__.joinStack.push(3)
})

channel.middleware(['foo', 'bar'])

channel
.joinTopic(ctx)
.then(() => {
process.nextTick(() => {
assert.deepEqual(ctx.joinStack, [1, 2, 3])
done()
})
})
.catch(done)
})

test('pass runtime params to middleware', (assert, done) => {
const ctx = {
socket: new Socket('foo', new FakeConnection()),
joinStack: []
}

ioc.fake('Adonis/Middleware/Foo', () => {
class Foo {
async wsHandle (__ctx__, next, params) {
__ctx__.joinStack = __ctx__.joinStack.concat(params)
await next()
}
}
return new Foo()
})

middleware.registerNamed({
foo: 'Adonis/Middleware/Foo'
})

const channel = new Channel('foo', function (__ctx__) {
__ctx__.joinStack.push('done')
})

channel.middleware(['foo:first', 'foo:second'])

channel
.joinTopic(ctx)
.then(() => {
process.nextTick(() => {
done(() => {
assert.deepEqual(ctx.joinStack, ['first', 'second', 'done'])
})
})
})
.catch(done)
})
})

test.group('Channel Manager', (group) => {
Expand Down
30 changes: 30 additions & 0 deletions test/unit/ws.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
const test = require('japa')
const { Config } = require('@adonisjs/sink')
const Ws = require('../../src/Ws')
const middleware = require('../../src/Middleware')

const helpers = require('../helpers')

test.group('Ws', (group) => {
group.afterEach(() => {
middleware._middleware.global = []
middleware._middleware.named = {}

if (this.ws) {
this.ws.close()
}
Expand Down Expand Up @@ -129,4 +133,30 @@ test.group('Ws', (group) => {
}, 200)
})
})

test('register global middleware', (assert) => {
this.ws = new Ws(new Config())
this.ws.registerGlobal(['Adonis/Middleware/AuthInit'])

assert.deepEqual(middleware._middleware.global, [
{
namespace: 'Adonis/Middleware/AuthInit.wsHandle',
params: []
}
])
})

test('register named middleware', (assert) => {
this.ws = new Ws(new Config())
this.ws.registerNamed({
auth: 'Adonis/Middleware/Auth'
})

assert.deepEqual(middleware._middleware.named, {
auth: {
namespace: 'Adonis/Middleware/Auth.wsHandle',
params: []
}
})
})
})

0 comments on commit f0eaf3d

Please sign in to comment.