发送邮件接口增加分布式锁, 默认55秒锁定
This commit is contained in:
parent
5001ca558f
commit
8405836b69
@ -59,4 +59,6 @@ OKX_SECRET_KEY='AF7F4CEE2A10715F9709D38452CE0BFD'
|
||||
|
||||
DISCORD_CLIENT_ID='1199290913155981345'
|
||||
DISCORD_CLIENT_SECRET='0-iIPG1waeQ7GpFV3e_dGH6kfjv1SVNS'
|
||||
DISCORD_REDIRECT_URI='https://oauth-svr.cebggame.com/oauth/redirect'
|
||||
DISCORD_REDIRECT_URI='https://oauth-svr.cebggame.com/oauth/redirect'
|
||||
|
||||
REDIS=redis://192.168.100.22:6379/13
|
@ -29,10 +29,12 @@
|
||||
"fastify": "^4.8.1",
|
||||
"fastify-plugin": "^4.2.1",
|
||||
"google-auth-library": "^8.5.2",
|
||||
"ioredis": "^5.4.1",
|
||||
"mongoose": "^6.6.5",
|
||||
"mongoose-findorcreate": "^3.0.0",
|
||||
"nanoid": "^3.1.23",
|
||||
"node-schedule": "^2.1.1",
|
||||
"redlock": "^5.0.0-beta.2",
|
||||
"rustwallet": "file:./rustwallet",
|
||||
"siwe": "^2.1.4",
|
||||
"tracer": "^1.1.6",
|
||||
|
4
publish.sh
Executable file
4
publish.sh
Executable file
@ -0,0 +1,4 @@
|
||||
cd ..
|
||||
tar zcvf wallet-svr.tar.gz ./wallet-svr
|
||||
scp -P27256 ./wallet-svr.tar.gz root@45.78.31.162:./upload
|
||||
cd wallet-svr
|
@ -136,7 +136,13 @@ export class ApiServer {
|
||||
})
|
||||
this.server.setErrorHandler(function (error: FastifyError, request: FastifyRequest, reply: FastifyReply) {
|
||||
let statusCode = (error && error.statusCode) || 100
|
||||
logger.info(error)
|
||||
if (statusCode >= 500) {
|
||||
logger.error(error)
|
||||
} else if (statusCode >= 400) {
|
||||
logger.error(error)
|
||||
} else {
|
||||
logger.info(error?.message || error || 'unknown error')
|
||||
}
|
||||
reply.code(200).send({
|
||||
errcode: statusCode,
|
||||
errmsg: error ? error.message : 'unknown error',
|
||||
|
66
src/common/SyncLocker.ts
Normal file
66
src/common/SyncLocker.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { singleton } from 'zutils'
|
||||
import Client from 'ioredis'
|
||||
import Redlock, { Lock, ResourceLockedError } from 'redlock'
|
||||
import logger from 'logger/logger'
|
||||
|
||||
interface IRequest {
|
||||
method: string
|
||||
url: string
|
||||
user?: {
|
||||
id: string
|
||||
}
|
||||
lock?: Lock
|
||||
}
|
||||
|
||||
const redisA = new Client(process.env.REDIS)
|
||||
const redlock = new Redlock(
|
||||
// You should have one client for each independent redis node
|
||||
// or cluster.
|
||||
[redisA],
|
||||
{
|
||||
// The expected clock drift; for more details see:
|
||||
// http://redis.io/topics/distlock
|
||||
driftFactor: 0.01, // multiplied by lock ttl to determine drift time
|
||||
|
||||
// The max number of times Redlock will attempt to lock a resource
|
||||
// before erroring.
|
||||
retryCount: 0,
|
||||
|
||||
// the time in ms between attempts
|
||||
retryDelay: 200, // time in ms
|
||||
|
||||
// the max time in ms randomly added to retries
|
||||
// to improve performance under high contention
|
||||
// see https://www.awsarchitectureblog.com/2015/03/backoff.html
|
||||
retryJitter: 200, // time in ms
|
||||
|
||||
// The minimum remaining time on a lock before an extension is automatically
|
||||
// attempted with the `using` API.
|
||||
automaticExtensionThreshold: 500, // time in ms
|
||||
},
|
||||
)
|
||||
|
||||
redlock.on('error', error => {
|
||||
// Ignore cases where a resource is explicitly marked as locked on a client.
|
||||
if (error instanceof ResourceLockedError) {
|
||||
return
|
||||
}
|
||||
// Log all other errors.
|
||||
logger.error(error)
|
||||
})
|
||||
|
||||
@singleton
|
||||
export class SyncLocker {
|
||||
public async unlock(req: IRequest) {
|
||||
if (req.lock) {
|
||||
await req.lock.release()
|
||||
}
|
||||
}
|
||||
|
||||
public async checkLock(req: IRequest, key?: string, lockTime: number = 60000) {
|
||||
key = key || `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||
let lock = await redlock.acquire([key], lockTime)
|
||||
req.lock = lock
|
||||
return true
|
||||
}
|
||||
}
|
@ -13,8 +13,14 @@ import {
|
||||
DEFAULT_VERIFY_MAIL_SUBJECT,
|
||||
EmailSvr,
|
||||
} from 'service/email.svr'
|
||||
import { uuid } from 'zutils/utils/security.util'
|
||||
import { sha1, uuid } from 'zutils/utils/security.util'
|
||||
import { BaseController, role, ROLE_ANON, router, ZError } from 'zutils'
|
||||
import { SyncLocker } from 'common/SyncLocker'
|
||||
|
||||
export const isEmail = (email: string) => {
|
||||
const reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/
|
||||
return reg.test(email)
|
||||
}
|
||||
|
||||
class MailController extends BaseController {
|
||||
/**
|
||||
@ -131,7 +137,15 @@ class MailController extends BaseController {
|
||||
if (!email || !type) {
|
||||
throw new ZError(10, 'params mismatch')
|
||||
}
|
||||
if (!isEmail(email)) {
|
||||
throw new ZError(12, 'email error')
|
||||
}
|
||||
type = parseInt(type)
|
||||
if (type !== CodeType.REGIST && type !== CodeType.RESET && type !== CodeType.VERIFY && type !== CodeType.LOGIN) {
|
||||
throw new ZError(13, 'type error')
|
||||
}
|
||||
const lockKey = sha1(`${email}_${type}`)
|
||||
await new SyncLocker().checkLock(req, lockKey, 55000)
|
||||
if (type === CodeType.REGIST) {
|
||||
let account = await Account.findByEmail(email)
|
||||
if (account) {
|
||||
|
@ -29,7 +29,7 @@ export class NetClient {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}
|
||||
Object.assign(defaultCfg, data)
|
||||
console.log(defaultCfg)
|
||||
// console.log(defaultCfg)
|
||||
const res = await axios(defaultCfg)
|
||||
return res.data
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ export interface IMailData {
|
||||
}
|
||||
|
||||
const DEFAULT_MSG_DATA: IMailData = {
|
||||
from: 'CEBG <noreply@cebg.games>',
|
||||
from: 'Counter Fire <noreply@cebg.games>',
|
||||
to: '',
|
||||
subject: 'Please verify your email address',
|
||||
}
|
||||
|
52
yarn.lock
52
yarn.lock
@ -493,6 +493,11 @@
|
||||
resolved "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
|
||||
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
|
||||
|
||||
"@ioredis/commands@^1.1.1":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11"
|
||||
integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz"
|
||||
@ -1467,6 +1472,11 @@ clone-response@^1.0.2:
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
cluster-key-slot@^1.1.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
|
||||
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz"
|
||||
@ -2866,6 +2876,21 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
|
||||
resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ioredis@^5.4.1:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.4.1.tgz#1c56b70b759f01465913887375ed809134296f40"
|
||||
integrity sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==
|
||||
dependencies:
|
||||
"@ioredis/commands" "^1.1.1"
|
||||
cluster-key-slot "^1.1.0"
|
||||
debug "^4.3.4"
|
||||
denque "^2.1.0"
|
||||
lodash.defaults "^4.2.0"
|
||||
lodash.isarguments "^3.1.0"
|
||||
redis-errors "^1.2.0"
|
||||
redis-parser "^3.0.0"
|
||||
standard-as-callback "^2.1.0"
|
||||
|
||||
ip@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz"
|
||||
@ -3184,11 +3209,21 @@ lodash.clonedeep@^4.5.0:
|
||||
resolved "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
|
||||
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
|
||||
|
||||
lodash.defaults@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||
integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==
|
||||
|
||||
lodash.includes@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmmirror.com/lodash.includes/-/lodash.includes-4.3.0.tgz"
|
||||
integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==
|
||||
|
||||
lodash.isarguments@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
|
||||
integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==
|
||||
|
||||
lodash.isboolean@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.npmmirror.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz"
|
||||
@ -3580,6 +3615,11 @@ next-tick@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
|
||||
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
|
||||
|
||||
node-abort-controller@^3.0.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548"
|
||||
integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==
|
||||
|
||||
node-addon-api@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
|
||||
@ -4015,6 +4055,13 @@ redis@^3.1.2:
|
||||
redis-errors "^1.2.0"
|
||||
redis-parser "^3.0.0"
|
||||
|
||||
redlock@^5.0.0-beta.2:
|
||||
version "5.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/redlock/-/redlock-5.0.0-beta.2.tgz#a629c07e07d001c0fdd9f2efa614144c4416fe44"
|
||||
integrity sha512-2RDWXg5jgRptDrB1w9O/JgSZC0j7y4SlaXnor93H/UJm/QyDiFgBKNtrh0TI6oCXqYSaSoXxFh6Sd3VtYfhRXw==
|
||||
dependencies:
|
||||
node-abort-controller "^3.0.1"
|
||||
|
||||
reflect-metadata@^0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.npmmirror.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz"
|
||||
@ -4395,6 +4442,11 @@ sshpk@^1.7.0:
|
||||
safer-buffer "^2.0.2"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
standard-as-callback@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
|
||||
integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==
|
||||
|
||||
statuses@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
|
Loading…
x
Reference in New Issue
Block a user