From 02b21f27e02185c963837d6d6df69edaea953287 Mon Sep 17 00:00:00 2001 From: luying Date: Tue, 26 Jan 2021 16:53:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=9B=E5=9B=A2=EF=BC=9A=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servers/battle/handler/guildHandler.ts | 17 +++++-- game-server/app/services/guildService.ts | 45 +++++++++++++++---- game-server/app/services/redLockService.ts | 8 +++- .../app/services/redlockCacheService.ts | 5 +++ shared/consts/constModules/guildConst.ts | 4 ++ shared/consts/statusCode.ts | 1 + shared/db/ErrLog.ts | 26 +++++++++++ 7 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 shared/db/ErrLog.ts diff --git a/game-server/app/servers/battle/handler/guildHandler.ts b/game-server/app/servers/battle/handler/guildHandler.ts index a7cb0f5cf..70ebef3a5 100644 --- a/game-server/app/servers/battle/handler/guildHandler.ts +++ b/game-server/app/servers/battle/handler/guildHandler.ts @@ -1,6 +1,6 @@ import { Application, BackendSession, pinus, ChannelService } from 'pinus'; import { resResult, getRandEelm, reduceCe, getRefTime } from '../../../pubUtils/util'; -import { STATUS, GUILD_OPERATE, GUILD_AUTH, GUILD_JOB, GUILD_APPLY_TYPE, GUILD_STRUCTURE, GUILD_REC_TYPE, GUILD_STRUCTURE_NAME, MAIL_TYPE, REDIS_KEY } from '../../../consts'; +import { STATUS, GUILD_OPERATE, GUILD_AUTH, GUILD_JOB, GUILD_APPLY_TYPE, GUILD_STRUCTURE, GUILD_REC_TYPE, GUILD_STRUCTURE_NAME, MAIL_TYPE, REDIS_KEY, GUILD_DATA_NAME } from '../../../consts'; import { UserGuildModel } from '../../../db/UserGuild'; import { checkAuth, joinGuild, getGuildWithRefActive, getUserGuildWithRefActive, addActive, message, settleGuildWeekly } from '../../../services/guildService'; import { GuildModel, GuildType } from '../../../db/Guild'; @@ -15,6 +15,7 @@ import { hasStructureConsume, getStructureConsume, gameData } from '../../../pub import { GuildRecModel } from '../../../db/GuildRec'; import { sendMail } from '../../../services/mailService'; import { existsRank, initSingleRankWithServer, getRank, setRank, redisUserInfoUpdate, redisUserInfoAdd, removeFromRank, getMyRank } from '../../../services/redisService'; +import { lockData } from '../../../services/redLockService'; import { openGuildRefine } from '../../../services/guildRefineService'; import { unlockTrain } from '../../../services/guildTrainService'; @@ -638,7 +639,7 @@ export class GuildHandler { const roleId = session.get('roleId'); const roleName = session.get('roleName'); const sid = session.get('sid'); - // const serverId = session.get('serverId'); + const serverId = session.get('serverId'); const { code, roleId: leaderRoleId } = msg; // 弹劾的权限 @@ -670,7 +671,6 @@ export class GuildHandler { const topUser = topUserGuild.role; // 交换 - // TODO redlock await UserGuildModel.updateInfo(leaderRoleId, { auth: GUILD_AUTH.MEMBER }, {}, 'auth'); // 团长撤 await UserGuildModel.updateInfo(topUserGuild.roleId, { auth: GUILD_AUTH.LEADER }, {}, 'auth'); // 最高功勋人升 let managerCntInc = topUserGuild.auth == GUILD_AUTH.MANAGER ? -1 : 0; // 管理人数 @@ -705,35 +705,44 @@ export class GuildHandler { const checkResult = await checkAuth(GUILD_OPERATE.UP_STRUCTURE, roleId, code); if (!checkResult) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH); + let res:any = await lockData(serverId, GUILD_DATA_NAME.UP_STRUCTURE, code);// 加锁 + if (!!res.err) return resResult(STATUS.REDLOCK_ERR); + const guild = await GuildModel.findByCode(code, serverId, 'lv structure'); if(!guild) { + res.releaseCallback();//解锁 return resResult(STATUS.GUILD_NOT_FOUND); } - // TODO 加写锁 const { lv, structure } = guild; const curStructure = structure.find(cur => cur.id == id); if(!curStructure) { + res.releaseCallback(); //解锁 return resResult(STATUS.GUILD_STRUCTURE_NOT_FOUND); } if(id != GUILD_STRUCTURE.ARMY_CENTER && curStructure.lv >= lv) { // 中军大帐以外建筑物 if(curStructure.lv >= lv) { + res.releaseCallback(); //解锁 return resResult(STATUS.GUILD_STRUCTURE_LV_MAX); } } if(!hasStructureConsume(id, curStructure.lv + 1)) { + res.releaseCallback(); //解锁 return resResult(STATUS.GUILD_STRUCTURE_LV_MAX); } const cost = getStructureConsume(id, curStructure.lv); const costResult = await GuildModel.costFund(code, cost); if(!costResult) { + res.releaseCallback(); //解锁 return resResult(STATUS.GUILD_FUND_NOT_ENOUGH); } const result = await GuildModel.upStructure(code, id, 'code fund structure lv'); if(!result) { + res.releaseCallback(); //解锁 return resResult(STATUS.GUILD_STRUCTURE_NOT_FOUND); } + res.releaseCallback(); //解锁 const resultStructure = result.structure.find(cur => cur.id == id); // 修改信息 diff --git a/game-server/app/services/guildService.ts b/game-server/app/services/guildService.ts index 89586b038..bde54825e 100644 --- a/game-server/app/services/guildService.ts +++ b/game-server/app/services/guildService.ts @@ -1,7 +1,7 @@ import { gameData, getGuildActiveWeekReward, getGuildActiveByIdAndType } from "../pubUtils/data"; import { GuildModel, GuildType } from "../db/Guild"; -import { resResult, shouldRefreshWeek, shouldRefresh } from "../pubUtils/util"; -import { STATUS, GUILD_OPERATE, MAIL_TYPE, GUILD_AUTH, GUILD_JOB, REDIS_KEY, } from "../consts"; +import { resResult, shouldRefresh } from "../pubUtils/util"; +import { STATUS, MAIL_TYPE, GUILD_AUTH, GUILD_JOB, REDIS_KEY, GUILD_DATA_NAME, } from "../consts"; import { RoleModel, RoleType } from "../db/Role"; import { UserGuildModel, UserGuildType } from "../db/UserGuild"; import { UserGuildApplyModel } from "../db/UserGuildApply"; @@ -13,6 +13,8 @@ import { ARMY } from "../pubUtils/dicParam"; import { sendMail } from "./mailService"; import { setRank, getMyRank, initSingleRank } from "./redisService"; import { GuildRankParam, GuildLeader } from "../pubUtils/interface"; +import { lockData, isLocked } from '../services/redLockService'; +import { ErrLogModel } from '../db/ErrLog'; /** * @description 检查该玩家是否有权限做操作 @@ -22,7 +24,7 @@ import { GuildRankParam, GuildLeader } from "../pubUtils/interface"; export async function checkAuth(func: number, roleId: string, code?: string, userGuild?: UserGuildType) { const auth = await UserGuildModel.getMyAuth(roleId, code, userGuild); const dicGuildAuth = gameData.guildAuth.get(func); - console.log(auth, dicGuildAuth) + // console.log(auth, dicGuildAuth) if(!dicGuildAuth) return false; return dicGuildAuth.includes(auth); @@ -36,44 +38,60 @@ export async function checkAuth(func: number, roleId: string, code?: string, use */ export async function joinGuild(code: string, lv: number, roleId: string, serverId: number) { - // TODO 加redlock + // 周结算锁 + let isWeeklySum = await isLocked(serverId, GUILD_DATA_NAME.WEEKLY_GUILD_SUM, code); + if(isWeeklySum) return { status: 0, resResult: resResult(STATUS.GUILD_WEEKLY_SUM) }; + + // 人数锁 + let res:any = await lockData(serverId, GUILD_DATA_NAME.JOIN_GUILD, code);// 加锁 + if (!!res.err) return { status: 0, resResult: resResult(STATUS.REDLOCK_ERR) }; const result = await RoleModel.joinGuild(roleId); if(!result) { + res.releaseCallback();//解锁 return { status: 0, resResult: resResult(STATUS.GUILD_HAS_JOIN) }; } const dicCenterBase = gameData.centerBase.get(lv); if(!dicCenterBase) { + res.releaseCallback();//解锁 return { status: 0, resResult: resResult(STATUS.DIC_DATA_NOT_FOUND) }; } const maxMemberCnt = dicCenterBase.peopleNum; const guild = await GuildModel.addGuild(code, roleId, maxMemberCnt, serverId, result.ce); if(!guild) { + res.releaseCallback();//解锁 return { status: 0, resResult: resResult(STATUS.GUILD_MEMBER_MAX) }; } const role = await RoleModel.findByRoleId(roleId); const userGuild = await UserGuildModel.createUserGuild(guild.code, role, false); if(!userGuild) { + res.releaseCallback();//解锁 return { status: 0, resResult: resResult(STATUS.GUILD_CREATE_ERROR) }; } await UserGuildApplyModel.deleteApply(roleId); // 删除玩家所有对其他公会的申请 + res.releaseCallback();//解锁 return { status: 1, guild, userGuild, roleName: role.roleName, memberCnt: guild.memberCnt } } /** - * 刷新军团活跃 + * 刷新军团日活跃 * @param guildCode 军团唯一code * @param serverId 区 */ export async function getGuildWithRefActive(guildCode: string, serverId: number) { - // TODO 加写锁 + let res:any = await lockData(serverId, GUILD_DATA_NAME.REFRESH_ACTIVE, guildCode);// 加锁 + if (!!res.err) return false; + let guild = await GuildModel.findByCode(guildCode, serverId, '+refTimeDaily'); - if(!guild) return false; + if(!guild) { + res.releaseCallback();//解锁 + return false; + } console.log(JSON.stringify(guild)); const now = new Date(); @@ -84,6 +102,7 @@ export async function getGuildWithRefActive(guildCode: string, serverId: number) activeDaily = 0; refTimeDaily = now; guild = await GuildModel.updateInfo(guildCode, { activeDaily, refTimeDaily }, {}); } + res.releaseCallback();//解锁 return guild; } @@ -113,6 +132,10 @@ export async function addActive(roleId: string, serverId: number, id: number, ty let guild = await getGuildWithRefActive(guildCode, serverId); if(!guild) return { status: 0, resResult: resResult(STATUS.GUILD_NOT_FOUND) }; + // 周结算锁 + let isWeeklySum = await isLocked(serverId, GUILD_DATA_NAME.WEEKLY_GUILD_SUM, guildCode); + if(isWeeklySum) return { status: 0, resResult: resResult(STATUS.GUILD_WEEKLY_SUM) }; + let {activeRecord} = userGuild; if(id != 0) { // 用于debug,传0时直接增加活跃 let curActiveRecord = activeRecord.find(cur => cur.id == id); @@ -168,7 +191,12 @@ export async function settleGuildWeekly() { console.log('————— settleGuildWeekly —————'); const guildList = await GuildModel.findAllGuild('code activeWeekly memberCnt serverId'); + // 周结算时,1. 不能变动memberCnt 2.玩家activeWeekly不能变动 3.公会activeWeekly不能变动 for(let { code, memberCnt, serverId } of guildList) { + let res:any = await lockData(serverId, GUILD_DATA_NAME.WEEKLY_GUILD_SUM, code);//加锁 + if (!!res.err) { + await ErrLogModel.create(`settle guild lock data error: ${res.err}`) + } const userGuildList = await UserGuildModel.getListByGuild(code, 'roleId auth activeWeekly', { activeWeekly: -1, activeUpdateTime: 1 }); let otherMemberCnt = 0; // 除了大将军以外从活跃高到底成员人数,用户计算活跃排名百分比 @@ -189,7 +217,7 @@ export async function settleGuildWeekly() { if(otherMemberCnt <= rankCnt) break; } } - await UserGuildModel.updateInfo(roleId, { job,/* activeWeekly: 0*/ }, {}); + await UserGuildModel.updateInfo(roleId, { job, activeWeekly: 0 }, {}); if(activeWeekly > ARMY.ARMY_WEEKHONOUR_LIMIT) { // 低于一定不发奖励 members.set(roleId, job); @@ -211,6 +239,7 @@ export async function settleGuildWeekly() { } await GuildModel.updateInfo(code, { activeWeekly: 0 }, {}); + res.releaseCallback();//解锁 } await initSingleRank(REDIS_KEY.GUILD_ACTIVE_RANK); await SystemConfigModel.updateSystemConfig({settleGuildWeeklyTime: nowSeconds()}); // 记录一下 diff --git a/game-server/app/services/redLockService.ts b/game-server/app/services/redLockService.ts index e16287fe1..d84c715e0 100644 --- a/game-server/app/services/redLockService.ts +++ b/game-server/app/services/redLockService.ts @@ -1,5 +1,5 @@ import { localrun } from "pinus/lib/master/starter"; -import { setLock, releaseLock } from './redlockCacheService'; +import { setLock, releaseLock, getLock } from './redlockCacheService'; var Redlock = require('redlock'); var _redlockCache; @@ -62,4 +62,10 @@ function lock(lockKey: string) { } export async function releaseCallback(lockKey: string) { releaseLock(lockKey); +} + +export async function isLocked(serverId: number, dataName: string, id: string) { + let key = 'serverId_'+serverId+'_'+dataName+'_'+id; + let lockKey = 'locks:' + key; + return getLock(lockKey); } \ No newline at end of file diff --git a/game-server/app/services/redlockCacheService.ts b/game-server/app/services/redlockCacheService.ts index bbbc0e8d7..44d87de29 100644 --- a/game-server/app/services/redlockCacheService.ts +++ b/game-server/app/services/redlockCacheService.ts @@ -34,3 +34,8 @@ export function releaseLock(lockKey: string) { export function setLock(lockKey: string, lock: any){ userCacheMap.set(lockKey, {lock, time: nowSeconds()}) }; + +export function getLock(lockKey: string) { + var userCache = userCacheMap.get(lockKey); + return !!userCache && !!userCache.lock +} \ No newline at end of file diff --git a/shared/consts/constModules/guildConst.ts b/shared/consts/constModules/guildConst.ts index eefe7f98e..ee5c0ae81 100644 --- a/shared/consts/constModules/guildConst.ts +++ b/shared/consts/constModules/guildConst.ts @@ -124,6 +124,10 @@ export enum GUILD_DATA_NAME { GUILD = 'Guild', GUILD_REFINE = 'GuildRefine', GUILD_ASSIST_REFINE = 'GuildAssistRefine', + UP_STRUCTURE = 'GuildStructure', + JOIN_GUILD = 'JoinGuild', + REFRESH_ACTIVE = 'GuildRefActive', + WEEKLY_GUILD_SUM = 'WeeklyGuildSum', // 每周结算活跃和奖励 } export const GUILD_REPORT_NUM = 40; diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 76e3efd59..c907953ea 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -147,6 +147,7 @@ export const STATUS = { GUILD_ACTIVE_BOX_NOT_FOUND: { code: 20918, simStr: '未找到该活跃宝箱' }, GUILD_ACTIVE_POINT_NOT_REACH: { code: 20919, simStr: '军团活跃值不足' }, GUILD_ACTIVE_BOX_HAS_RECEIVED: { code: 20920, simStr: '该活跃宝箱已领取' }, + GUILD_WEEKLY_SUM: { code: 20921, simStr: '正在周结算中' }, // 通用 30000 - 30099 DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' }, diff --git a/shared/db/ErrLog.ts b/shared/db/ErrLog.ts new file mode 100644 index 000000000..ceb8c6454 --- /dev/null +++ b/shared/db/ErrLog.ts @@ -0,0 +1,26 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; +import { genCode } from '../pubUtils/util' + +/** + * 自增 ID +*/ +@index({ name: 1 }) +export default class ErrLog extends BaseModel { + + @prop({ required: true }) + code: string; + + @prop({ required: true, default: "" }) + desc: string; + + public static async create(desc: string) { + let code = genCode(12); + await ErrLogModel.insertMany({ code, desc }); + } + +} + +export const ErrLogModel = getModelForClass(ErrLog); + +export interface ErrLogType extends Pick, keyof ErrLog>{}; \ No newline at end of file