add /mute chat command
fix eslint no-import error for jsons that don't get packed by webpack (i am sure there must be a better way to do that, but i am too lazy right now)
This commit is contained in:
parent
cd7c373277
commit
5cc626b8a0
|
@ -24,6 +24,7 @@ import {
|
|||
createPngBackup,
|
||||
incrementialBackupRedis,
|
||||
} from './core/tilesBackup';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
|
||||
/*
|
||||
|
|
114
src/core/ChatProvider.js
Normal file
114
src/core/ChatProvider.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* @flow */
|
||||
|
||||
|
||||
import logger from '../core/logger';
|
||||
import redis from '../data/redis';
|
||||
import User from '../data/models/User';
|
||||
import webSockets from '../socket/websockets';
|
||||
|
||||
|
||||
class ChatProvider {
|
||||
/*
|
||||
* TODO:
|
||||
* history really be saved in redis
|
||||
*/
|
||||
history: Array;
|
||||
|
||||
constructor() {
|
||||
this.history = [];
|
||||
}
|
||||
|
||||
addMessage(name, message) {
|
||||
if (this.history.length > 20) {
|
||||
this.history.shift();
|
||||
}
|
||||
this.history.push([name, message]);
|
||||
}
|
||||
|
||||
async sendMessage(user, message) {
|
||||
if (message.length > 300) {
|
||||
// eslint-disable-next-line max-len
|
||||
return 'You can\'t send a message this long :(';
|
||||
}
|
||||
const name = (user.regUser) ? user.regUser.name : null;
|
||||
if (!name) {
|
||||
// eslint-disable-next-line max-len
|
||||
return 'Couldn\'t send your message, pls log out and back in again.';
|
||||
}
|
||||
|
||||
if (user.isAdmin() && message.charAt(0) === '/') {
|
||||
// admin commands
|
||||
const cmd = message.split(' ', 3);
|
||||
if (cmd[0] === '/mute') {
|
||||
return ChatProvider.mute(cmd[1], cmd[2]);
|
||||
} if (cmd[0] === '/unmute') {
|
||||
return ChatProvider.unmute(cmd[1]);
|
||||
}
|
||||
}
|
||||
|
||||
const muted = await ChatProvider.checkIfMuted(user);
|
||||
if (muted === -1) {
|
||||
return 'You are permanently muted, join our discord to apppeal the mute';
|
||||
}
|
||||
if (muted > 0) {
|
||||
if (muted > 120) {
|
||||
const timeMin = Math.round(muted / 60);
|
||||
return `You are muted for another ${timeMin} minutes`;
|
||||
}
|
||||
return `You are muted for another ${muted} seconds`;
|
||||
}
|
||||
this.addMessage(name, message);
|
||||
webSockets.broadcastChatMessage(name, message);
|
||||
return null;
|
||||
}
|
||||
|
||||
broadcastChatMessage(name, message, sendapi: boolean = true) {
|
||||
this.addMessage(name, message);
|
||||
webSockets.broadcastChatMessage(name, message, sendapi);
|
||||
}
|
||||
|
||||
static async checkIfMuted(user) {
|
||||
const key = `mute:${user.id}`;
|
||||
const ttl: number = await redis.ttlAsync(key);
|
||||
return ttl;
|
||||
}
|
||||
|
||||
static async mute(name, timeMin) {
|
||||
const id = await User.name2Id(name);
|
||||
if (!id) {
|
||||
return `Couldn't find user ${name}`;
|
||||
}
|
||||
const key = `mute:${id}`;
|
||||
if (timeMin) {
|
||||
const ttl = timeMin * 60;
|
||||
await redis.setAsync(key, '', 'EX', ttl);
|
||||
webSockets.broadcastChatMessage('info',
|
||||
`${name} has been muted for ${timeMin}min`);
|
||||
} else {
|
||||
await redis.setAsync(key, '');
|
||||
webSockets.broadcastChatMessage('info',
|
||||
`${name} has been muted forever`);
|
||||
}
|
||||
logger.info(`Muted user ${id}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
static async unmute(name) {
|
||||
const id = await User.name2Id(name);
|
||||
if (!id) {
|
||||
return `Couldn't find user ${name}`;
|
||||
}
|
||||
const key = `mute:${id}`;
|
||||
const delKeys = await redis.delAsync(key);
|
||||
if (delKeys !== 1) {
|
||||
return `User ${name} is not muted`;
|
||||
}
|
||||
webSockets.broadcastChatMessage('info',
|
||||
`${name} has been unmuted`);
|
||||
logger.info(`Unmuted user ${id}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const chatProvider = new ChatProvider();
|
||||
export default chatProvider;
|
|
@ -8,6 +8,7 @@ import RedisCanvas from '../data/models/RedisCanvas';
|
|||
import logger from './logger';
|
||||
import { getChunkOfPixel } from './utils';
|
||||
import { TILE_SIZE } from './constants';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import Palette from './Palette';
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import { getChunkOfPixel, getOffsetOfPixel } from './utils';
|
|||
import webSockets from '../socket/websockets';
|
||||
import logger from './logger';
|
||||
import RedisCanvas from '../data/models/RedisCanvas';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
|
||||
import { THREE_CANVAS_HEIGHT } from './constants';
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* @flow
|
||||
*/
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ passport.deserializeUser((req, id, done) => {
|
|||
RegUser.findOne({ where: { id } }).then((reguser) => {
|
||||
if (reguser) {
|
||||
user.regUser = reguser;
|
||||
user.id = id;
|
||||
} else {
|
||||
user.id = null;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import fs from 'fs';
|
|||
|
||||
import type { Cell } from './Cell';
|
||||
import logger from './logger';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import Palette from './Palette';
|
||||
import RedisCanvas from '../data/models/RedisCanvas';
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
THREE_TILE_SIZE,
|
||||
THREE_CANVAS_HEIGHT,
|
||||
} from '../../core/constants';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import logger from '../../core/logger';
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
import Sequelize from 'sequelize';
|
||||
import redis from '../redis';
|
||||
import { randomDice } from '../../utils/random';
|
||||
import logger from '../../core/logger';
|
||||
|
||||
import Model from '../sequelize';
|
||||
|
@ -32,8 +31,23 @@ class User {
|
|||
this.regUser = null;
|
||||
}
|
||||
|
||||
static async name2Id(name: string) {
|
||||
try {
|
||||
const userq = await Model.query('SELECT id FROM Users WHERE name = $1',
|
||||
{
|
||||
bind: [name],
|
||||
type: Sequelize.QueryTypes.SELECT,
|
||||
raw: true,
|
||||
plain: true,
|
||||
});
|
||||
return userq.id;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async setWait(coolDown: number, canvasId: number): Promise<boolean> {
|
||||
if (coolDown == 0) return false;
|
||||
if (!coolDown) return false;
|
||||
this.wait = Date.now() + coolDown;
|
||||
// PX is milliseconds expire
|
||||
await redis.setAsync(`cd:${canvasId}:ip:${this.ip}`, '', 'PX', coolDown);
|
||||
|
@ -46,7 +60,9 @@ class User {
|
|||
async getWait(canvasId: number): Promise<?number> {
|
||||
let ttl: number = await redis.pttlAsync(`cd:${canvasId}:ip:${this.ip}`);
|
||||
if (this.id != null && ttl < 0) {
|
||||
const ttlid: number = await redis.pttlAsync(`cd:${canvasId}:id:${this.id}`);
|
||||
const ttlid: number = await redis.pttlAsync(
|
||||
`cd:${canvasId}:id:${this.id}`,
|
||||
);
|
||||
ttl = Math.max(ttl, ttlid);
|
||||
}
|
||||
logger.debug('ererer', ttl, typeof ttl);
|
||||
|
@ -82,10 +98,15 @@ class User {
|
|||
return this.regUser.totalPixels;
|
||||
}
|
||||
try {
|
||||
const userq = await Model.query('SELECT totalPixels FROM Users WHERE id = $1',
|
||||
const userq = await Model.query(
|
||||
'SELECT totalPixels FROM Users WHERE id = $1',
|
||||
{
|
||||
bind: [id], type: Sequelize.QueryTypes.SELECT, raw: true, plain: true,
|
||||
});
|
||||
bind: [id],
|
||||
type: Sequelize.QueryTypes.SELECT,
|
||||
raw: true,
|
||||
plain: true,
|
||||
},
|
||||
);
|
||||
return userq.totalPixels;
|
||||
} catch (err) {
|
||||
return 0;
|
||||
|
@ -95,7 +116,9 @@ class User {
|
|||
async updateLogInTimestamp(): Promise<boolean> {
|
||||
if (!this.regUser) return false;
|
||||
try {
|
||||
await this.regUser.update({ lastLogIn: Sequelize.literal('CURRENT_TIMESTAMP') });
|
||||
await this.regUser.update({
|
||||
lastLogIn: Sequelize.literal('CURRENT_TIMESTAMP'),
|
||||
});
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import logger from '../core/logger';
|
|||
import { Blacklist, Whitelist } from '../data/models';
|
||||
|
||||
import { MINUTE } from '../core/constants';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import { imageABGR2Canvas } from '../core/Image';
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import webSockets from '../../socket/websockets';
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import Minecraft from '../core/minecraft';
|
|||
import { drawUnsafe, setPixel } from '../core/draw';
|
||||
import logger from '../core/logger';
|
||||
import { APISOCKET_KEY } from '../core/config';
|
||||
import chatProvider from '../core/ChatProvider';
|
||||
|
||||
function heartbeat() {
|
||||
this.isAlive = true;
|
||||
|
@ -182,7 +183,7 @@ class APISocketServer extends WebSocketEvents {
|
|||
if (clr < 0 || clr > 32) return;
|
||||
// be aware that user null has no cd
|
||||
if (!minecraftid && !ip) {
|
||||
setPixel("0", clr, x, y);
|
||||
setPixel('0', clr, x, y);
|
||||
ws.send(JSON.stringify(['retpxl', null, null, true, 0, 0]));
|
||||
return;
|
||||
}
|
||||
|
@ -190,7 +191,7 @@ class APISocketServer extends WebSocketEvents {
|
|||
user.ip = ip;
|
||||
const {
|
||||
error, success, waitSeconds, coolDownSeconds,
|
||||
} = await drawUnsafe(user, "0", clr, x, y, null);
|
||||
} = await drawUnsafe(user, '0', clr, x, y, null);
|
||||
ws.send(JSON.stringify([
|
||||
'retpxl',
|
||||
(minecraftid) || ip,
|
||||
|
@ -237,13 +238,13 @@ class APISocketServer extends WebSocketEvents {
|
|||
const chatname = (user.id)
|
||||
? `[MC] ${user.regUser.name}`
|
||||
: `[MC] ${minecraftname}`;
|
||||
webSockets.broadcastChatMessage(chatname, msg, false);
|
||||
chatProvider.broadcastChatMessage(chatname, msg, false);
|
||||
this.broadcastChatMessage(chatname, msg, true, ws);
|
||||
return;
|
||||
}
|
||||
if (command == 'chat') {
|
||||
const [name, msg] = packet;
|
||||
webSockets.broadcastChatMessage(name, msg, false);
|
||||
chatProvider.broadcastChatMessage(name, msg, false);
|
||||
this.broadcastChatMessage(name, msg, true, ws);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* save the chat history
|
||||
* TODO:
|
||||
* This should really be saved in redis
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
class ChatHistory {
|
||||
OP_CODE = 0xA5;
|
||||
history: Array;
|
||||
|
||||
constructor() {
|
||||
this.history = [];
|
||||
}
|
||||
|
||||
addMessage(name, message) {
|
||||
if (this.history.length > 20) {
|
||||
this.history.shift();
|
||||
}
|
||||
this.history.push([name, message]);
|
||||
}
|
||||
}
|
||||
|
||||
const chatHistory = new ChatHistory();
|
||||
export default chatHistory;
|
|
@ -17,7 +17,7 @@ import RequestChatHistory from './packets/RequestChatHistory';
|
|||
import CoolDownPacket from './packets/CoolDownPacket';
|
||||
import ChangedMe from './packets/ChangedMe';
|
||||
|
||||
import ChatHistory from './ChatHistory';
|
||||
import chatProvider from '../core/ChatProvider';
|
||||
import authenticateClient from './verifyClient';
|
||||
import WebSocketEvents from './WebSocketEvents';
|
||||
import webSockets from './websockets';
|
||||
|
@ -217,17 +217,17 @@ class SocketServer extends WebSocketEvents {
|
|||
webSockets.broadcastOnlineCounter(online);
|
||||
}
|
||||
|
||||
static onTextMessage(message, ws) {
|
||||
static async onTextMessage(message, ws) {
|
||||
if (ws.name && message) {
|
||||
const waitLeft = ws.rateLimiter.tick();
|
||||
if (waitLeft) {
|
||||
// eslint-disable-next-line max-len
|
||||
ws.send(JSON.stringify(['info', `You are sending messages too fast, you have to wait ${Math.floor(waitLeft / 1000)}s :(`]));
|
||||
} else if (message.length > 300) {
|
||||
// eslint-disable-next-line max-len
|
||||
ws.send(JSON.stringify(['info', 'You can\'t send a message this long :(']));
|
||||
} else {
|
||||
webSockets.broadcastChatMessage(ws.name, message);
|
||||
return;
|
||||
}
|
||||
const errorMsg = await chatProvider.sendMessage(ws.user, message);
|
||||
if (errorMsg) {
|
||||
ws.send(JSON.stringify(['info', errorMsg]));
|
||||
}
|
||||
} else {
|
||||
logger.info('Got empty message or message from unidentified ws');
|
||||
|
@ -278,7 +278,7 @@ class SocketServer extends WebSocketEvents {
|
|||
break;
|
||||
}
|
||||
case RequestChatHistory.OP_CODE: {
|
||||
const history = JSON.stringify(ChatHistory.history);
|
||||
const history = JSON.stringify(chatProvider.history);
|
||||
ws.send(history);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import logger from '../core/logger';
|
||||
import ChatHistory from './ChatHistory';
|
||||
import OnlineCounter from './packets/OnlineCounter';
|
||||
import PixelUpdate from './packets/PixelUpdate';
|
||||
|
||||
|
@ -67,7 +66,6 @@ class WebSockets {
|
|||
sendapi: boolean = true,
|
||||
) {
|
||||
logger.info(`Received chat message ${message} from ${name}`);
|
||||
ChatHistory.addMessage(name, message);
|
||||
this.listeners.forEach(
|
||||
(listener) => listener.broadcastChatMessage(name, message, sendapi),
|
||||
);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import isoFetch from 'isomorphic-fetch';
|
||||
import HttpProxyAgent from 'http-proxy-agent';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import proxylist from './proxies.json';
|
||||
|
||||
import logger from '../core/logger';
|
||||
|
|
Loading…
Reference in New Issue
Block a user