egg-socket在egg中的使用


 

WebSocket 的產生源於 Web 開發中日益增長的實時通信需求,對比基於 http 的輪詢方式,它大大節省了網絡帶寬,同時也降低了服務器的性能消耗; socket.io 支持 websocket、polling 兩種數據傳輸方式以兼容瀏覽器不支持 WebSocket 場景下的通信需求。
 
框架提供了 egg-socket.io 插件,增加了以下開發規約:
namespace: 通過配置的方式定義 namespace(命名空間)
middleware: 對每一次 socket 連接的建立/斷開、每一次消息/數據傳遞進行預處理
controller: 響應 socket.io 的 event 事件
router: 統一了 socket.io 的 event 與 框架路由的處理配置方式
 
安裝
$ npm i egg-socket.io --save

 

 開啟插件:config/plugin.js

exports.io = {
  enable: true,
  package: 'egg-socket.io',
};

 配置插件config/config.default.js  

/ 和 new2 屬於不同的命名空間 即如果你有兩個業務用到了socket,可以分別用不同的命名空間去管理,如果只用到一個寫一個及可

exports.io = {
  init: { }, // passed to engine.io
  namespace: {
    '/': {
      connectionMiddleware: [],
      packetMiddleware: [],
    },
    '/news': {
      connectionMiddleware: [],
      packetMiddleware: [],
    },
  },
};

 

 router\io.js 路由可以分別為不同的命名空間配置路由

of 來划分命名空間
io.of('/').route('chat', io.controller.chat.index);
io.of('/').route('message', io.controller.chat.message);
io.of('/').route('user', io.controller.chat.online);

io.of('/news').route('news', io.controller.news.index);

 

在生產環境下Nginx 配置

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:7001;

  # http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind
  # proxy_bind       $remote_addr transparent;
}

 

開啟 egg-socket.io 的項目目錄結構如下:
chat
├── app
│   ├── extend
│   │   └── helper.js
│   ├── io
│   │   ├── controller
│   │   │   └── default.js
│   │   └── middleware
│   │       ├── connection.js
│   │       └── packet.js
│   └── router.js
├── config
└── package.json

對應的文件都在io下

 

 app/io

 

 

配置socket的中間件在 app/io/middleware 下    新建auth.js

在每一個客戶端連接或者退出時發生作用,故而我們通常在這一步進行授權認證,對認證失敗的客戶端做出相應的處理

/**
 * Created by bear on 2018/2/12.
 */
const PREFIX = 'room';  //定義房間號

module.exports = app => {
  return async (ctx, next) => {
    const { app, socket, logger, helper } = ctx;
    const id = socket.id;
    const nsp = app.io.of('/');
    const query = socket.handshake.query;

    // 用戶信息
    const { room, userId } = query;  //獲取socket鏈接傳過來的參數
    const rooms = [ room ];

    console.log(room, userId);

    const tick = (id, msg) => {
      logger.debug('#tick', id, msg);
      // 踢出用戶前發送消息
      socket.emit(id, helper.parseMsg('deny', msg));
      // 調用 adapter 方法踢出用戶,客戶端觸發 disconnect 事件
      nsp.adapter.remoteDisconnect(id, true, err => {
        logger.error(err);
      });
    };
    // 檢查房間是否存在,不存在則踢出用戶
    // 備注:此處 app.redis 與插件無關,可用其他存儲代替
   
    const hasRoom = await app.redis.get(`${PREFIX}:${room}`);
    console.log(hasRoom,`${PREFIX}:${room}`)

    // if (!hasRoom) {
    //   tick(id, {
    //     type: 'deleted',
    //     message: 'deleted, room has been deleted.',
    //   });
    //   return;
    // }

    // 用戶加入
    logger.debug('#join', room);
    socket.join(room);

    // 在線列表
    nsp.adapter.clients(rooms, (err, clients) => {
      // 更新在線用戶列表
      nsp.to(room).emit('online', {
        clients,
        action: 'join',
        target: 'participator',
        message: `User(${id}) joined.`,
      });
      console.log(123,clients)
    });
    // socket.emit('connect', 'packet received!');
    
    await next();
    console.log('disconnect!');

  };
};

 app/io/middleware/filter.js

module.exports = (app) => {
    return async (ctx, next) => {
        // console.log(ctx.packet);
        await next();
        // console.log('packet response!');
    };
};
 
踢出用戶示例:
 
const tick = (id, msg) => {
  logger.debug('#tick', id, msg);
  socket.emit(id, msg);
  app.io.of('/').adapter.remoteDisconnect(id, true, err => {
    logger.error(err);
  });
};

 

Controller
Controller 對客戶端發送的 event 進行處理;由於其繼承於 egg.Contoller, 擁有如下成員對象:
ctx
app
service
config
logger

app/io/controller/chat.js

/**
 * Created by bear on 2018/2/12.
 */
module.exports = app => {
  class chatController extends app.Controller {
    async index() {
      this.ctx.socket.emit('res', 'test');
    }
    async message() {   //方法通過 客戶端 this.emit('message',{})//觸發
      this.ctx.socket.emit('message', 'test');
      const params = this.ctx.args[0];
     // this.ctx.service.message.sendPeerMessage(params);
      console.log(2,params);
    }


    async online() {// modelMessage.sendOfflineMessage(socket, data.userId);
    }
  }
  return chatController;
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM