require('xprofiler').start({ log_dir: '/zyz_logs/xprofiler', }); import { COM_TEAM_STATUS, STATUS } from './app/consts'; import { createTcpAcceptor, createTcpMailBox, FrontendOrBackendSession, HandlerCallback, pinus, RESERVED, RouteRecord } from 'pinus'; import * as mongoose from 'mongoose'; import * as redisService from './app/services/redisService'; import './app/servers/user.rpc.define' import * as routeUtil from './app/util/routeUtil'; import { preload } from './preload'; import { globalFilter } from'./app/servers/connector/filter/global'; import { guildAuthFilter } from'./app/servers/guild/filter/guildAuthFilter'; import { tokenFilter } from'./app/servers/gm/filter/tokenFilter'; import { connectRedis } from './app/pubUtils/redis'; import * as timeTaskService from './app/services/timeTaskService'; import * as redlockCacheService from './app/services/redlockCacheService'; import * as redLockService from './app/services/redLockService'; // TODO 需要整理。 import _pinus = require('pinus'); import { updateTeamStatus } from './app/services/battle/comBattleService'; import { resResult, genCode } from './app/pubUtils/util'; import { errlogger, infologger, loadLogger } from './app/util/logger'; import { connectThinkingData, getTire } from './app/services/sdkService'; import { loadSubDb, loadGmDb } from './app/db'; import { loadActivities } from './app/services/memoryCache/activityData'; import { checkAndSetApiIsClose } from './app/services/chatService'; import { initGuildActivityIndexInPinus, resetJoinWoodenHorse } from './app/services/guildActivity/guildActivityService'; import { setGVGConfig } from './app/services/gvg/gvgService'; import { isDevelopEnv } from './app/services/utilService'; import { initTeamToMem } from './app/services/gvg/gvgBattleService'; import { setServerGroup } from './app/services/serverService'; // 管理相关模块 import { UpdateComponent } from './app/components/UpdateComponent'; import { EvalComponent } from './app/components/EvalComponent'; import { UsrAdminModule } from './app/modules/UsrAdmin'; const filePath = (_pinus as any).FILEPATH; filePath.MASTER = '/config/master'; filePath.SERVER = '/config/servers'; filePath.CRON = '/config/crons'; filePath.LOG = '/config/log4js'; filePath.SERVER_PROTOS = '/config/serverProtos'; filePath.CLIENT_PROTOS = '/config/clientProtos'; filePath.MASTER_HA = '/config/masterha'; filePath.LIFECYCLE = '/lifecycle'; filePath.SERVER_DIR = '/app/servers/'; filePath.CONFIG_DIR = '/config'; const adminfilePath = _pinus.DEFAULT_ADMIN_PATH; adminfilePath.ADMIN_FILENAME = 'adminUser'; adminfilePath.ADMIN_USER = 'config/adminUser'; const ALL_ENVS = 'stable|development|alpha|dev|isbn|isbnhk|monitor|monitor2|distribute|sq1|sq3|sq4|sq7|sq9|zy1|yjzios|ch1|zytest'; /** * 替换全局Promise * 自动解析sourcemap * 捕获全局错误 */ preload(); if (process.env.NODE_PROCESS_TITLE) { process.title = process.env.NODE_PROCESS_TITLE; } console.log('process.env.NODE_ENV:', process.env.NODE_PROCESS_TITLE); /** * Init app for client. */ let app = pinus.createApp(); app.set('name', 'zyz'); // 全局配置,对所有 env 所有 serverType 生效 app.configure(function () { app.loadConfig('database', app.getBase() + '/config/database'); console.log('env:', app.get('env')); console.log('db:', app.get('database')); setupRoutes(app); setupFilters(app); connectThinkingData(app); loadLogger(app.getServerId()); treatStartLogic(app); app.set(RESERVED.ERROR_HANDLER, errorHandler); app.set(RESERVED.GLOBAL_ERROR_HANDLER, globalErrorHandler); // RPC 启用TCP协议 app.set('proxyConfig', { mailboxFactory: createTcpMailBox, // bufferMsg:true // rpc 超时时间 // timeout: 20 * 1000, // dynamicUserProxy: true, }); app.set('remoteConfig', { acceptorFactory: createTcpAcceptor, // bufferMsg:true, // interval:50, }); app.set('serverConfig', { 'reloadHandlers': true, 'reloadRemotes': true, }); app.load(UpdateComponent, { app: app }); app.load(EvalComponent, { app: app }); }); // 对所有 env 的 个别 serverType 进行配置 app.configure(ALL_ENVS, 'connector', function () { app.set('connectorConfig', { connector: pinus.connectors.hybridconnector, heartbeat: 60, useDict: false, useProtobuf: true }); app.set('protobufConfig', { // protobuf Encoder 使用 5m 的缓存 需要保证每个消息不会超过指定的缓存大小,超过了就会抛出异常 encoderCacheSize: 5 * 1024 * 1024, // decode 对客户端请求消息做校验 decodeCheckMsg: true, }); }); // wss加密 // app.configure('sq1', 'connector', function() { // app.set('connectorConfig', // { // connector: pinus.connectors.hybridconnector, // heartbeat: 60, // useDict: true, // useProtobuf: true, // ssl: { // type: 'wss', // key: fs.readFileSync('/usr/local/nginx/conf/cert/*.37wan.com.key'), // cert: fs.readFileSync('/usr/local/nginx/conf/cert/*.37wan.com_with_chain.crt'), // } // }); // }); app.configure(ALL_ENVS, 'gate', function () { app.set('connectorConfig', { connector: pinus.connectors.hybridconnector, useProtobuf: true }); }); app.configure(ALL_ENVS, 'guild', function () { app.filter(guildAuthFilter(app)); }) app.configure(ALL_ENVS, 'gm', function () { app.filter(tokenFilter(app)); }); app.registerAdmin(UsrAdminModule, {app: app}); function errorHandler(err: Error, msg: any, resp: any, session: FrontendOrBackendSession, cb: HandlerCallback) { const errCode = genCode(10); if(err.message == 'globalFilter') { infologger.debug('global after ', msg && msg.logCode, msg && JSON.stringify(msg), resp && JSON.stringify(resp), session && session.get('roleId')); } else { errlogger.error(`${pinus.app.serverId} error handler \n msg[${JSON.stringify(msg)}] \n resp[${JSON.stringify(resp)}] \n sessionId:${JSON.stringify(session.export())} \n error 【${errCode}】 stack: ${err.stack}`); } if (!resp) { resp = resResult(STATUS.GLOBAL_ERR, { errCode, stack: err.stack }); } cb(err, resp); } export function globalErrorHandler(err: Error, msg: any, resp: any, session: FrontendOrBackendSession, cb: HandlerCallback) { const errCode = genCode(10); errlogger.error(`${pinus.app.serverId} globalErrorHandler handler \n msg[${JSON.stringify(msg)}] \n resp[${JSON.stringify(resp)}] \n sessionId:${JSON.stringify(session.export())} \n error 【${errCode}】 stack: ${err.stack}`); if (cb) { cb(err, resp ? resp : { code: 503 }); } } async function treatStartLogic(app: _pinus.Application) { await connectDb(app); console.log('treatStartLogic', app.getServerType()); if(app.getServerType() == 'systimer') { redisService.redisSubScribe(); timeTaskService.init(); initGuildActivityIndexInPinus(); } if(app.getServerType() == 'chat' && !isDevelopEnv()) { getTire(); } if(app.getServerType() == 'activity') { loadActivities(); } treatStartMainten(app); checkAndSetApiIsClose(); if(app.getServerType() == 'guild') { initGuildActivityIndexInPinus() .then(resetJoinWoodenHorse); } if(app.getServerType() == 'battle'|| app.getServerType() == 'role'|| app.getServerType() == 'connector') { timeTaskService.setPvpSeasonNum(); timeTaskService.setPvpSettleSeasonNum(); } if(app.getServerType() != 'systimer') { timeTaskService.initHiddenData(); } if(app.getServerType() == 'battle'|| app.getServerType() == 'guild'|| app.getServerType() == 'chat'|| app.getServerType() == 'connector' || app.getServerType() == 'systimer' || app.getServerType() == 'gm') { setServerGroup(); } if(app.getServerType() == 'guild') { setGVGConfig() app.event.on('start_all', () => { setGVGConfig().then(initTeamToMem); }); } if(app.isMaster()) { // redisService.initAllRank(); redisService.readDataBase(); redisService.clearComBtlQueue(); redisService.clearChannelServers(); redisService.clearGVGHistoryAreas(); redisService.clearGVGHistoryAreaTeam(); redisService.clearGVGHistoryCityTeam(); redisService.resetMaxOnlineUsers(); updateTeamStatus(COM_TEAM_STATUS.DEFAULT, COM_TEAM_STATUS.LOOSE); updateTeamStatus(COM_TEAM_STATUS.FIGHTING, COM_TEAM_STATUS.LOOSE); } } async function treatStartMainten(app: _pinus.Application) { if(app.getServerType() == 'systimer') { // 维护信息 await timeTaskService.initMaintenance(undefined, true); } else { await timeTaskService.initMaintenanaceInOtherServers(); } } async function connectDb(app: _pinus.Application) { // Promise并行处理 return Promise.all([ initMongodb(app), initSubMongodb(app), initGmMongodb(app), initRedis(app) ]) } async function initMongodb(app: _pinus.Application) { await mongoose.connect(app.get('database').mongo, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false }, (err) => { if (err) { errlogger.error('mongodb connect err', err); } else { console.log('mongodb connect suc'); } }); } async function initSubMongodb(app: _pinus.Application) { let connect = await mongoose.createConnection(app.get('database').mongoSub||app.get('database').mongo, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false }); loadSubDb(connect); console.log('subMongo connect suc') } async function initGmMongodb(app: _pinus.Application) { let gmconnect = await mongoose.createConnection(app.get('database').gmmongo, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false }); loadGmDb(gmconnect); console.log('mongoGmDb connect suc') } function initRedis(app: _pinus.Application) { const redisClient = connectRedis(app.get('database').redis, app.get('database').redispw); app.set('redis', redisClient); const redisClientPub = connectRedis(app.get('database').redis, app.get('database').redispw); app.set('redisPub', redisClientPub); // 发布订阅机 // app.set('redis', redisClient); const redisClientLock = connectRedis(app.get('database').redisLock||app.get('database').redis, app.get('database').redisLockpw||app.get('database').redispw); redLockService.initRedlock(redisClientLock); redlockCacheService.init(); } function setupRoutes(app: _pinus.Application) { app.route('chat', routeUtil.chat); app.route('battle', routeUtil.battle); app.route('comBattle', routeUtil.comBattle); app.route('gm', routeUtil.gm); app.route('guild', routeUtil.guild); app.route('activity', routeUtil.activity); app.route('order', routeUtil.order); app.route('role', routeUtil.role); } function setupFilters(app: _pinus.Application) { // filter configures app.filter(new pinus.filters.time()); app.filter(new pinus.filters.timeout()); app.filter(globalFilter(app)); app.globalAfter((err: Error, routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, resp: any, cb: HandlerCallback) => { if (err) infologger.debug(err); }) app.globalBefore((routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, cb: HandlerCallback) => { if (msg.body === null) { cb(new Error(`msg body ===null maybe protobuf check error uid:${session.uid} ${JSON.stringify(msg)}`), { code: 499 }); return; } cb(null); }); } // TODO: 所有环境打开监听模块和日志 app.configure(function () { // enable the system monitor modules app.enable('systemMonitor'); app.enable('rpcDebugLog'); }); if (app.isMaster()) { // app.use(createRobotPlugin({scriptFile: __dirname + '/robot/robot.js'})); app.event.on('add_servers', (server) => { redisService.setConnectors(server); }) app.event.on('replace_servers', (server) => { redisService.setConnectors(server); }) app.event.on('remove_servers', (server) => { redisService.removeConnectors(server); }) app.event.on('start_all', () => { // 全部服务器启动完毕后初始化 redis 数据 redisService.checkConnectors(); }); } // start app app.start();