UNPKG

egg-jianghu

Version:
194 lines (171 loc) 6.04 kB
'use strict'; const { resourceTypeEnum, socketResponse, resourcePath, socketRequest: socketRequestBodyBuild, } = require('../constant/constant'); const { BizError, errorInfoEnum } = require('../constant/error'); const { sqlResource, serviceResource, } = require('./controllerUtil/resourceUtil'); const socketPackage = require('../middleware/socketPackage'); const socketPackageRecord = require('../middleware/socketPackageRecord'); const socketUserInfo = require('../middleware/socketUserInfo'); const socketAuthorization = require('../middleware/socketAuthorization'); const syncSocketStatus = require('../schedule/syncSocketStatus'); const socketResourceBeforeHook = require('../middleware/socketResourceBeforeHook'); const socketResourceAfterHook = require('../middleware/socketResourceAfterHook'); async function socketRequest({ socket, app, body }, next) { const { packageId, packageType, appData } = body; const { jianghuKnex, config } = app; const { appId, jiangHuConfig: { packageIdCheck }, } = config; const ctx = app.createAnonymousContext(); ctx.jianghuSocket = socket; ctx.request.body = body; ctx.body = body; await socketPackage(ctx); await socketResourceBeforeHook(ctx); await socketUserInfo(ctx); await socketAuthorization(ctx); const { packageResource } = ctx; const { resourceType, resourceId, pageId, actionId } = packageResource; // packageId 唯一性校验 if (packageIdCheck) { const resourceActivity = await jianghuKnex(tableEnum._resource_request_log) .where({ packageId }) .first(); if (resourceActivity || !packageId) { throw new BizError(errorInfoEnum.request_repeated); } } // TODO: base64场景 appData太大了 app.logger.debug('[socketResource.js socketRequest body]', { packageId, resourceId, appData, }); let resultData; switch (resourceType) { case resourceTypeEnum.socketSql: case resourceTypeEnum.sql: resultData = await sqlResource({ jianghuKnex, ctx }); break; case resourceTypeEnum.service: case resourceTypeEnum.socketService: resultData = await serviceResource({ ctx }); break; default: throw new BizError(errorInfoEnum.resource_not_support); } // 记录socket请求 await socketPackageRecord(ctx); // Tip:socket connect 场景; 必须先next() 让链接建立成功; next(); if (packageType === 'socketRequest') { const responseBody = socketResponse.success({ packageId, // TODO: ...resultData, resultData 为兼容代码 appData: { ...resultData, resultData, appId, pageId, actionId }, }); socket.emit(resourcePath, responseBody); } await socketResourceAfterHook(ctx); } async function socketIOInit(app) { const { socketIO, logger, config: { appId }, } = app; const socketIOConnectEventBuild = socketIO => { socketIO.use(async function(socket, next) { try { const body = socket.handshake.auth; const { appData: { actionData: { socketId } } } = body; if (socketId) { // 建立连接时把其它同名 socket 下线 const allSockets = await socketIO.fetchSockets(); const oldList = allSockets.filter(s => s.id === socketId); if (oldList.length > 0) { for (const old of oldList) { logger.info('[disconnect old same name socket]', old.id); await old.disconnect(); } } } await socketRequest({ socket, app, body }, next); } catch (error) { logger.error('[第一次建立连接失败]', error); next(error); } }); }; const socketIOOtherEventBuild = socketIO => { socketIO.on('connection', socket => { const { id: socketId } = socket; logger.info('[socket connection success]', { socketId }); // 业务入口 socket.on(resourcePath, async function(body) { const { packageId, appData } = body; const { appId, pageId, actionId } = appData; try { await socketRequest({ socket, app, body }, () => {}); } catch (err) { logger.error('[resource.js socketIOOtherEventBuild]', err); const errorCode = err.errorCode || err.code || errorInfoEnum.server_error.errorCode; const errorReason = err.errorReason || err.sqlMessage || err.message || errorInfoEnum.server_error.errorReason; const errorReasonSupplement = err.errorReasonSupplement || null; const socketBody = socketResponse.fail({ packageId, appData: { errorCode, errorReason, errorReasonSupplement, appId, pageId, actionId, }, }); socket.emit(resourcePath, socketBody); } }); // 断线 socket.on('disconnect', async function(message) { const { id: socketId } = socket; logger.warn('[socket disconnect]', { socketId, message }); // 切换网络时,可能出现异常的 disconnect,其实 socket 已经重连了 // 所以多检查一下在线 socket 列表 const allSockets = await socketIO.fetchSockets(); // logger.info('[socket disconnect, allSockets]', allSockets); if (allSockets.find(s => s.id === socketId)) { logger.info('[socket ignore disconnect]', { socketId, message }); return; } // 调用应用层的 disconnect 方法 const body = socketRequestBodyBuild.bodyBuild({ appData: { appId, pageId: 'socket', actionId: 'disconnect', authToken: null, actionData: { message }, }, }); await socketRequest({ socket, app, body }, () => {}); }); }); }; socketIOConnectEventBuild(socketIO); socketIOOtherEventBuild(socketIO); } module.exports = socketIOInit;