return cross-shard requests only to shard that requested

make api/banme POST request
This commit is contained in:
HF 2022-09-22 16:25:03 +02:00
parent 279819eac0
commit 2707fb6123
6 changed files with 76 additions and 31 deletions

View File

@ -56,7 +56,7 @@ const RegUser = sequelize.define('User', {
},
discordid: {
type: DataTypes.CHAR(18),
type: DataTypes.CHAR(20),
allowNull: true,
},

View File

@ -7,11 +7,21 @@ import { banIP } from '../../data/sql/Ban';
import { getIPv6Subnet, getIPFromRequest } from '../../utils/ip';
async function banme(req, res) {
const { code } = req.query;
const { code } = req.body;
const ip = getIPFromRequest(req);
// eslint-disable-next-line max-len
logger.info(`AUTOBAN ${code} - ${ip} of user ${req.user.id} with ua "${req.headers['user-agent']}"`);
let reason = 'AUTOBAN';
if (code === '1') {
let expires = 0;
if (code === 1) {
reason = 'Userscript Bot';
} else if (code === '2') {
expires = Date.now() + 1000 * 3600 * 24 * 7;
/*
* ignore it for now to collect data manually
*
} else if (code === 2) {
const ua = req.headers['user-agent'];
if (ua && (ua.includes('Android') || ua.includes('iPhone'))) {
res.json({
@ -20,14 +30,18 @@ async function banme(req, res) {
return;
}
reason = 'Captcha Solving Script';
expires = Date.now() + 1000 * 3600 * 24 * 3;
*/
} else {
res.json({
status: 'nope',
});
return;
}
const ip = getIPFromRequest(req);
// eslint-disable-next-line max-len
logger.info(`AUTOBAN ${code}${ip} of user ${req.user.id} with ua "${req.headers['user-agent']}"`);
await banIP(
getIPv6Subnet(ip),
reason,
0,
expires,
1,
);
res.json({

View File

@ -98,7 +98,7 @@ router.get('/chathistory', chatHistory);
router.get('/me', me);
router.get('/banme', banme);
router.post('/banme', banme);
router.use('/auth', auth);

View File

@ -35,6 +35,17 @@ class MessageBroker extends SocketEvents {
super();
this.isCluster = true;
this.thisShard = SHARD_NAME;
/*
* currently running cross-shard requests,
* are tracked in order to only send them to receiving
* shard
* [{
* id: request id,
* shard: requesting shard name,
* ts: timestamp of request,
* },...]
*/
this.csReq = [];
/*
* all other shards
*/
@ -95,22 +106,16 @@ class MessageBroker extends SocketEvents {
const key = message.slice(message.indexOf(':') + 1, comma);
console.log('CLUSTER: Broadcast', key);
const val = JSON.parse(message.slice(comma + 1));
/*
if (key.startsWith('req:')) {
try {
const shard = message.slice(0, message.indexOf(':'));
const chan = val.shift();
const ret = await super.req(key.slice(4), ...val);
this.publisher.publish(
`${LISTEN_PREFIX}:${shard}`,
`res:${chan},${JSON.stringify([ret])}`,
);
} catch {
// nothing
}
return;
// cross-shard requests
const shard = message.slice(0, message.indexOf(':'));
const id = val[0];
this.csReq.push({
id,
shard,
ts: Date.now(),
});
}
*/
super.emit(key, ...val);
return;
}
@ -145,6 +150,7 @@ class MessageBroker extends SocketEvents {
try {
const comma = message.indexOf(',');
const key = message.slice(0, comma);
console.log(`CLUSTER shard listener got ${key}`);
const val = JSON.parse(message.slice(comma + 1));
super.emit(key, ...val);
} catch (err) {
@ -188,13 +194,14 @@ class MessageBroker extends SocketEvents {
const callback = (retn) => {
amountOtherShards -= 1;
ret = combineObjects(ret, retn);
// eslint-disable-next-line
console.log(`CLUSTER got res:${type} from shard, ${amountOtherShards} still left`);
if (amountOtherShards <= 0) {
console.log(`CLUSTER res:${type} finished`);
console.log(`CLUSTER res:${chan}:${type} finished`);
this.off(chankey, callback);
clearTimeout(id);
resolve(ret);
} else {
// eslint-disable-next-line
console.log(`CLUSTER got res:${chan}:${type} from shard, ${amountOtherShards} still left`);
}
};
id = setTimeout(() => {
@ -202,7 +209,7 @@ class MessageBroker extends SocketEvents {
if (ret) {
resolve(ret);
} else {
reject(new Error(`Timeout on req ${type}`));
reject(new Error(`CLUSTER Timeout on wait for res:${chan}:${type}`));
}
}, 45000);
this.on(chankey, callback);
@ -210,6 +217,22 @@ class MessageBroker extends SocketEvents {
});
}
res(chan, ret) {
// only response to requesting shard
const csre = this.csReq.find((r) => r.id === chan);
// eslint-disable-next-line
console.log(`CLUSTER send res:${chan} to shard ${csre && csre.shard}`);
if (csre) {
this.publisher.publish(
`${LISTEN_PREFIX}:${csre.shard}`,
`res:${chan},${JSON.stringify([ret])}`,
);
this.csReq = this.csReq.filter((r) => r.id !== chan);
} else {
super.emit(`res:${chan}`, ret);
}
}
updateShardOnlineCounter(shard, cnt) {
const shardCounter = this.shardOnlineCounters.find(
(c) => c[0] === shard,
@ -347,7 +370,7 @@ class MessageBroker extends SocketEvents {
checkHealth() {
// remove disconnected shards
const threshold = Date.now() - 30000;
let threshold = Date.now() - 30000;
const { shards } = this;
Object.keys(shards).forEach((shard) => {
if (shards[shard] < threshold) {
@ -364,6 +387,9 @@ class MessageBroker extends SocketEvents {
});
// send keep alive to others
this.publisher.publish(BROADCAST_CHAN, this.thisShard);
// clean up dead shard requests
threshold -= 30000;
this.csReq = this.csReq.filter((r) => r.ts > threshold);
}
}

View File

@ -73,10 +73,14 @@ class SocketEvents extends EventEmitter {
});
}
res(chan, ret) {
this.emit(`res:${chan}`, ret);
}
onReq(type, cb) {
this.on(`req:${type}`, async (chan, ...args) => {
const ret = await cb(...args);
this.emit(`res:${chan}`, ret);
this.res(chan, ret);
});
}

View File

@ -348,7 +348,8 @@ export function requestIID() {
}
export function requestBanMe(code) {
return makeAPIGETRequest(
`/api/banme?code=${code}`,
return makeAPIPOSTRequest(
'/api/banme',
{ code },
);
}