Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

Commit

Permalink
feat(socket): Controller DI (#37)
Browse files Browse the repository at this point in the history
* feat(socket): Controller DI

* chore(socket, express): Clean up
  • Loading branch information
serhiisol authored Feb 27, 2017
1 parent 81d884a commit 2711529
Show file tree
Hide file tree
Showing 17 changed files with 178 additions and 80 deletions.
2 changes: 1 addition & 1 deletion express/src/decorators/params.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ParameterType, ExpressClass } from '../interface';
import { ParameterType, ExpressClass, ParameterConfiguration } from '../interface';
import { getMeta } from '../meta';

/**
Expand Down
2 changes: 1 addition & 1 deletion express/src/express.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Router, Express, RequestHandler } from 'express';

import { ParameterType, Routes, Middleware, Injectable, ExpressClass } from './interface';
import { ParameterType, Routes, Middleware, Injectable, ExpressClass, Params } from './interface';

function getParam(source: any, paramType: string, name: string) {
let param = source[paramType] || source;
Expand Down
8 changes: 7 additions & 1 deletion playground/socket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class SocketWrapper {
@Namespace('/messaging')
class FirstController {

constructor(...args) {
console.log(args);
}

@Event('message', (io, socket, packet, next) => {
console.log('Message middleware');
next();
Expand All @@ -46,4 +50,6 @@ class FirstController {

}

bootstrapSocketIO(server, [ FirstController ]);
bootstrapSocketIO(server, [
{ provide: FirstController, deps: [1, 2, 3]}
]);
7 changes: 7 additions & 0 deletions socket/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Socket#1.4.0
* Controller DI
```typescript
{ provide: UserController, deps: [UserService] }
```
* Renamed methods **bootstrapSocketIO** and **attachControllerToSocket** (see README for details)

# Socket#1.3.3
* Added possibility to pass array of middleware funcs into:
* **@ServerMiddleware**
Expand Down
11 changes: 9 additions & 2 deletions socket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@ npm install @decorators/socket --save
```
### API
#### Functions
* **bootstrapSocketIO(io: SocketIO.Server, Controllers)** - Attaches controllers to IO server
* **attachControllerToSocket(io: SocketIO.Server, socket: SocketIO.Socket, Controllers)** - Attaches controllers to Socket
* **attachControllers(io: SocketIO.Server, Controller[] || Injectable[])** - Attaches controllers to IO server
* **attachControllersToSocket(io: SocketIO.Server, socket: SocketIO.Socket, Controller[] || Injectable[])** - Attaches controllers to Socket
where Injectable:
```typescript
{ provide: UserController, deps: [UserService] }
```

* **bootstrapSocketIO(io: SocketIO.Server, Controllers)** - Attaches controllers to IO server - **_[deprecated, use attachControllers - will be removed in v2.0.0 of this library]_**
* **attachControllerToSocket(io: SocketIO.Server, socket: SocketIO.Socket, Controllers)** - Attaches controllers to Socket - **_[deprecated, use attachControllersToSocket - will be removed in v2.0.0 of this library]_**

#### Decorators
##### Class
Expand Down
20 changes: 19 additions & 1 deletion socket/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
export * from './src';
export {
Namespace,
ServerMiddleware,
GlobalMiddleware,
Middleware,
Connection,
Disconnect,
GlobalEvent,
Event,
IO,
Socket,
Args,
Callback,
attachControllers,
attachControllersToSocket
} from './src';

/** @deprecated */
export { bootstrapSocketIO, attachControllerToSocket } from './src';
2 changes: 1 addition & 1 deletion socket/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@decorators/socket",
"version": "1.3.3",
"version": "1.4.0",
"description": "node decorators",
"main": "index.js",
"dependencies": {
Expand Down
1 change: 1 addition & 0 deletions socket/src/decorators/class.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SocketIOMeta } from '../interface';
import { getMeta } from '../meta';

/**
Expand Down
6 changes: 3 additions & 3 deletions socket/src/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './class';
export * from './property';
export * from './param';
export { Namespace, ServerMiddleware, GlobalMiddleware, Middleware } from './class';
export { Connection, Disconnect, GlobalEvent, Event } from './property';
export { IO, Socket, Args, Callback } from './param';
6 changes: 3 additions & 3 deletions socket/src/decorators/param.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ParameterType, SocketIOClass, ParameterConfiguration } from '../interface';
import { getMeta } from '../meta';
import { ParameterType } from '../interface';

/**
* Add parameter to metadata
Expand All @@ -22,7 +22,7 @@ function addParameterMeta(target: SocketIOClass, propertyKey: string | symbol, c
*/
function parameterDecoratorFactory(parameterType: ParameterType): () => ParameterDecorator {
return function(): ParameterDecorator {
return function (target: SocketIOClass, propertyKey: string | symbol, index: number) {
return function(target: SocketIOClass, propertyKey: string | symbol, index: number) {
addParameterMeta(target, propertyKey, {index, type: parameterType});
};
};
Expand All @@ -40,7 +40,7 @@ export const IO = parameterDecoratorFactory(ParameterType.IO);
* @type { (WrapperClass?: any) => ParameterDecorator }
*/
export const Socket = function(WrapperClass?: any): ParameterDecorator {
return function (target: SocketIOClass, propertyKey: string | symbol, index: number) {
return function(target: SocketIOClass, propertyKey: string | symbol, index: number) {
addParameterMeta(target, propertyKey, {
index, type: ParameterType.Socket, data: WrapperClass
});
Expand Down
1 change: 1 addition & 0 deletions socket/src/decorators/property.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SocketIOClass, SocketIOMeta } from '../interface';
import { getMeta } from '../meta';

/**
Expand Down
18 changes: 17 additions & 1 deletion socket/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
export * from './decorators';
export {
Namespace,
ServerMiddleware,
GlobalMiddleware,
Middleware,
Connection,
Disconnect,
GlobalEvent,
Event,
IO,
Socket,
Args,
Callback
} from './decorators';
export { attachControllers, attachControllersToSocket } from './socket';

/** @deprecated */
export { bootstrapSocketIO, attachControllerToSocket } from './socket';
48 changes: 48 additions & 0 deletions socket/src/interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
export interface ParameterConfiguration {
index: number;
type: any;
name?: string;
data?: any;
}

export interface Params {
[key: string]: ParameterConfiguration[];
}

/**
* Parameter types enum
*/
Expand All @@ -7,3 +18,40 @@ export enum ParameterType {
Args,
Callback
}

export interface Listener {
[key: string]: {
event: string;
middleware: Function[];
};
}

export interface SocketIOMeta {
serverOrPort: any;
options: any;
namespace: string;

middleware: {
io: Function[];
socket: Function[];
controller: Function[];
}

listeners: {
all: string[],
io: Listener;
socket: Listener;
};

params: Params;
}

export interface Injectable {
provide: Function;
deps: any[];
}
export interface SocketIOClass extends Object {
__meta__: SocketIOMeta;

new (...deps: any[]);
}
2 changes: 2 additions & 0 deletions socket/src/meta.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SocketIOClass, SocketIOMeta } from './interface';

/**
* Get or initiate metadata on target
* @param target
Expand Down
84 changes: 58 additions & 26 deletions socket/src/socket.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { ParameterType } from './interface';
import {
ParameterType,
Listener,
SocketIOMeta,
Injectable,
SocketIOClass,
ParameterConfiguration,
Params
} from './interface';

/**
* Dummy function to ensure, that callback exists
Expand Down Expand Up @@ -53,9 +61,9 @@ function extractParameters(
* loop through all params and put them into correct order
*/
for (let item of params) {
switch(item.type) {
switch (item.type) {
default: args[item.index] = getSocket(item, socket); break; // socket
case ParameterType.IO: args[item.index] = io; break;
case ParameterType.Socket: args[item.index] = getSocket(item, socket); break;
case ParameterType.Args: args[item.index] = eventArgs.pop(); break;
case ParameterType.Callback: args[item.index] = callback || noop; break;
}
Expand Down Expand Up @@ -93,22 +101,24 @@ function applyListeners(

(socket || io).on(listeners[listener].event, (...args) => {
let handlerArgs = extractParameters(io, (socket || args[0]), params[listener], args);
return controller[listener].apply(controller, handlerArgs)
return controller[listener].apply(controller, handlerArgs);
});
}
}

/**
* Get artifacts, instantiates controller and extract meta data
* @param Controller
* @param deps
* @returns { {controller, meta: SocketIOMeta, listeners: {io: Listener, socket: Listener}, params: Params} }
*/
function getArtifacts(Controller) {
const controller = new Controller(),
meta: SocketIOMeta = controller.__meta__,
namespace: string = meta.namespace,
listeners = meta.listeners,
params = meta.params;
function getArtifacts(Controller, deps) {
const controller = new Controller(...deps);
const meta: SocketIOMeta = controller.__meta__;
const namespace: string = meta.namespace;
const listeners = meta.listeners;
const params = meta.params;

return { controller, meta, listeners, params, namespace };
}

Expand All @@ -123,7 +133,7 @@ function _attachControllerToSocket(io, socket, artifacts) {
* Apply all registered middleware to socket
*/
artifacts.meta.middleware.socket.forEach(middleware => {
(<any>socket).use((...args) =>middleware.apply(middleware, [io, socket, ...args]));
(<any>socket).use((...args) => middleware.apply(middleware, [io, socket, ...args]));
});

/**
Expand All @@ -132,7 +142,7 @@ function _attachControllerToSocket(io, socket, artifacts) {
artifacts.meta.middleware.controller.forEach(middleware => {
(<any>socket).use((packet, next) => {
if (artifacts.meta.listeners.all.indexOf(packet[0]) !== -1) {
return middleware.apply(middleware, [io, socket, packet, next])
return middleware.apply(middleware, [io, socket, packet, next]);
}
next();
});
Expand All @@ -155,9 +165,9 @@ function _attachControllerToSocket(io, socket, artifacts) {
* @param io
* @param Controller
*/
function attachController(io: SocketIO.Server, Controller) {
const artifacts = getArtifacts(Controller),
_io: SocketIO.Namespace = io.of(artifacts.namespace);
function attachController(io: SocketIO.Server, Controller, deps) {
const artifacts = getArtifacts(Controller, deps);
const _io: SocketIO.Namespace = io.of(artifacts.namespace);

/**
* Apply all registered global middleware to io
Expand All @@ -180,27 +190,49 @@ function attachController(io: SocketIO.Server, Controller) {
/**
* Attaches controllers to IO server
* @param {SocketIO.Server} io
* @param {Object[]} Controllers
* @param {Array<Injectable|ExpressClass>} injectables
*/
export function bootstrapSocketIO(io: SocketIO.Server, Controllers: any[]) {
Controllers.forEach(Controller => {
attachController(io, Controller);
});
export function attachControllers(io: SocketIO.Server, injectables: Array<Injectable | SocketIOClass>) {
injectables
.forEach((injectable: Injectable | SocketIOClass) => {
const controller = (<Injectable>injectable).provide || <SocketIOClass>injectable;
const deps = (<Injectable>injectable).deps || [];

attachController(io, controller, deps);
});
}

/**
* Attach Controller to already existed socket io server
* With this approach you can't define global middleware, it's up to you.
* @param {SocketIO.Server} io
* @param {SocketIO.Socket} socket
* @param Controllers
* @param {Array<Injectable|ExpressClass>} injectables
*/
export function attachControllerToSocket(
export function attachControllersToSocket(
io: SocketIO.Server,
socket: SocketIO.Socket,
Controllers
injectables: Array<Injectable | SocketIOClass>
) {
Controllers.forEach(Controller => {
_attachControllerToSocket(io, socket, getArtifacts(Controller));
});
injectables
.forEach((injectable: Injectable | SocketIOClass) => {
const controller = (<Injectable>injectable).provide || <SocketIOClass>injectable;
const deps = (<Injectable>injectable).deps || [];

_attachControllerToSocket(io, socket, getArtifacts(controller, deps));
});
}

/**
* @alias
* @see attachControllers
* @deprecated
*/
export let bootstrapSocketIO = attachControllers;

/**
* @alias
* @see attachControllersToSocket
* @deprecated
*/
export let attachControllerToSocket = attachControllersToSocket;
10 changes: 0 additions & 10 deletions types/base.d.ts

This file was deleted.

Loading

0 comments on commit 2711529

Please sign in to comment.