接口增加防刷机制
This commit is contained in:
parent
ae3eab82a8
commit
feb3ff15fb
@ -9,6 +9,7 @@ import { mongoose } from '@typegoose/typegoose'
|
||||
import logger from 'logger/logger'
|
||||
import { RedisClient } from 'redis/RedisClient'
|
||||
import NonceRecordSchedule from 'schedule/noncerecord.schedule'
|
||||
import { SyncLocker } from 'common/SyncLocker'
|
||||
|
||||
const zReqParserPlugin = require('plugins/zReqParser')
|
||||
|
||||
@ -115,7 +116,7 @@ export class ApiServer {
|
||||
) {
|
||||
reply.send({ errcode: 404, errmsg: 'page not found' })
|
||||
})
|
||||
this.server.setErrorHandler(function (error: FastifyError, request: FastifyRequest, reply: FastifyReply) {
|
||||
this.server.setErrorHandler(function (error: FastifyError, req: FastifyRequest, reply: FastifyReply) {
|
||||
let statusCode = (error && error.statusCode) || 100
|
||||
if (statusCode >= 500) {
|
||||
logger.error(error)
|
||||
@ -137,8 +138,9 @@ export class ApiServer {
|
||||
* @private
|
||||
*/
|
||||
private setFormatSend() {
|
||||
this.server.addHook('preSerialization', async (request: FastifyRequest, reply: FastifyReply, payload) => {
|
||||
this.server.addHook('preSerialization', async (req: FastifyRequest, reply: FastifyReply, payload) => {
|
||||
reply.header('X-Powered-By', 'PHP/5.4.16')
|
||||
new SyncLocker().unlock(req)
|
||||
// @ts-ignore
|
||||
if (!payload.errcode) {
|
||||
payload = {
|
||||
|
@ -14,7 +14,6 @@ export class LotteryCache {
|
||||
}
|
||||
return this.map.get(user+dateTag);
|
||||
}
|
||||
|
||||
public async flush() {
|
||||
for (let record of this.map.values()) {
|
||||
await record.save();
|
||||
|
36
src/common/SyncLocker.ts
Normal file
36
src/common/SyncLocker.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { singleton } from "decorators/singleton";
|
||||
import { FastifyRequest } from "fastify";
|
||||
import { ZError } from "./ZError";
|
||||
|
||||
@singleton
|
||||
export class SyncLocker {
|
||||
map: Map<string, boolean> = new Map();
|
||||
|
||||
public lock(req: FastifyRequest) {
|
||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||
if (this.map.has(key)) {
|
||||
return false;
|
||||
}
|
||||
this.map.set(key, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public unlock(req: FastifyRequest) {
|
||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||
this.map.delete(key);
|
||||
}
|
||||
|
||||
public checkLock(req: FastifyRequest) {
|
||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||
if (this.map.has(key)) {
|
||||
throw new ZError(100, 'request too fast');
|
||||
}
|
||||
this.lock(req);
|
||||
return true;
|
||||
}
|
||||
|
||||
public isLocked(req: FastifyRequest) {
|
||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||
return this.map.has(key);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { SyncLocker } from "common/SyncLocker";
|
||||
import { ZError } from "common/ZError";
|
||||
import BaseController, { ROLE_ANON } from "common/base.controller";
|
||||
import { role, router } from "decorators/router";
|
||||
@ -31,6 +32,7 @@ export default class ActivityController extends BaseController {
|
||||
*/
|
||||
@router('post /api/activity/upload_invite_code')
|
||||
async uploadInviteCode(req) {
|
||||
new SyncLocker().checkLock(req);
|
||||
let { code } = req.params
|
||||
let user = req.user;
|
||||
if (user.inviteUser) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { EMPTY_REWARD, ITEM_FRAME } from "common/Constants";
|
||||
import { LotteryCache } from "common/LotteryCache";
|
||||
import { SyncLocker } from "common/SyncLocker";
|
||||
import { ZError } from "common/ZError";
|
||||
import BaseController from "common/base.controller";
|
||||
import { FUSION_CFG } from "configs/fusion";
|
||||
@ -84,6 +85,7 @@ export default class LotteryController extends BaseController {
|
||||
|
||||
@router('get /api/lottery/draw')
|
||||
async draw(req) {
|
||||
new SyncLocker().checkLock(req);
|
||||
let user = req.user;
|
||||
const { start, end, rewards } = LOTTERY_CFG;
|
||||
const startTime = new Date(start).getTime();
|
||||
@ -145,6 +147,7 @@ export default class LotteryController extends BaseController {
|
||||
|
||||
@router('get /api/lottery/fusion')
|
||||
async fusion(req) {
|
||||
new SyncLocker().checkLock(req);
|
||||
let user = req.user;
|
||||
let items = await ActivityItem.find({user: user.id, activity: user.activity});
|
||||
let itemCountMap = new Map();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import BaseController, {ROLE_ANON} from 'common/base.controller'
|
||||
import { SyncLocker } from 'common/SyncLocker'
|
||||
import {ZError} from 'common/ZError'
|
||||
import { role, router } from 'decorators/router'
|
||||
import logger from 'logger/logger'
|
||||
@ -120,6 +121,7 @@ class SignController extends BaseController {
|
||||
}
|
||||
@router('get /api/user/state/boost')
|
||||
async boost(req){
|
||||
new SyncLocker().checkLock(req);
|
||||
const user = req.user;
|
||||
if (user.boost > 1 && user.boostExpire && user.boostExpire > Date.now()) {
|
||||
throw new ZError(11, 'already boosted')
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { SyncLocker } from "common/SyncLocker";
|
||||
import { ZError } from "common/ZError";
|
||||
import BaseController, { ROLE_ANON } from "common/base.controller";
|
||||
import BaseController from "common/base.controller";
|
||||
import { router } from "decorators/router";
|
||||
import { ActivityInfo, TaskCfg, TaskTypeEnum } from "models/ActivityInfo";
|
||||
import { ActivityUser, TaskStatus, TaskStatusEnum } from "models/ActivityUser";
|
||||
import { TaskCfg, TaskTypeEnum } from "models/ActivityInfo";
|
||||
import { TaskStatus, TaskStatusEnum } from "models/ActivityUser";
|
||||
import { join } from 'path'
|
||||
import { formatDate } from "utils/date.util";
|
||||
const fs = require('fs')
|
||||
@ -74,6 +75,7 @@ export default class TasksController extends BaseController {
|
||||
|
||||
@router('post /api/tasks/begin_task')
|
||||
async beginTask(req) {
|
||||
new SyncLocker().checkLock(req);
|
||||
let user = req.user;
|
||||
let activity = req.activity;
|
||||
let { task } = req.params;
|
||||
@ -161,6 +163,7 @@ export default class TasksController extends BaseController {
|
||||
|
||||
@router('post /api/tasks/claim')
|
||||
async claimTask(req) {
|
||||
new SyncLocker().checkLock(req);
|
||||
const user = req.user;
|
||||
const activity = req.activity;
|
||||
const { task } = req.params;
|
||||
|
Loading…
x
Reference in New Issue
Block a user