rename allowPlace to cooldown and batch incrementing pixelcounts into a
single transaction
This commit is contained in:
parent
100bdb17b5
commit
1fe9b70b9b
|
@ -7,7 +7,7 @@ import {
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import logger, { pixelLogger } from './logger';
|
import logger, { pixelLogger } from './logger';
|
||||||
import RedisCanvas from '../data/redis/RedisCanvas';
|
import RedisCanvas from '../data/redis/RedisCanvas';
|
||||||
import allowPlace from '../data/redis/allowPlace';
|
import allowPlace from '../data/redis/cooldown';
|
||||||
import {
|
import {
|
||||||
setPixelByOffset,
|
setPixelByOffset,
|
||||||
setPixelByCoords,
|
setPixelByCoords,
|
||||||
|
@ -70,7 +70,7 @@ export async function drawByOffsets(
|
||||||
let pxlCnt = 0;
|
let pxlCnt = 0;
|
||||||
let rankedPxlCnt = 0;
|
let rankedPxlCnt = 0;
|
||||||
let needProxycheck = 0;
|
let needProxycheck = 0;
|
||||||
const { ip } = user;
|
const { ipSub: ip } = user;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
@ -220,7 +220,7 @@ export async function drawByOffsets(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rankedPxlCnt) {
|
if (rankedPxlCnt) {
|
||||||
await user.incrementPixelcount(rankedPxlCnt);
|
user.incrementPixelcount(rankedPxlCnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retCode !== 13) {
|
if (retCode !== 13) {
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
* */
|
* */
|
||||||
|
|
||||||
import { QueryTypes, Utils } from 'sequelize';
|
import { QueryTypes, Utils } from 'sequelize';
|
||||||
import redis from './redis/client';
|
|
||||||
import logger from '../core/logger';
|
|
||||||
|
|
||||||
import sequelize from './sql/sequelize';
|
import sequelize from './sql/sequelize';
|
||||||
import { RegUser, Channel, UserBlock } from './sql';
|
import { RegUser, Channel, UserBlock } from './sql';
|
||||||
|
import { incrementPixelcount } from './sql/RegUser';
|
||||||
|
import { setCoolDown, getCoolDown } from './redis/cooldown';
|
||||||
import { getIPv6Subnet } from '../utils/ip';
|
import { getIPv6Subnet } from '../utils/ip';
|
||||||
import { ADMIN_IDS } from '../core/config';
|
import { ADMIN_IDS } from '../core/config';
|
||||||
|
|
||||||
|
@ -171,45 +171,16 @@ class User {
|
||||||
return (this.regUser) ? this.regUser.name : null;
|
return (this.regUser) ? this.regUser.name : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setWait(wait, canvasId) {
|
setWait(wait, canvasId) {
|
||||||
// PX is milliseconds expire
|
return setCoolDown(this.ipSub, this.id, canvasId, wait);
|
||||||
await redis.set(`cd:${canvasId}:ip:${this.ipSub}`, '', {
|
|
||||||
PX: wait,
|
|
||||||
});
|
|
||||||
if (this.id) {
|
|
||||||
await redis.set(`cd:${canvasId}:id:${this.id}`, '', {
|
|
||||||
PX: wait,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getWait(canvasId) {
|
getWait(canvasId) {
|
||||||
let ttl = await redis.pTTL(`cd:${canvasId}:ip:${this.ipSub}`);
|
return getCoolDown(this.ipSub, this.id, canvasId);
|
||||||
if (this.id) {
|
|
||||||
const ttlid = await redis.pTTL(
|
|
||||||
`cd:${canvasId}:id:${this.id}`,
|
|
||||||
);
|
|
||||||
ttl = Math.max(ttl, ttlid);
|
|
||||||
}
|
|
||||||
logger.debug('ererer', ttl, typeof ttl);
|
|
||||||
|
|
||||||
const wait = ttl < 0 ? 0 : ttl;
|
|
||||||
return wait;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async incrementPixelcount(amount = 1) {
|
incrementPixelcount(amount = 1) {
|
||||||
const { id } = this;
|
incrementPixelcount(this.regUser, amount);
|
||||||
if (!id) return false;
|
|
||||||
try {
|
|
||||||
await this.regUser.increment(
|
|
||||||
['totalPixels', 'dailyTotalPixels'],
|
|
||||||
{ by: amount },
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTotalPixels() {
|
async getTotalPixels() {
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*
|
|
||||||
* redis script for user pixel placement
|
|
||||||
* this does not set any pixels itself, see lua/placePixel.lua
|
|
||||||
*/
|
|
||||||
import client from './client';
|
|
||||||
import { getIPv6Subnet } from '../../utils/ip';
|
|
||||||
import { PREFIX as CAPTCHA_PREFIX } from './captcha';
|
|
||||||
import { PREFIX as ALLOWED_PREFIX } from './isAllowedCache';
|
|
||||||
import { CAPTCHA_TIME } from '../../core/config';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* gets pixels and chunk coords and checks if
|
|
||||||
* and how many a user can set and sets the cooldown accordingly
|
|
||||||
* @param ip ip of request
|
|
||||||
* @param id userId
|
|
||||||
* @param clrIgnore, bcd, pcd, cds incormations about canvas
|
|
||||||
* @param i, j chunk coordinates
|
|
||||||
* @param pxls Array with offsets of pixels
|
|
||||||
* @return see lua/placePixel.lua
|
|
||||||
*/
|
|
||||||
export default function allowPlace(
|
|
||||||
ip,
|
|
||||||
id,
|
|
||||||
canvasId,
|
|
||||||
i, j,
|
|
||||||
clrIgnore,
|
|
||||||
bcd,
|
|
||||||
pcd,
|
|
||||||
cds,
|
|
||||||
pxls,
|
|
||||||
) {
|
|
||||||
const ipn = getIPv6Subnet(ip);
|
|
||||||
const isalKey = `${ALLOWED_PREFIX}:${ipn}`;
|
|
||||||
const captKey = (CAPTCHA_TIME >= 0) ? `${CAPTCHA_PREFIX}:${ipn}` : 'nope';
|
|
||||||
const ipCdKey = `cd:${canvasId}:ip:${ipn}`;
|
|
||||||
const idCdKey = (id) ? `cd:${canvasId}:id:${id}` : 'nope';
|
|
||||||
const chunkKey = `ch:${canvasId}:${i}:${j}`;
|
|
||||||
return client.placePxl(
|
|
||||||
isalKey, captKey, ipCdKey, idCdKey, chunkKey,
|
|
||||||
clrIgnore, bcd, pcd, cds,
|
|
||||||
...pxls,
|
|
||||||
);
|
|
||||||
}
|
|
90
src/data/redis/cooldown.js
Normal file
90
src/data/redis/cooldown.js
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* redis script for cooldown calculation
|
||||||
|
* this does not set any pixels itself, see lua/placePixel.lua
|
||||||
|
*/
|
||||||
|
import client from './client';
|
||||||
|
import { PREFIX as CAPTCHA_PREFIX } from './captcha';
|
||||||
|
import { PREFIX as ALLOWED_PREFIX } from './isAllowedCache';
|
||||||
|
import { CAPTCHA_TIME } from '../../core/config';
|
||||||
|
|
||||||
|
const PREFIX = 'cd';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* checks how many of the given pixels can be set,
|
||||||
|
* sets user cooldown and returns the number of pixels to set
|
||||||
|
* @param ip ip of request
|
||||||
|
* @param id userId
|
||||||
|
* @param clrIgnore, bcd, pcd, cds incormations about canvas
|
||||||
|
* @param i, j chunk coordinates
|
||||||
|
* @param pxls Array with offsets of pixels
|
||||||
|
* @return see lua/placePixel.lua
|
||||||
|
*/
|
||||||
|
export default function allowPlace(
|
||||||
|
ip,
|
||||||
|
id,
|
||||||
|
canvasId,
|
||||||
|
i, j,
|
||||||
|
clrIgnore,
|
||||||
|
bcd,
|
||||||
|
pcd,
|
||||||
|
cds,
|
||||||
|
pxls,
|
||||||
|
) {
|
||||||
|
const isalKey = `${ALLOWED_PREFIX}:${ip}`;
|
||||||
|
const captKey = (CAPTCHA_TIME >= 0) ? `${CAPTCHA_PREFIX}:${ip}` : 'nope';
|
||||||
|
const ipCdKey = `${PREFIX}:${canvasId}:ip:${ip}`;
|
||||||
|
const idCdKey = (id) ? `${PREFIX}:${canvasId}:id:${id}` : 'nope';
|
||||||
|
const chunkKey = `ch:${canvasId}:${i}:${j}`;
|
||||||
|
return client.placePxl(
|
||||||
|
isalKey, captKey, ipCdKey, idCdKey, chunkKey,
|
||||||
|
clrIgnore, bcd, pcd, cds,
|
||||||
|
...pxls,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get cooldown of specific user
|
||||||
|
* @param ip ip of request
|
||||||
|
* @param id userId
|
||||||
|
* @param canvasId
|
||||||
|
* @return cooldown
|
||||||
|
*/
|
||||||
|
export async function getCoolDown(
|
||||||
|
ip,
|
||||||
|
id,
|
||||||
|
canvasId,
|
||||||
|
) {
|
||||||
|
let ttl = await client.pTTL(`${PREFIX}:${canvasId}:ip:${ip}`);
|
||||||
|
if (id) {
|
||||||
|
const ttlid = await client.pTTL(`${PREFIX}:${canvasId}:id:${id}`);
|
||||||
|
ttl = Math.max(ttl, ttlid);
|
||||||
|
}
|
||||||
|
const cooldown = ttl < 0 ? 0 : ttl;
|
||||||
|
return cooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set cooldown of specific user
|
||||||
|
* @param ip ip of request
|
||||||
|
* @param id userId
|
||||||
|
* @param canvasId
|
||||||
|
* @param cooldown (in ms)
|
||||||
|
* @return cooldown
|
||||||
|
*/
|
||||||
|
export async function setCoolDown(
|
||||||
|
ip,
|
||||||
|
id,
|
||||||
|
canvasId,
|
||||||
|
cooldown,
|
||||||
|
) {
|
||||||
|
// PX is milliseconds expire
|
||||||
|
await client.set(`${PREFIX}:${canvasId}:ip:${ip}`, '', {
|
||||||
|
PX: cooldown,
|
||||||
|
});
|
||||||
|
if (id) {
|
||||||
|
await client.set(`${PREFIX}:${canvasId}:id:${id}`, '', {
|
||||||
|
PX: cooldown,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -6,8 +6,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DataTypes, QueryTypes } from 'sequelize';
|
import { DataTypes, QueryTypes } from 'sequelize';
|
||||||
import sequelize from './sequelize';
|
|
||||||
|
|
||||||
|
import logger from '../../core/logger';
|
||||||
|
import sequelize from './sequelize';
|
||||||
import { generateHash } from '../../utils/hash';
|
import { generateHash } from '../../utils/hash';
|
||||||
|
|
||||||
|
|
||||||
|
@ -203,4 +204,42 @@ export async function getNamesToIds(ids) {
|
||||||
return idToNameMap;
|
return idToNameMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* increment user pixelcount in a batched transaction
|
||||||
|
*/
|
||||||
|
const incrementQueue = [];
|
||||||
|
let pushLoop = null;
|
||||||
|
const incrementLoop = async () => {
|
||||||
|
if (!incrementQueue.length) {
|
||||||
|
clearInterval(pushLoop);
|
||||||
|
pushLoop = null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
sequelize.transaction(async (t) => {
|
||||||
|
while (incrementQueue.length) {
|
||||||
|
const [model, amount] = incrementQueue.pop();
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await model.increment(
|
||||||
|
['totalPixels', 'dailyTotalPixels'],
|
||||||
|
{ by: amount, transaction: t },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(`Error on batched incrementing pixelcounts: ${err.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// TODO remove this after testing
|
||||||
|
setInterval(() => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('INCREMENTATION QUEUE SIZE', incrementQueue.length);
|
||||||
|
}, 300000);
|
||||||
|
export async function incrementPixelcount(model, amount) {
|
||||||
|
incrementQueue.push([model, amount]);
|
||||||
|
if (!pushLoop) {
|
||||||
|
pushLoop = setInterval(incrementLoop, 250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default RegUser;
|
export default RegUser;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user