Merge branch 'master' into production
This commit is contained in:
commit
50e3a95161
|
@ -189,12 +189,14 @@ export function receiveChatMessage(
|
||||||
name: string,
|
name: string,
|
||||||
text: string,
|
text: string,
|
||||||
country: string,
|
country: string,
|
||||||
|
channel: number,
|
||||||
): Action {
|
): Action {
|
||||||
return {
|
return {
|
||||||
type: 'RECEIVE_CHAT_MESSAGE',
|
type: 'RECEIVE_CHAT_MESSAGE',
|
||||||
name,
|
name,
|
||||||
text,
|
text,
|
||||||
country,
|
country,
|
||||||
|
channel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,6 +622,13 @@ export function showChatModal(): Action {
|
||||||
return showModal('CHAT');
|
return showModal('CHAT');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setChatChannel(channelId: number): Action {
|
||||||
|
return {
|
||||||
|
type: 'SET_CHAT_CHANNEL',
|
||||||
|
channelId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function hideModal(): Action {
|
export function hideModal(): Action {
|
||||||
return {
|
return {
|
||||||
type: 'HIDE_MODAL',
|
type: 'HIDE_MODAL',
|
||||||
|
|
|
@ -56,8 +56,11 @@ export type Action =
|
||||||
| { type: 'RECEIVE_CHAT_MESSAGE',
|
| { type: 'RECEIVE_CHAT_MESSAGE',
|
||||||
name: string,
|
name: string,
|
||||||
text: string,
|
text: string,
|
||||||
country: string }
|
country: string,
|
||||||
|
channel: number,
|
||||||
|
}
|
||||||
| { type: 'RECEIVE_CHAT_HISTORY', data: Array }
|
| { type: 'RECEIVE_CHAT_HISTORY', data: Array }
|
||||||
|
| { type: 'SET_CHAT_CHANNEL', channelId: number }
|
||||||
| { type: 'RECEIVE_ME',
|
| { type: 'RECEIVE_ME',
|
||||||
name: string,
|
name: string,
|
||||||
waitSeconds: number,
|
waitSeconds: number,
|
||||||
|
|
|
@ -43,8 +43,8 @@ function init() {
|
||||||
ProtocolClient.on('onlineCounter', ({ online }) => {
|
ProtocolClient.on('onlineCounter', ({ online }) => {
|
||||||
store.dispatch(receiveOnline(online));
|
store.dispatch(receiveOnline(online));
|
||||||
});
|
});
|
||||||
ProtocolClient.on('chatMessage', (name, text, country) => {
|
ProtocolClient.on('chatMessage', (name, text, country, channelId) => {
|
||||||
store.dispatch(receiveChatMessage(name, text, country));
|
store.dispatch(receiveChatMessage(name, text, country, channelId));
|
||||||
});
|
});
|
||||||
ProtocolClient.on('chatHistory', (data) => {
|
ProtocolClient.on('chatHistory', (data) => {
|
||||||
store.dispatch(receiveChatHistory(data));
|
store.dispatch(receiveChatHistory(data));
|
||||||
|
|
|
@ -12,27 +12,23 @@ import ChatInput from './ChatInput';
|
||||||
import { colorFromText, splitCoordsInString } from '../core/utils';
|
import { colorFromText, splitCoordsInString } from '../core/utils';
|
||||||
|
|
||||||
|
|
||||||
function onError() {
|
const Chat = ({ chatMessages, chatChannel }) => {
|
||||||
this.onerror = null;
|
|
||||||
this.src = './cf/xx.gif';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Chat = ({ chatMessages }) => {
|
|
||||||
const listRef = useRef();
|
const listRef = useRef();
|
||||||
const { stayScrolled } = useStayScrolled(listRef, {
|
const { stayScrolled } = useStayScrolled(listRef, {
|
||||||
initialScroll: Infinity,
|
initialScroll: Infinity,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const channelMessages = chatMessages[chatChannel];
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
stayScrolled();
|
stayScrolled();
|
||||||
}, [chatMessages.length]);
|
}, [channelMessages.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '100%' }}>
|
<div style={{ height: '100%' }}>
|
||||||
<ul className="chatarea" ref={listRef}>
|
<ul className="chatarea" ref={listRef}>
|
||||||
{
|
{
|
||||||
chatMessages.map((message) => (
|
channelMessages.map((message) => (
|
||||||
<p className="chatmsg">
|
<p className="chatmsg">
|
||||||
{(message[0] === 'info')
|
{(message[0] === 'info')
|
||||||
? <span style={{ color: '#cc0000' }}>{message[1]}</span>
|
? <span style={{ color: '#cc0000' }}>{message[1]}</span>
|
||||||
|
@ -42,7 +38,10 @@ const Chat = ({ chatMessages }) => {
|
||||||
alt=""
|
alt=""
|
||||||
title={`${message[2]}`}
|
title={`${message[2]}`}
|
||||||
src={`${window.assetserver}/cf/${message[2]}.gif`}
|
src={`${window.assetserver}/cf/${message[2]}.gif`}
|
||||||
onError={onError}
|
onError={(e) => {
|
||||||
|
e.target.onerror = null;
|
||||||
|
e.target.src = './cf/xx.gif';
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
|
@ -75,7 +74,8 @@ const Chat = ({ chatMessages }) => {
|
||||||
|
|
||||||
function mapStateToProps(state: State) {
|
function mapStateToProps(state: State) {
|
||||||
const { chatMessages } = state.user;
|
const { chatMessages } = state.user;
|
||||||
return { chatMessages };
|
const { chatChannel } = state.gui;
|
||||||
|
return { chatMessages, chatChannel };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps)(Chat);
|
export default connect(mapStateToProps)(Chat);
|
||||||
|
|
|
@ -10,7 +10,8 @@ import { connect } from 'react-redux';
|
||||||
import type { State } from '../reducers';
|
import type { State } from '../reducers';
|
||||||
import ProtocolClient from '../socket/ProtocolClient';
|
import ProtocolClient from '../socket/ProtocolClient';
|
||||||
|
|
||||||
import { showUserAreaModal } from '../actions';
|
import { showUserAreaModal, setChatChannel } from '../actions';
|
||||||
|
import { CHAT_CHANNELS } from '../core/constants';
|
||||||
|
|
||||||
class ChatInput extends React.Component {
|
class ChatInput extends React.Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -22,44 +23,80 @@ class ChatInput extends React.Component {
|
||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(e) {
|
handleSubmit(e, channelId) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const { message } = this.state;
|
const { message } = this.state;
|
||||||
if (!message) return;
|
if (!message) return;
|
||||||
// send message via websocket
|
// send message via websocket
|
||||||
ProtocolClient.sendMessage(message);
|
ProtocolClient.sendChatMessage(message, channelId);
|
||||||
this.setState({
|
this.setState({
|
||||||
message: '',
|
message: '',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.name) {
|
const {
|
||||||
|
name, chatChannel, open, setChannel,
|
||||||
|
} = this.props;
|
||||||
|
const {
|
||||||
|
message,
|
||||||
|
} = this.state;
|
||||||
|
const selectedChannel = CHAT_CHANNELS[chatChannel];
|
||||||
|
|
||||||
|
if (name) {
|
||||||
return (
|
return (
|
||||||
<div className="chatinput">
|
<div className="chatinput">
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form
|
||||||
|
onSubmit={(e) => { this.handleSubmit(e, chatChannel); }}
|
||||||
|
style={{ display: 'inline' }}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
style={{ maxWidth: '80%', width: '240px' }}
|
style={{ maxWidth: '58%', width: '240px' }}
|
||||||
value={this.state.message}
|
value={message}
|
||||||
onChange={(evt) => this.setState({ message: evt.target.value })}
|
onChange={(evt) => this.setState({ message: evt.target.value })}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Chat here"
|
placeholder="Chat here"
|
||||||
/>
|
/>
|
||||||
<button id="chatmsginput" type="submit">Send</button>
|
<button
|
||||||
|
id="chatmsginput"
|
||||||
|
type="submit"
|
||||||
|
style={{ height: 22 }}
|
||||||
|
>
|
||||||
|
‣
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
<select
|
||||||
|
onChange={(evt) => setChannel(evt.target.selectedIndex)}
|
||||||
|
style={{ height: 22 }}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
CHAT_CHANNELS.map((ch) => (
|
||||||
|
<option selected={ch === selectedChannel}>{ch}</option>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="modallink" onClick={this.props.open} style={{ textAlign: 'center', fontSize: 13 }}>You must be logged in to chat</div>
|
<div
|
||||||
|
className="modallink"
|
||||||
|
onClick={open}
|
||||||
|
style={{ textAlign: 'center', fontSize: 13 }}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
You must be logged in to chat
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state: State) {
|
function mapStateToProps(state: State) {
|
||||||
const { name } = state.user;
|
const { name } = state.user;
|
||||||
return { name };
|
const { chatChannel } = state.gui;
|
||||||
|
return { name, chatChannel };
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
|
@ -67,6 +104,9 @@ function mapDispatchToProps(dispatch) {
|
||||||
open() {
|
open() {
|
||||||
dispatch(showUserAreaModal());
|
dispatch(showUserAreaModal());
|
||||||
},
|
},
|
||||||
|
setChannel(channelId) {
|
||||||
|
dispatch(setChatChannel(channelId));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ import redis from '../data/redis';
|
||||||
import User from '../data/models/User';
|
import User from '../data/models/User';
|
||||||
import webSockets from '../socket/websockets';
|
import webSockets from '../socket/websockets';
|
||||||
|
|
||||||
|
import { CHAT_CHANNELS } from './constants';
|
||||||
|
|
||||||
|
|
||||||
class ChatProvider {
|
class ChatProvider {
|
||||||
/*
|
/*
|
||||||
|
@ -16,20 +18,23 @@ class ChatProvider {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.history = [];
|
this.history = [];
|
||||||
|
for (let i = 0; i < CHAT_CHANNELS.length; i += 1) {
|
||||||
|
this.history.push([]);
|
||||||
|
}
|
||||||
this.caseCheck = /^[A-Z !.]*$/;
|
this.caseCheck = /^[A-Z !.]*$/;
|
||||||
this.filters = [
|
this.filters = [
|
||||||
{
|
{
|
||||||
regexp: /ADMIN/gi,
|
regexp: /ADMIN/gi,
|
||||||
matches: 2,
|
matches: 3,
|
||||||
},
|
|
||||||
{
|
|
||||||
regexp: /FUCK/gi,
|
|
||||||
matches: 2,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
regexp: /JEBAĆ/gi,
|
regexp: /JEBAĆ/gi,
|
||||||
matches: 2,
|
matches: 2,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
regexp: /FUCK/gi,
|
||||||
|
matches: 3,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
regexp: /FACK/gi,
|
regexp: /FACK/gi,
|
||||||
matches: 3,
|
matches: 3,
|
||||||
|
@ -44,20 +49,21 @@ class ChatProvider {
|
||||||
this.mutedCountries = [];
|
this.mutedCountries = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
addMessage(name, message, country) {
|
addMessage(name, message, country, channelId = 0) {
|
||||||
if (this.history.length > 20) {
|
const channelHistory = this.history[channelId];
|
||||||
this.history.shift();
|
if (channelHistory.length > 20) {
|
||||||
|
channelHistory.shift();
|
||||||
}
|
}
|
||||||
this.history.push([name, message, country]);
|
channelHistory.push([name, message, country]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage(user, message) {
|
async sendMessage(user, message, channelId: number = 0) {
|
||||||
const name = (user.regUser) ? user.regUser.name : null;
|
const name = (user.regUser) ? user.regUser.name : null;
|
||||||
const country = (name.endsWith('berg') || name.endsWith('stein'))
|
const country = (name.endsWith('berg') || name.endsWith('stein'))
|
||||||
? 'il'
|
? 'il'
|
||||||
: (user.country || 'xx');
|
: (user.country || 'xx');
|
||||||
|
|
||||||
if (name.startsWith('popie')) return null;
|
if (name.startsWith('popi')) return null;
|
||||||
if (!name) {
|
if (!name) {
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
return 'Couldn\'t send your message, pls log out and back in again.';
|
return 'Couldn\'t send your message, pls log out and back in again.';
|
||||||
|
@ -77,7 +83,7 @@ class ChatProvider {
|
||||||
const filter = this.filters[i];
|
const filter = this.filters[i];
|
||||||
const count = (message.match(filter.regexp) || []).length;
|
const count = (message.match(filter.regexp) || []).length;
|
||||||
if (count >= filter.matches) {
|
if (count >= filter.matches) {
|
||||||
ChatProvider.mute(name, 30);
|
ChatProvider.mute(name, channelId, 30);
|
||||||
return 'Ow no! Spam protection decided to mute you';
|
return 'Ow no! Spam protection decided to mute you';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,17 +110,22 @@ class ChatProvider {
|
||||||
if (cmd === 'mute') {
|
if (cmd === 'mute') {
|
||||||
const timeMin = Number(args.slice(-1));
|
const timeMin = Number(args.slice(-1));
|
||||||
if (Number.isNaN(timeMin)) {
|
if (Number.isNaN(timeMin)) {
|
||||||
return ChatProvider.mute(args.join(' '));
|
return ChatProvider.mute(args.join(' '), channelId);
|
||||||
}
|
}
|
||||||
return ChatProvider.mute(args.slice(0, -1).join(' '), timeMin);
|
return ChatProvider.mute(
|
||||||
|
args.slice(0, -1).join(' '),
|
||||||
|
channelId,
|
||||||
|
timeMin,
|
||||||
|
);
|
||||||
} if (cmd === 'unmute') {
|
} if (cmd === 'unmute') {
|
||||||
return ChatProvider.unmute(args.join(' '));
|
return ChatProvider.unmute(args.join(' '), channelId);
|
||||||
} if (cmd === 'mutec' && args[0]) {
|
} if (cmd === 'mutec' && args[0]) {
|
||||||
const cc = args[0].toLowerCase();
|
const cc = args[0].toLowerCase();
|
||||||
this.mutedCountries.push(cc);
|
this.mutedCountries.push(cc);
|
||||||
webSockets.broadcastChatMessage(
|
webSockets.broadcastChatMessage(
|
||||||
'info',
|
'info',
|
||||||
`Country ${cc} has been muted`,
|
`Country ${cc} has been muted`,
|
||||||
|
channelId,
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
} if (cmd === 'unmutec' && args[0]) {
|
} if (cmd === 'unmutec' && args[0]) {
|
||||||
|
@ -126,6 +137,7 @@ class ChatProvider {
|
||||||
webSockets.broadcastChatMessage(
|
webSockets.broadcastChatMessage(
|
||||||
'info',
|
'info',
|
||||||
`Country ${cc} has been unmuted`,
|
`Country ${cc} has been unmuted`,
|
||||||
|
channelId,
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -146,8 +158,8 @@ class ChatProvider {
|
||||||
}
|
}
|
||||||
return `You are muted for another ${muted} seconds`;
|
return `You are muted for another ${muted} seconds`;
|
||||||
}
|
}
|
||||||
this.addMessage(name, message, country);
|
this.addMessage(name, message, country, channelId);
|
||||||
webSockets.broadcastChatMessage(name, message, country);
|
webSockets.broadcastChatMessage(name, message, country, channelId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,10 +167,11 @@ class ChatProvider {
|
||||||
name,
|
name,
|
||||||
message,
|
message,
|
||||||
country: string = 'xx',
|
country: string = 'xx',
|
||||||
|
channelId: number = 0,
|
||||||
sendapi: boolean = true,
|
sendapi: boolean = true,
|
||||||
) {
|
) {
|
||||||
this.addMessage(name, message, country);
|
this.addMessage(name, message, country, channelId);
|
||||||
webSockets.broadcastChatMessage(name, message, country, sendapi);
|
webSockets.broadcastChatMessage(name, message, country, channelId, sendapi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -166,8 +179,8 @@ class ChatProvider {
|
||||||
* singleton
|
* singleton
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
automute(name) {
|
automute(name, channelId = 0) {
|
||||||
ChatProvider.mute(name, 600);
|
ChatProvider.mute(name, channelId, 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async checkIfMuted(user) {
|
static async checkIfMuted(user) {
|
||||||
|
@ -176,7 +189,7 @@ class ChatProvider {
|
||||||
return ttl;
|
return ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async mute(name, timeMin = null) {
|
static async mute(name, channelId = 0, timeMin = null) {
|
||||||
const id = await User.name2Id(name);
|
const id = await User.name2Id(name);
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return `Couldn't find user ${name}`;
|
return `Couldn't find user ${name}`;
|
||||||
|
@ -186,19 +199,25 @@ class ChatProvider {
|
||||||
const ttl = timeMin * 60;
|
const ttl = timeMin * 60;
|
||||||
await redis.setAsync(key, '', 'EX', ttl);
|
await redis.setAsync(key, '', 'EX', ttl);
|
||||||
if (timeMin !== 600) {
|
if (timeMin !== 600) {
|
||||||
webSockets.broadcastChatMessage('info',
|
webSockets.broadcastChatMessage(
|
||||||
`${name} has been muted for ${timeMin}min`);
|
'info',
|
||||||
|
`${name} has been muted for ${timeMin}min`,
|
||||||
|
channelId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await redis.setAsync(key, '');
|
await redis.setAsync(key, '');
|
||||||
webSockets.broadcastChatMessage('info',
|
webSockets.broadcastChatMessage(
|
||||||
`${name} has been muted forever`);
|
'info',
|
||||||
|
`${name} has been muted forever`,
|
||||||
|
channelId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
logger.info(`Muted user ${id}`);
|
logger.info(`Muted user ${id}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async unmute(name) {
|
static async unmute(name, channelId = 0) {
|
||||||
const id = await User.name2Id(name);
|
const id = await User.name2Id(name);
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return `Couldn't find user ${name}`;
|
return `Couldn't find user ${name}`;
|
||||||
|
@ -208,8 +227,11 @@ class ChatProvider {
|
||||||
if (delKeys !== 1) {
|
if (delKeys !== 1) {
|
||||||
return `User ${name} is not muted`;
|
return `User ${name} is not muted`;
|
||||||
}
|
}
|
||||||
webSockets.broadcastChatMessage('info',
|
webSockets.broadcastChatMessage(
|
||||||
`${name} has been unmuted`);
|
'info',
|
||||||
|
`${name} has been unmuted`,
|
||||||
|
channelId,
|
||||||
|
);
|
||||||
logger.info(`Unmuted user ${id}`);
|
logger.info(`Unmuted user ${id}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,3 +88,6 @@ export const MINUTE = 60 * SECOND;
|
||||||
export const HOUR = 60 * MINUTE;
|
export const HOUR = 60 * MINUTE;
|
||||||
export const DAY = 24 * HOUR;
|
export const DAY = 24 * HOUR;
|
||||||
export const MONTH = 30 * DAY;
|
export const MONTH = 30 * DAY;
|
||||||
|
|
||||||
|
// available Chat Channels
|
||||||
|
export const CHAT_CHANNELS = ['en', 'int'];
|
||||||
|
|
|
@ -17,6 +17,7 @@ export type GUIState = {
|
||||||
compactPalette: boolean,
|
compactPalette: boolean,
|
||||||
paletteOpen: boolean,
|
paletteOpen: boolean,
|
||||||
menuOpen: boolean,
|
menuOpen: boolean,
|
||||||
|
chatChannel: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: GUIState = {
|
const initialState: GUIState = {
|
||||||
|
@ -31,6 +32,7 @@ const initialState: GUIState = {
|
||||||
compactPalette: false,
|
compactPalette: false,
|
||||||
paletteOpen: true,
|
paletteOpen: true,
|
||||||
menuOpen: false,
|
menuOpen: false,
|
||||||
|
chatChannel: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,6 +97,13 @@ export default function gui(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'SET_CHAT_CHANNEL': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
chatChannel: action.channelId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
case 'SELECT_COLOR': {
|
case 'SELECT_COLOR': {
|
||||||
const {
|
const {
|
||||||
compactPalette,
|
compactPalette,
|
||||||
|
|
|
@ -44,7 +44,10 @@ const initialState: UserState = {
|
||||||
mailreg: false,
|
mailreg: false,
|
||||||
totalRanking: {},
|
totalRanking: {},
|
||||||
totalDailyRanking: {},
|
totalDailyRanking: {},
|
||||||
chatMessages: [['info', 'Welcome to the PixelPlanet Chat', 'il']],
|
chatMessages: [
|
||||||
|
[['info', 'Welcome to the PixelPlanet Chat', 'il']],
|
||||||
|
[['info', 'Welcome to the PixelPlanet Chat', 'il']],
|
||||||
|
],
|
||||||
minecraftname: null,
|
minecraftname: null,
|
||||||
isOnMobile: false,
|
isOnMobile: false,
|
||||||
notification: null,
|
notification: null,
|
||||||
|
@ -119,14 +122,21 @@ export default function user(
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'RECEIVE_CHAT_MESSAGE': {
|
case 'RECEIVE_CHAT_MESSAGE': {
|
||||||
const { name, text, country } = action;
|
const {
|
||||||
let { chatMessages } = state;
|
name, text, country, channel,
|
||||||
if (chatMessages.length > 50) {
|
} = action;
|
||||||
chatMessages = chatMessages.slice(-50);
|
const chatMessages = state.chatMessages.slice();
|
||||||
|
let channelMessages = chatMessages[channel];
|
||||||
|
if (channelMessages.length > 50) {
|
||||||
|
channelMessages = channelMessages.slice(-50);
|
||||||
}
|
}
|
||||||
|
channelMessages = channelMessages.concat([
|
||||||
|
[name, text, country]
|
||||||
|
]);
|
||||||
|
chatMessages[channel] = channelMessages;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
chatMessages: chatMessages.concat([[name, text, country]]),
|
chatMessages,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ async function verifyClient(info, done) {
|
||||||
const ip = await getIPFromRequest(req);
|
const ip = await getIPFromRequest(req);
|
||||||
|
|
||||||
if (!headers.authorization
|
if (!headers.authorization
|
||||||
|| headers.authorization != `Bearer ${APISOCKET_KEY}`) {
|
|| headers.authorization !== `Bearer ${APISOCKET_KEY}`) {
|
||||||
logger.warn(`API ws request from ${ip} authenticated`);
|
logger.warn(`API ws request from ${ip} authenticated`);
|
||||||
return done(false);
|
return done(false);
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,15 @@ class APISocketServer extends WebSocketEvents {
|
||||||
setInterval(this.ping, 45 * 1000);
|
setInterval(this.ping, 45 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastChatMessage(name, msg, country, sendapi, ws = null) {
|
broadcastChatMessage(
|
||||||
if (!sendapi) return;
|
name,
|
||||||
|
msg,
|
||||||
|
country,
|
||||||
|
channelId,
|
||||||
|
sendapi,
|
||||||
|
ws = null,
|
||||||
|
) {
|
||||||
|
if (!sendapi || channelId !== 0) return;
|
||||||
|
|
||||||
const sendmsg = JSON.stringify(['msg', name, msg]);
|
const sendmsg = JSON.stringify(['msg', name, msg]);
|
||||||
this.wss.clients.forEach((client) => {
|
this.wss.clients.forEach((client) => {
|
||||||
|
@ -238,14 +245,14 @@ class APISocketServer extends WebSocketEvents {
|
||||||
const chatname = (user.id)
|
const chatname = (user.id)
|
||||||
? `[MC] ${user.regUser.name}`
|
? `[MC] ${user.regUser.name}`
|
||||||
: `[MC] ${minecraftname}`;
|
: `[MC] ${minecraftname}`;
|
||||||
chatProvider.broadcastChatMessage(chatname, msg, 'xx', false);
|
chatProvider.broadcastChatMessage(chatname, msg, 'xx', 0, false);
|
||||||
this.broadcastChatMessage(chatname, msg, 'xx', true, ws);
|
this.broadcastChatMessage(chatname, msg, 'xx', 0, true, ws);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (command == 'chat') {
|
if (command == 'chat') {
|
||||||
const [name, msg] = packet;
|
const [name, msg] = packet;
|
||||||
chatProvider.broadcastChatMessage(name, msg, 'xx', false);
|
chatProvider.broadcastChatMessage(name, msg, 'xx', 0, false);
|
||||||
this.broadcastChatMessage(name, msg, 'xx', true, ws);
|
this.broadcastChatMessage(name, msg, 'xx', 0, true, ws);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (command == 'linkacc') {
|
if (command == 'linkacc') {
|
||||||
|
|
|
@ -132,8 +132,10 @@ class ProtocolClient extends EventEmitter {
|
||||||
if (this.isConnected) this.ws.send(buffer);
|
if (this.isConnected) this.ws.send(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage(message) {
|
sendChatMessage(message, channelId) {
|
||||||
if (this.isConnected) this.ws.send(message);
|
if (this.isConnected) {
|
||||||
|
this.ws.send(JSON.stringify([message, channelId]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessage({ data: message }) {
|
onMessage({ data: message }) {
|
||||||
|
@ -160,10 +162,10 @@ class ProtocolClient extends EventEmitter {
|
||||||
this.emit('chatHistory', data);
|
this.emit('chatHistory', data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data.length === 3) {
|
if (data.length === 4) {
|
||||||
// Ordinary array: Chat message
|
// Ordinary array: Chat message
|
||||||
const [name, text, country] = data;
|
const [name, text, country, channelId] = data;
|
||||||
this.emit('chatMessage', name, text, country);
|
this.emit('chatMessage', name, text, country, channelId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// string = name
|
// string = name
|
||||||
|
|
|
@ -145,8 +145,13 @@ class SocketServer extends WebSocketEvents {
|
||||||
this.broadcast(buffer);
|
this.broadcast(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastChatMessage(name: string, message: string, country: string) {
|
broadcastChatMessage(
|
||||||
const text = JSON.stringify([name, message, country]);
|
name: string,
|
||||||
|
message: string,
|
||||||
|
country: string,
|
||||||
|
channelId: number = 0,
|
||||||
|
) {
|
||||||
|
const text = JSON.stringify([name, message, country, channelId]);
|
||||||
this.wss.clients.forEach((ws) => {
|
this.wss.clients.forEach((ws) => {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
if (ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send(text);
|
ws.send(text);
|
||||||
|
@ -217,23 +222,48 @@ class SocketServer extends WebSocketEvents {
|
||||||
webSockets.broadcastOnlineCounter(online);
|
webSockets.broadcastOnlineCounter(online);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async onTextMessage(message, ws) {
|
static async onTextMessage(text, ws) {
|
||||||
|
let message;
|
||||||
|
let channelId;
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(text);
|
||||||
|
[message, channelId] = data;
|
||||||
|
channelId = Number(channelId);
|
||||||
|
if (Number.isNaN(channelId)) {
|
||||||
|
throw new Error('NaN');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
logger.warn(
|
||||||
|
`Received unparseable message from ${ws.name} on websocket: ${text}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ws.name && message) {
|
if (ws.name && message) {
|
||||||
const waitLeft = ws.rateLimiter.tick();
|
const waitLeft = ws.rateLimiter.tick();
|
||||||
if (waitLeft) {
|
if (waitLeft) {
|
||||||
// eslint-disable-next-line max-len
|
ws.send(JSON.stringify([
|
||||||
ws.send(JSON.stringify(['info', `You are sending messages too fast, you have to wait ${Math.floor(waitLeft / 1000)}s :(`, 'il']));
|
'info',
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
`You are sending messages too fast, you have to wait ${Math.floor(waitLeft / 1000)}s :(`,
|
||||||
|
'il',
|
||||||
|
channelId,
|
||||||
|
]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const errorMsg = await chatProvider.sendMessage(ws.user, message);
|
const errorMsg = await chatProvider.sendMessage(
|
||||||
|
ws.user,
|
||||||
|
message,
|
||||||
|
channelId,
|
||||||
|
);
|
||||||
if (errorMsg) {
|
if (errorMsg) {
|
||||||
ws.send(JSON.stringify(['info', errorMsg, 'il']));
|
ws.send(JSON.stringify(['info', errorMsg, 'il', channelId]));
|
||||||
}
|
}
|
||||||
if (ws.last_message && ws.last_message === message) {
|
if (ws.last_message && ws.last_message === message) {
|
||||||
ws.message_repeat += 1;
|
ws.message_repeat += 1;
|
||||||
if (ws.message_repeat >= 3) {
|
if (ws.message_repeat >= 3) {
|
||||||
logger.info(`User ${ws.name} got automuted`);
|
logger.info(`User ${ws.name} got automuted`);
|
||||||
chatProvider.automute(ws.name);
|
chatProvider.automute(ws.name, channelId);
|
||||||
ws.message_repeat = 0;
|
ws.message_repeat = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,7 +14,7 @@ class WebSocketEvents {
|
||||||
broadcastPixelBuffer(canvasId: number, chunkid: number, buffer: Buffer) {
|
broadcastPixelBuffer(canvasId: number, chunkid: number, buffer: Buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastChatMessage(name: string, message: string) {
|
broadcastChatMessage(name: string, message: string, channelId: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastMinecraftLink(name: string, minecraftid: string, accepted: boolean) {
|
broadcastMinecraftLink(name: string, minecraftid: string, accepted: boolean) {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import logger from '../core/logger';
|
|
||||||
import OnlineCounter from './packets/OnlineCounter';
|
import OnlineCounter from './packets/OnlineCounter';
|
||||||
import PixelUpdate from './packets/PixelUpdate';
|
import PixelUpdate from './packets/PixelUpdate';
|
||||||
|
|
||||||
|
@ -64,14 +63,16 @@ class WebSockets {
|
||||||
name: string,
|
name: string,
|
||||||
message: string,
|
message: string,
|
||||||
country: string,
|
country: string,
|
||||||
|
channelId: number = 0,
|
||||||
sendapi: boolean = true,
|
sendapi: boolean = true,
|
||||||
) {
|
) {
|
||||||
country == country || 'xx';
|
country = country || 'xx';
|
||||||
this.listeners.forEach(
|
this.listeners.forEach(
|
||||||
(listener) => listener.broadcastChatMessage(
|
(listener) => listener.broadcastChatMessage(
|
||||||
name,
|
name,
|
||||||
message,
|
message,
|
||||||
country,
|
country,
|
||||||
|
channelId,
|
||||||
sendapi,
|
sendapi,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -173,6 +173,12 @@ export default (store) => (next) => (action) => {
|
||||||
|
|
||||||
case 'RECEIVE_CHAT_MESSAGE': {
|
case 'RECEIVE_CHAT_MESSAGE': {
|
||||||
if (!chatNotify) break;
|
if (!chatNotify) break;
|
||||||
|
|
||||||
|
const { chatChannel } = state.gui;
|
||||||
|
if (action.channel !== chatChannel) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const oscillatorNode = context.createOscillator();
|
const oscillatorNode = context.createOscillator();
|
||||||
const gainNode = context.createGain();
|
const gainNode = context.createGain();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user