@yutai/egg-socket.io
TypeScript icon, indicating that this package has built-in type declarations

1.0.5 • Public • Published

Install

$ npm i "@yutai/egg-socket.io" --save
$ npm i ioredis --save
  • 这是socket.io4.x版本 支持的适配器 @socket.io/redis-adapter, @socket.io/redis-streams-adapter 两种适配器
  • 适配器版本
  • 以下适配器内置
  • "@socket.io/redis-adapter": "^8.2.1",
  • "@socket.io/redis-streams-adapter": "^0.1.0",
 redis: {
      Redis: require('ioredis'), // 必须的配置
      clients: {
        lord: {
          port: 6379, // Redis port
          host: '127.0.0.1', // Redis host
          password: '123456',
          db: 0, // 0-15个数据库,默认为0
        },
        ioRedis: { // io适配器使用 必须的配置
          port: 6379, // Redis port
          host: '127.0.0.1', // Redis host
          password: '123456',
          db: 0, // 0-15个数据库,默认为0
        },
      },
    },
    io: { // 这里和官方是一样的配置
      init: {}, // passed to engine.io
      namespace: {
        '/': {
          connectionMiddleware: [ 'ioAuth' ], // 连接中间件
          packetMiddleware: [], // 数据包中间件
        },
      },
      redisAdapter: 'redisStreamsAdapter', // 适配器 adapter ||  redisStreamsAdapter
    },

redis 使用

const redis = app.redis.get('lord');
const ioRedis = app.redis.get('ioRedis');
redis.set('foo', 'bar'); // 这里就一样了

Requirements

  • Node.js >= 8.0
  • Egg.js >= 2.0

Configuration

Change ${app_root}/config/plugin.js to enable Socket.IO plugin:

// {app_root}/config/plugin.js
exports.io = {
  enable: true,
    package: '@yutai/egg-socket.io',
};

Configure Socket.IO in ${app_root}/config/config.default.js:

exports.io = {
  init: {}, // 一样的配置
  namespace: {
    '/': {
      connectionMiddleware: [],
      packetMiddleware: [],
    },
  },
  redis: {
    host: '127.0.0.1',
    port: 6379
  }
};

generateId

Note: This function is left on purpose to override and generate a unique ID according to your own rule:

exports.io = {
  generateId: (request) => {
        // Something like UUID.
        return 'This should be a random unique ID';
    }
};

Deployment

Node Conf

Because of socket.io's design, the multi process socket.io server must work at sticky mode.

So, you must start cluster server with sticky set to true, otherwise it will cause handshake exception.

$ # modify your package.json - npm scripts
$ egg-bin dev --sticky
$ egg-scripts start --sticky

which will start egg cluster with:

startCluster({
  sticky: true,
  ...
});

Nginx Conf

if you use a nginx proxy server:

location / {
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_pass   http://127.0.0.1:{ your node server port };
}

Usage

Directory Structure

app
├── io
│   ├── controller
│   │   └── chat.js
│   └── middleware
│       ├── auth.js
│       ├── filter.js
├── router.js
config
 ├── config.default.js
 └── plugin.js

Middleware

middleware are functions which every connection or packet will be processed by.

Connection Middleware

  • Write your connection middleware app/io/middleware/auth.js
module.exports = app => {
    return async (ctx, next) => {
        ctx.socket.emit('res', 'connected!');
        await next();
        // execute when disconnect.
        console.log('disconnection!');
    };
};
  • then config this middleware to make it works.

config/config.default.js

exports.io = {
  namespace: {
    '/': {
      connectionMiddleware: ['auth'],
    },
  },
};

pay attention to the namespace, the config will only work for a specific namespace.

Packet Middleware

  • Write your packet middleware app/io/middleware/filter.js
module.exports = app => {
    return async (ctx, next) => {
        ctx.socket.emit('res', 'packet received!');
        console.log('packet:', this.packet);
        await next();
    };
};
  • then config this middleware to make it works.

config/config.default.js

exports.io = {
  namespace: {
    '/': {
      packetMiddleware: ['filter'],
    },
  },
};

pay attention to the namespace, the config will only work for a specific namespace.

Controller

controller is designed to handle the emit event from the client.

example:

app/io/controller/chat.js

module.exports = app => {
  class Controller extends app.Controller {
    async ping() {
      const message = this.ctx.args[0];
      await this.ctx.socket.emit('res', `Hi! I've got your message: ${message}`);
    }
  }
  return Controller
};

 // or async functions
exports.ping = async function() {
  const message = this.args[0];
  await this.socket.emit('res', `Hi! I've got your message: ${message}`);
};

next, config the router at app/router.js

module.exports = app => {
  // or app.io.of('/')
  app.io.route('chat', app.io.controller.chat.ping);
};

Router

A router is mainly responsible for distributing different events corresponding to a controller on a specific socket connection.

It should be configured at app/router.js refer to the last chapter.

Besides that, there are several system Event:

  • disconnecting doing the disconnect
  • disconnect connection has disconnected
  • error Error occured

Example:

app/router.js

app.io.route('disconnect', app.io.controller.chat.disconnect);

app/io/controller/chat.js

module.exports = (app) => {
  class Controller extends app.Controller {
    async disconnect() {
      const message = this.ctx.args[0];
      console.log(message);
    }
  }
  return Controller
};

Session

The session is supported by egg-socket.io. It's behaviour just like the normal HTTP session.

Session creates or check just happens at the handshake period. Session can be accessed by ctx.session in packetMiddleware and controller, but it's only created at the handshake period.

The feature is powered by egg-session, make sure it has been enabled.

Questions & Suggestions

Please open an issue here.

License

MIT

Package Sidebar

Install

npm i @yutai/egg-socket.io

Weekly Downloads

0

Version

1.0.5

License

MIT

Unpacked Size

30.5 kB

Total Files

16

Last publish

Collaborators

  • yutai