All Projects → typestack → Socket Controllers

typestack / Socket Controllers

Licence: mit
Use class-based controllers to handle websocket events.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Socket Controllers

socket.io-react
A High-Order component to connect React and Socket.io easily
Stars: ✭ 67 (-64.92%)
Mutual labels:  socket, socket-io, decorators
Node Decorators
node-decorators
Stars: ✭ 230 (+20.42%)
Mutual labels:  decorators, socket, socket-io
Vuesocial
something like QQ、weibo、weChat(vue+express+socket.io仿微博、微信的聊天社交平台)
Stars: ✭ 189 (-1.05%)
Mutual labels:  socket, socket-io
Peeplus
python+vue3前后端分离项目
Stars: ✭ 28 (-85.34%)
Mutual labels:  socket, socket-io
Ngx Socket Io
Socket.IO module for Angular
Stars: ✭ 178 (-6.81%)
Mutual labels:  socket, socket-io
Bizsocket
异步socket,对一些业务场景做了支持
Stars: ✭ 469 (+145.55%)
Mutual labels:  socket, socket-io
Angular Contacts App Example
Full Stack Angular PWA example app with NgRx & NestJS
Stars: ✭ 570 (+198.43%)
Mutual labels:  socket, socket-io
Chatter
A chatting app using socket.io
Stars: ✭ 53 (-72.25%)
Mutual labels:  socket, socket-io
video-group-meeting
WebRTC video chat for multi users using React and Node Express.
Stars: ✭ 40 (-79.06%)
Mutual labels:  socket, socket-io
Rltm.js
Easily swap realtime providers with a single code base
Stars: ✭ 106 (-44.5%)
Mutual labels:  socket, socket-io
Socket.io Redux
Redux middleware to emit action via socket.io
Stars: ✭ 103 (-46.07%)
Mutual labels:  socket, socket-io
Graphql Live Query
Realtime GraphQL Live Queries with JavaScript
Stars: ✭ 112 (-41.36%)
Mutual labels:  socket, socket-io
Socket.io
NodeJS《你画我猜》游戏
Stars: ✭ 255 (+33.51%)
Mutual labels:  socket, socket-io
socket-chat
This project will help you build a chat app by using the Socket IO library.
Stars: ✭ 36 (-81.15%)
Mutual labels:  socket, socket-io
Dodgem
A Simple Multiplayer Game, built with Mage Game Engine.
Stars: ✭ 12 (-93.72%)
Mutual labels:  socket, socket-io
ddos
Simple dos attack utility
Stars: ✭ 36 (-81.15%)
Mutual labels:  socket, socket-io
Progress Bot
High-tech weaponized moe progress delivery bot for IRC, Discord, and web
Stars: ✭ 38 (-80.1%)
Mutual labels:  socket, socket-io
Tsed
📐 Ts.ED is a Node.js and TypeScript framework on top of Express to write your application with TypeScript (or ES6). It provides a lot of decorators and guideline to make your code more readable and less error-prone.
Stars: ✭ 1,941 (+916.23%)
Mutual labels:  decorators, socket-io
react-webrtc-chat
React WebRTC chat
Stars: ✭ 39 (-79.58%)
Mutual labels:  socket, socket-io
chattt-backend
🖥 Backend for chattt
Stars: ✭ 17 (-91.1%)
Mutual labels:  socket, socket-io

socket-controllers

Build Status codecov npm version

Use class-based controllers to handle websocket events. Helps to organize your code using websockets in classes.

Installation

  1. Install socket-controllers:

    npm install socket-controllers
    
  2. Install reflect-metadata shim:

    npm install reflect-metadata
    

    and make sure to import it in a global place, like app.ts:

    import 'reflect-metadata';
    

Example of usage

  1. Create a file MessageController.ts

    import {
      OnConnect,
      SocketController,
      ConnectedSocket,
      OnDisconnect,
      MessageBody,
      OnMessage,
    } from 'socket-controllers';
    
    @SocketController()
    export class MessageController {
      @OnConnect()
      connection(@ConnectedSocket() socket: any) {
        console.log('client connected');
      }
    
      @OnDisconnect()
      disconnect(@ConnectedSocket() socket: any) {
        console.log('client disconnected');
      }
    
      @OnMessage('save')
      save(@ConnectedSocket() socket: any, @MessageBody() message: any) {
        console.log('received message:', message);
        console.log('setting id to the message and sending it back to the client');
        message.id = 1;
        socket.emit('message_saved', message);
      }
    }
    
  2. Create a file app.ts

    import 'es6-shim'; // this shim is optional if you are using old version of node
    import 'reflect-metadata'; // this shim is required
    import { createSocketServer } from 'socket-controllers';
    import { MessageController } from './MessageController';
    
    createSocketServer(3001, {
      controllers: [MessageController],
    });
    
  3. Now you can send save websocket message using websocket-client.

More usage examples

Run code on socket client connect / disconnect

Controller action marked with @OnConnect() decorator is called once new client connected. Controller action marked with @OnDisconnect() decorator is called once client disconnected.

import { SocketController, OnConnect, OnDisconnect } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnConnect()
  save() {
    console.log('client connected');
  }

  @OnDisconnect()
  save() {
    console.log('client disconnected');
  }
}

@ConnectedSocket() decorator

To get connected socket instance you need to use @ConnectedSocket() decorator.

import { SocketController, OnMessage, ConnectedSocket } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  save(@ConnectedSocket() socket: any) {
    socket.emit('save_success');
  }
}

@MessageBody() decorator

To get received message body use @MessageBody() decorator:

import { SocketController, OnMessage, MessageBody } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  save(@MessageBody() message: any) {
    console.log('received message: ', message);
  }
}

If you specify a class type to parameter that is decorated with @MessageBody(), socket-controllers will use class-transformer to create instance of the given class type with the data received in the message. To disable this behaviour you need to specify a { useConstructorUtils: false } in SocketControllerOptions when creating a server.

@SocketQueryParam() decorator

To get received query parameter use @SocketQueryParam() decorator.

import { SocketController, OnMessage, MessageBody } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  save(@SocketQueryParam('token') token: string) {
    console.log('authorization token from query parameter: ', token);
  }
}

Get socket client id using @SocketId() decorator

To get connected client id use @SocketId() decorator.

import { SocketController, OnMessage, MessageBody } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  save(@SocketId() id: string) {}
}

Get access to using socket.io instance using @SocketIO() decorator

import { SocketController, OnMessage, MessageBody } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  save(@SocketIO() io: any) {
    // now you can broadcast messages to specific rooms or namespaces using io instance
  }
}

Send message back to client after method execution

You can use @EmitOnSuccess decorator:

import { SocketController, OnMessage, EmitOnSuccess } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  @EmitOnSuccess('save_successfully')
  save() {
    // after this controller executed "save_successfully" message will be emitted back to the client
  }
}

If you return something, it will be returned in the emitted message data:

import { SocketController, OnMessage, EmitOnSuccess } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  @EmitOnSuccess('save_successfully')
  save() {
    // after this controller executed "save_successfully" message will be emitted back to the client with message object
    return {
      id: 1,
      text: 'new message',
    };
  }
}

You can also control what message will be emitted if there is error/exception during execution:

import { SocketController, OnMessage, EmitOnSuccess, EmitOnFail } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('save')
  @EmitOnSuccess('save_successfully')
  @EmitOnFail('save_error')
  save() {
    if (1 === 1) {
      throw new Error('One is equal to one! Fatal error!');
    }
    return {
      id: 1,
      text: 'new message',
    };
  }
}

In this case save_error message will be sent to the client with One is equal to one! Fatal error! error message.

Sometimes you may want to not emit success/error message if returned result is null or undefined. In such cases you can use @SkipEmitOnEmptyResult() decorator.

import { SocketController, OnMessage, EmitOnSuccess, EmitOnFail, SkipEmitOnEmptyResult } from 'socket-controllers';

@SocketController()
export class MessageController {
  @OnMessage('get')
  @EmitOnSuccess('get_success')
  @SkipEmitOnEmptyResult()
  get(): Promise<Message[]> {
    return this.messageRepository.findAll();
  }
}

In this case if findAll will return undefined, get_success message will not be emitted. If findAll will return array of messages, they will be emitted back to the client in the get_success message. This example also demonstrates Promises support. If promise returned by controller action, message will be emitted only after promise will be resolved.

Using exist server instead of creating a new one

If you need to create and configure socket.io server manually, you can use useSocketServer instead of createSocketServer function. Here is example of creating socket.io server and configuring it with express:

import 'reflect-metadata'; // this shim is required
import { useSocketServer } from 'socket-controllers';

const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);

server.listen(3001);

app.get('/', function (req: any, res: any) {
  res.send('hello express');
});

io.use((socket: any, next: Function) => {
  console.log('Custom middleware');
  next();
});
useSocketServer(io);

Load all controllers from the given directory

You can load all controllers in once from specific directories, by specifying array of directories via options in createSocketServer or useSocketServer:

import 'reflect-metadata'; // this shim is required
import { createSocketServer } from 'socket-controllers';

createSocketServer(3000, {
  controllers: [__dirname + '/controllers/*.js'],
}); // registers all given controllers

Using socket.io namespaces

To listen to messages only of the specific namespace you can mark a controller with namespace:

@SocketController('/messages')
export class MessageController {
  // ...
}

Also you can use dynamic namespace, like express router patterns:

@SocketController('/messages/:userId')
export class MessageController {
  // ...
}

Using middlewares

Middlewares are the functions passed to the socketIo.use method. Middlewares allows you to define a logic that will be executed each time client connected to the server. To create your middlewares use @Middleware decorator:

import { Middleware, MiddlewareInterface } from 'socket-controllers';

@Middleware()
export class CompressionMiddleware implements MiddlewareInterface {
  use(socket: any, next: (err?: any) => any) {
    console.log('do something, for example get authorization token and check authorization');
    next();
  }
}

Don't forget to load your controllers and middlewares

Controllers and middlewares should be loaded:

import 'reflect-metadata';
import { createSocketServer } from 'socket-controllers';
import { MessageController } from './MessageController';
import { MyMiddleware } from './MyMiddleware'; // here we import it
let io = createSocketServer(3000, {
  controllers: [MessageController],
  middlewares: [MyMiddleware],
});

Also you can load them from directories. Also you can use glob patterns:

import 'reflect-metadata';
import { createSocketServer } from 'socket-controllers';
let io = createSocketServer(3000, {
  controllers: [__dirname + '/controllers/**/*.js'],
  middlewares: [__dirname + '/middlewares/**/*.js'],
});

Using DI container

socket-controllers supports a DI container out of the box. You can inject your services into your controllers and middlewares. Container must be setup during application bootstrap. Here is example how to integrate socket-controllers with typedi:

import 'reflect-metadata';
import { createSocketServer, useContainer } from 'socket-controllers';
import { Container } from 'typedi';

// its important to set container before any operation you do with socket-controllers,
// including importing controllers
useContainer(Container);

// create and run socket server
let io = createSocketServer(3000, {
  controllers: [__dirname + '/controllers/*.js'],
  middlewares: [__dirname + '/middlewares/*.js'],
});

That's it, now you can inject your services into your controllers:

@Service()
@SocketController()
export class MessageController {
  constructor(private messageRepository: MessageRepository) {}

  // ... controller actions
}

Note: TypeDI won't create instances for unknown classes since 0.9.0, you have to decorate your Class as a Service() as well.

Decorators Reference

| Signature | Description | | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | | @SocketController(namespace?: string\|Regex) | Registers a class to be a socket controller that can listen to websocket events and respond to them. | | @OnMessage(messageName: string) | Registers controller's action to be executed when socket receives message with given name. | | @OnConnect() | Registers controller's action to be executed when client connects to the socket. | | @OnDisconnect() | Registers controller's action to be executed when client disconnects from the socket. | | @ConnectedSocket() | Injects connected client's socket object to the controller action. | | @SocketIO() | Injects socket.io object that initialized a connection. | | @MessageBody() | Injects received message body. | | @SocketQueryParam(paramName: string) | Injects query parameter from the received socket request. | | @SocketId() | Injects socket id from the received request. | | @SocketRequest() | Injects request object received by socket. | | @SocketRooms() | Injects rooms of the connected socket client. | | @NspParams() | Injects dynamic namespace params. | | @NspParam(paramName: string) | Injects param from the dynamic namespace. | | @Middleware() | Registers a new middleware to be registered in the socket.io. | | @EmitOnSuccess(messageName: string) | If this decorator is set then after controller action will emit message with the given name after action execution. It will emit message only if controller succeed without errors. If result is a Promise then it will wait until promise is resolved and emit a message. | | @EmitOnFail(messageName: string) | If this decorator is set then after controller action will emit message with the given name after action execution. It will emit message only if controller throw an exception. If result is a Promise then it will wait until promise throw an error and emit a message. | | @SkipEmitOnEmptyResult() | Used in conjunction with @EmitOnSuccess and @EmitOnFail decorators. If result returned by controller action is null or undefined then messages will not be emitted by @EmitOnSuccess or @EmitOnFail decorators. | |

Samples

Take a look on samples in ./sample for more examples of usage.

Related projects

  • If you are interested to create controller-based express or koa server use routing-controllers module.
  • If you need to use dependency injection in use typedi module.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].