refactor socket events
send captcha solution via websocket
This commit is contained in:
parent
7a2053fda3
commit
e9952134a5
|
@ -8,11 +8,6 @@ import createKeyPressHandler from './controls/keypress';
|
||||||
import {
|
import {
|
||||||
initTimer,
|
initTimer,
|
||||||
urlChange,
|
urlChange,
|
||||||
receiveOnline,
|
|
||||||
receiveCoolDown,
|
|
||||||
receiveChatMessage,
|
|
||||||
addChatChannel,
|
|
||||||
removeChatChannel,
|
|
||||||
setMobile,
|
setMobile,
|
||||||
windowResize,
|
windowResize,
|
||||||
} from './store/actions';
|
} from './store/actions';
|
||||||
|
@ -47,50 +42,6 @@ persistStore(store, {}, () => {
|
||||||
SocketClient.on('pixelReturn', (args) => {
|
SocketClient.on('pixelReturn', (args) => {
|
||||||
receivePixelReturn(store, getRenderer(), args);
|
receivePixelReturn(store, getRenderer(), args);
|
||||||
});
|
});
|
||||||
SocketClient.on('cooldownPacket', (coolDown) => {
|
|
||||||
store.dispatch(receiveCoolDown(coolDown));
|
|
||||||
});
|
|
||||||
SocketClient.on('onlineCounter', (online) => {
|
|
||||||
store.dispatch(receiveOnline(online));
|
|
||||||
});
|
|
||||||
SocketClient.on('chatMessage', (
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channelId,
|
|
||||||
userId,
|
|
||||||
) => {
|
|
||||||
const state = store.getState();
|
|
||||||
|
|
||||||
// assume that if one chat window is not hidden, all are
|
|
||||||
const isRead = state.windows.showWindows
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
&& state.windows.windows.find((win) => win.windowType === 'CHAT' && !win.hidden)
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
&& Object.values(state.windows.args).find((args) => args.chatChannel === channelId);
|
|
||||||
|
|
||||||
// TODO ping doesn't work since update
|
|
||||||
// const { nameRegExp } = state.user;
|
|
||||||
// const isPing = (nameRegExp && text.match(nameRegExp));
|
|
||||||
store.dispatch(receiveChatMessage(
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channelId,
|
|
||||||
userId,
|
|
||||||
false,
|
|
||||||
!!isRead,
|
|
||||||
));
|
|
||||||
});
|
|
||||||
SocketClient.on('changedMe', () => {
|
|
||||||
store.dispatch(fetchMe());
|
|
||||||
});
|
|
||||||
SocketClient.on('remch', (cid) => {
|
|
||||||
store.dispatch(removeChatChannel(cid));
|
|
||||||
});
|
|
||||||
SocketClient.on('addch', (channel) => {
|
|
||||||
store.dispatch(addChatChannel(channel));
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('hashchange', () => {
|
window.addEventListener('hashchange', () => {
|
||||||
store.dispatch(urlChange());
|
store.dispatch(urlChange());
|
||||||
|
|
|
@ -8,13 +8,14 @@ import React, { useState } from 'react';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import Captcha from './Captcha';
|
import Captcha from './Captcha';
|
||||||
|
import socketClient from '../socket/SocketClient';
|
||||||
import {
|
import {
|
||||||
requestSolveCaptcha,
|
|
||||||
requestBanMe,
|
requestBanMe,
|
||||||
} from '../store/actions/fetch';
|
} from '../store/actions/fetch';
|
||||||
|
|
||||||
const GlobalCaptcha = ({ close }) => {
|
const GlobalCaptcha = ({ close }) => {
|
||||||
const [errors, setErrors] = useState([]);
|
const [error, setError] = useState(null);
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [legit, setLegit] = useState(false);
|
const [legit, setLegit] = useState(false);
|
||||||
// used to be able to force Captcha rerender on error
|
// used to be able to force Captcha rerender on error
|
||||||
const [captKey, setCaptKey] = useState(Date.now());
|
const [captKey, setCaptKey] = useState(Date.now());
|
||||||
|
@ -24,7 +25,7 @@ const GlobalCaptcha = ({ close }) => {
|
||||||
onSubmit={async (e) => {
|
onSubmit={async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const text = e.target.captcha.value.slice(0, 6);
|
const text = e.target.captcha.value.slice(0, 6);
|
||||||
if (!text || text.length < 4) {
|
if (submitting || !text) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
@ -36,23 +37,44 @@ const GlobalCaptcha = ({ close }) => {
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
const captchaid = e.target.captchaid.value;
|
const captchaid = e.target.captchaid.value;
|
||||||
const { errors: resErrors } = await requestSolveCaptcha(
|
let errorText;
|
||||||
text,
|
try {
|
||||||
captchaid,
|
setSubmitting(true);
|
||||||
);
|
const retCode = await socketClient
|
||||||
if (resErrors) {
|
.sendCaptchaSolution(text, captchaid);
|
||||||
setCaptKey(Date.now());
|
console.log('Captcha return:', retCode);
|
||||||
setErrors(resErrors);
|
switch (retCode) {
|
||||||
} else {
|
case 0:
|
||||||
close();
|
close();
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
errorText = t`You took too long, try again.`;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
errorText = t`You failed your captcha`;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
errorText = t`No or invalid captcha text`;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
errorText = t`No captcha id given`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorText = t`Unknown Captcha Error`;
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
errorText = `${err.message}`;
|
||||||
|
}
|
||||||
|
setSubmitting(false);
|
||||||
|
setCaptKey(Date.now());
|
||||||
|
setError(errorText);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{errors.map((error) => (
|
{(error) && (
|
||||||
<p key={error} className="errormessage">
|
<p key={error} className="errormessage">
|
||||||
<span>{t`Error`}</span>: {error}
|
<span>{t`Error`}</span>: {error}
|
||||||
</p>
|
</p>
|
||||||
))}
|
)}
|
||||||
<Captcha autoload key={captKey} setLegit={setLegit} />
|
<Captcha autoload key={captKey} setLegit={setLegit} />
|
||||||
<p>
|
<p>
|
||||||
<button
|
<button
|
||||||
|
@ -65,7 +87,7 @@ const GlobalCaptcha = ({ close }) => {
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
{t`Send`}
|
{(submitting) ? '...' : t`Send`}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -233,8 +233,7 @@ class PixelPlainterControls {
|
||||||
// 5275_-8713
|
// 5275_-8713
|
||||||
// 5398_-8614
|
// 5398_-8614
|
||||||
if (x > 5275 && y > -8713 && x < 5398 && y < -8614) {
|
if (x > 5275 && y > -8713 && x < 5398 && y < -8614) {
|
||||||
// eslint-disable-next-line eqeqeq
|
if (state.canvas.canvasId === '0') {
|
||||||
if (state.canvas.canvasId == 0) {
|
|
||||||
window.location.href = 'https://files.catbox.moe/gh2wtr.mp4';
|
window.location.href = 'https://files.catbox.moe/gh2wtr.mp4';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,7 @@ function createKeyPressHandler(store) {
|
||||||
const canvasIds = Object.keys(canvases).filter((id) => !canvases[id].hid);
|
const canvasIds = Object.keys(canvases).filter((id) => !canvases[id].hid);
|
||||||
if (num <= canvasIds.length) {
|
if (num <= canvasIds.length) {
|
||||||
const canvasId = canvasIds[num - 1];
|
const canvasId = canvasIds[num - 1];
|
||||||
// eslint-disable-next-line eqeqeq
|
if (canvasId !== curCanvasId) {
|
||||||
if (canvasId != curCanvasId) {
|
|
||||||
store.dispatch(selectCanvas(canvasId));
|
store.dispatch(selectCanvas(canvasId));
|
||||||
const canvasName = canvases[canvasId].title;
|
const canvasName = canvases[canvasId].title;
|
||||||
store.dispatch(notify(t`Switched to ${canvasName}`));
|
store.dispatch(notify(t`Switched to ${canvasName}`));
|
||||||
|
|
|
@ -268,7 +268,7 @@ export class ChatProvider {
|
||||||
const cmdArr = message.split(' ');
|
const cmdArr = message.split(' ');
|
||||||
const cmd = cmdArr[0].substring(1);
|
const cmd = cmdArr[0].substring(1);
|
||||||
const args = cmdArr.slice(1);
|
const args = cmdArr.slice(1);
|
||||||
const initiator = `@[${escapeMd(user.getName())}](${user.id})`;
|
const initiator = `@[${escapeMd(user.name)}](${user.id})`;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'mute': {
|
case 'mute': {
|
||||||
const timeMin = Number(args.slice(-1));
|
const timeMin = Number(args.slice(-1));
|
||||||
|
@ -398,7 +398,7 @@ export class ChatProvider {
|
||||||
) {
|
) {
|
||||||
const { id } = user;
|
const { id } = user;
|
||||||
const { t } = user.ttag;
|
const { t } = user.ttag;
|
||||||
const name = user.getName();
|
const { name } = user;
|
||||||
|
|
||||||
if (!name || !id) {
|
if (!name || !id) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const DEFAULT_SCALE = 3;
|
||||||
|
|
||||||
// default canvas that is first assumed, before real canvas data
|
// default canvas that is first assumed, before real canvas data
|
||||||
// gets fetched via api/me
|
// gets fetched via api/me
|
||||||
export const DEFAULT_CANVAS_ID = 0;
|
export const DEFAULT_CANVAS_ID = '0';
|
||||||
export const DEFAULT_CANVASES = {
|
export const DEFAULT_CANVASES = {
|
||||||
0: {
|
0: {
|
||||||
ident: 'd',
|
ident: 'd',
|
||||||
|
|
|
@ -160,7 +160,7 @@ export function getIdFromObject(obj, ident) {
|
||||||
for (let i = 0; i < ids.length; i += 1) {
|
for (let i = 0; i < ids.length; i += 1) {
|
||||||
const key = ids[i];
|
const key = ids[i];
|
||||||
if (obj[key].ident === ident) {
|
if (obj[key].ident === ident) {
|
||||||
return parseInt(key, 10);
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -158,6 +158,14 @@ class User {
|
||||||
this.setRegUser(this.regUser);
|
this.setRegUser(this.regUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return (this.regUser) ? this.regUser.name : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isRegistered() {
|
||||||
|
return !!this.id;
|
||||||
|
}
|
||||||
|
|
||||||
addChannel(cid, channelArray) {
|
addChannel(cid, channelArray) {
|
||||||
this.channels[cid] = channelArray;
|
this.channels[cid] = channelArray;
|
||||||
}
|
}
|
||||||
|
@ -166,10 +174,6 @@ class User {
|
||||||
delete this.channels[cid];
|
delete this.channels[cid];
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return (this.regUser) ? this.regUser.name : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
setWait(wait, canvasId) {
|
setWait(wait, canvasId) {
|
||||||
return setCoolDown(this.ipSub, this.id, canvasId, wait);
|
return setCoolDown(this.ipSub, this.id, canvasId, wait);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,20 +68,14 @@ function evaluateResult(captchaText, userText) {
|
||||||
* set captcha solution
|
* set captcha solution
|
||||||
*
|
*
|
||||||
* @param text Solution of captcha
|
* @param text Solution of captcha
|
||||||
* @param ip
|
|
||||||
* @param captchaid
|
* @param captchaid
|
||||||
*/
|
*/
|
||||||
export async function setCaptchaSolution(
|
export async function setCaptchaSolution(
|
||||||
text,
|
text,
|
||||||
ip,
|
captchaid,
|
||||||
captchaid = null,
|
|
||||||
) {
|
) {
|
||||||
let key = `capt:${ip}`;
|
|
||||||
if (captchaid) {
|
|
||||||
key += `:${captchaid}`;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
await client.set(key, text, {
|
await client.set(`capt:${captchaid}`, text, {
|
||||||
EX: CAPTCHA_TIMEOUT,
|
EX: CAPTCHA_TIMEOUT,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -105,22 +99,24 @@ export async function setCaptchaSolution(
|
||||||
export async function checkCaptchaSolution(
|
export async function checkCaptchaSolution(
|
||||||
text,
|
text,
|
||||||
ip,
|
ip,
|
||||||
onetime = false,
|
onetime,
|
||||||
captchaid = null,
|
captchaid,
|
||||||
wrongCallback = null,
|
wrongCallback = null,
|
||||||
) {
|
) {
|
||||||
const ipn = getIPv6Subnet(ip);
|
if (!text || text.length > 10) {
|
||||||
let key = `capt:${ip}`;
|
return 3;
|
||||||
if (captchaid) {
|
|
||||||
key += `:${captchaid}`;
|
|
||||||
}
|
}
|
||||||
const solution = await client.get(key);
|
if (!captchaid) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
const solution = await client.get(`capt:${captchaid}`);
|
||||||
if (solution) {
|
if (solution) {
|
||||||
if (evaluateResult(solution, text)) {
|
if (evaluateResult(solution, text)) {
|
||||||
if (Math.random() < 0.1) {
|
if (Math.random() < 0.1) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (!onetime) {
|
if (!onetime) {
|
||||||
|
const ipn = getIPv6Subnet(ip);
|
||||||
const solvkey = `${PREFIX}:${ipn}`;
|
const solvkey = `${PREFIX}:${ipn}`;
|
||||||
await client.set(solvkey, '', {
|
await client.set(solvkey, '', {
|
||||||
EX: TTL_CACHE,
|
EX: TTL_CACHE,
|
||||||
|
|
43
src/popup.js
43
src/popup.js
|
@ -8,10 +8,6 @@ import { parentExists } from './core/utils';
|
||||||
import store from './store/storePopUp';
|
import store from './store/storePopUp';
|
||||||
import {
|
import {
|
||||||
urlChange,
|
urlChange,
|
||||||
receiveOnline,
|
|
||||||
receiveChatMessage,
|
|
||||||
removeChatChannel,
|
|
||||||
addChatChannel,
|
|
||||||
} from './store/actions';
|
} from './store/actions';
|
||||||
import {
|
import {
|
||||||
fetchMe,
|
fetchMe,
|
||||||
|
@ -28,45 +24,6 @@ persistStore(store, {}, () => {
|
||||||
store.dispatch(urlChange());
|
store.dispatch(urlChange());
|
||||||
});
|
});
|
||||||
|
|
||||||
SocketClient.on('onlineCounter', (online) => {
|
|
||||||
store.dispatch(receiveOnline(online));
|
|
||||||
});
|
|
||||||
SocketClient.on('chatMessage', (
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channelId,
|
|
||||||
userId,
|
|
||||||
) => {
|
|
||||||
const state = store.getState();
|
|
||||||
|
|
||||||
// assume that if one chat window is not hidden, all are
|
|
||||||
const isRead = state.popup.windowType === 'CHAT'
|
|
||||||
&& state.popup.args.chatChannel === channelId;
|
|
||||||
|
|
||||||
// TODO ping doesn't work since update
|
|
||||||
// const { nameRegExp } = state.user;
|
|
||||||
// const isPing = (nameRegExp && text.match(nameRegExp));
|
|
||||||
store.dispatch(receiveChatMessage(
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channelId,
|
|
||||||
userId,
|
|
||||||
false,
|
|
||||||
!!isRead,
|
|
||||||
));
|
|
||||||
});
|
|
||||||
SocketClient.on('changedMe', () => {
|
|
||||||
store.dispatch(fetchMe());
|
|
||||||
});
|
|
||||||
SocketClient.on('remch', (cid) => {
|
|
||||||
store.dispatch(removeChatChannel(cid));
|
|
||||||
});
|
|
||||||
SocketClient.on('addch', (channel) => {
|
|
||||||
store.dispatch(addChatChannel(channel));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!parentExists()) {
|
if (!parentExists()) {
|
||||||
store.dispatch(fetchMe());
|
store.dispatch(fetchMe());
|
||||||
SocketClient.initialize(store);
|
SocketClient.initialize(store);
|
||||||
|
|
|
@ -119,7 +119,7 @@ async function block(req, res) {
|
||||||
errors: ['Could not (un)block user'],
|
errors: ['Could not (un)block user'],
|
||||||
});
|
});
|
||||||
logger.info(
|
logger.info(
|
||||||
`User ${user.getName()} (un)blocked ${userName}`,
|
`User ${user.name} (un)blocked ${userName}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ async function blockdm(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`User ${user.getName()} (un)blocked all dms`,
|
`User ${user.name} (un)blocked all dms`,
|
||||||
);
|
);
|
||||||
|
|
||||||
await user.regUser.update({
|
await user.regUser.update({
|
||||||
|
|
|
@ -15,16 +15,6 @@ export default async (req, res) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { text, id } = req.body;
|
const { text, id } = req.body;
|
||||||
if (!text) {
|
|
||||||
res.status(400)
|
|
||||||
.json({ errors: [t`No captcha text given`] });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!id) {
|
|
||||||
res.status(400)
|
|
||||||
.json({ errors: [t`No captcha id given`] });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ret = await checkCaptchaSolution(
|
const ret = await checkCaptchaSolution(
|
||||||
text,
|
text,
|
||||||
|
@ -46,15 +36,19 @@ export default async (req, res) => {
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
res.status(422)
|
res.status(422)
|
||||||
.json({
|
.json({ errors: [t`You failed your captcha`] });
|
||||||
errors: [t`You failed your captcha`],
|
break;
|
||||||
});
|
case 3:
|
||||||
|
res.status(400)
|
||||||
|
.json({ errors: [t`No captcha text given`] });
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
res.status(400)
|
||||||
|
.json({ errors: [t`No captcha id given`] });
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res.status(422)
|
res.status(422)
|
||||||
.json({
|
.json({ errors: [t`Unknown Captcha Error`] });
|
||||||
errors: [t`Unknown Captcha Error`],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('CAPTCHA', error);
|
logger.error('CAPTCHA', error);
|
||||||
|
|
|
@ -57,7 +57,7 @@ async function leaveChan(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`Removing user ${user.getName()} from channel ${channel.name || channelId}`,
|
`Removing user ${user.name} from channel ${channel.name || channelId}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
user.regUser.removeChannel(channel);
|
user.regUser.removeChannel(channel);
|
||||||
|
|
|
@ -25,7 +25,7 @@ async function privatize(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`User ${user.getName()} set private status to ${priv}`,
|
`User ${user.name} set private status to ${priv}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
await user.regUser.update({
|
await user.regUser.update({
|
||||||
|
|
|
@ -108,7 +108,7 @@ async function startDm(req, res) {
|
||||||
ChatProvider.addUserToChannel(
|
ChatProvider.addUserToChannel(
|
||||||
userId,
|
userId,
|
||||||
ChannelId,
|
ChannelId,
|
||||||
[user.getName(), 1, curTime, user.id],
|
[user.name, 1, curTime, user.id],
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default (req, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ip = getIPFromRequest(req);
|
const ip = getIPFromRequest(req);
|
||||||
setCaptchaSolution(text, ip, id);
|
setCaptchaSolution(text, id);
|
||||||
logger.info(`Captchas: ${ip} got captcha with text: ${text}`);
|
logger.info(`Captchas: ${ip} got captcha with text: ${text}`);
|
||||||
|
|
||||||
res.set({
|
res.set({
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import WebSocket from 'ws';
|
import WebSocket from 'ws';
|
||||||
|
|
||||||
import socketEvents from './socketEvents';
|
import socketEvents from './socketEvents';
|
||||||
|
import { dehydrateOnlineCounter } from './packets/server';
|
||||||
import chatProvider, { ChatProvider } from '../core/ChatProvider';
|
import chatProvider, { ChatProvider } from '../core/ChatProvider';
|
||||||
import { RegUser } from '../data/sql';
|
import { RegUser } from '../data/sql';
|
||||||
import { getIPFromRequest } from '../utils/ip';
|
import { getIPFromRequest } from '../utils/ip';
|
||||||
|
@ -55,7 +56,6 @@ class APISocketServer {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.broadcast = this.broadcast.bind(this);
|
|
||||||
this.broadcastOnlineCounter = this.broadcastOnlineCounter.bind(this);
|
this.broadcastOnlineCounter = this.broadcastOnlineCounter.bind(this);
|
||||||
this.broadcastPixelBuffer = this.broadcastPixelBuffer.bind(this);
|
this.broadcastPixelBuffer = this.broadcastPixelBuffer.bind(this);
|
||||||
this.ping = this.ping.bind(this);
|
this.ping = this.ping.bind(this);
|
||||||
|
@ -155,8 +155,9 @@ class APISocketServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastOnlineCounter(data) {
|
broadcastOnlineCounter(online) {
|
||||||
this.broadcast(data, (client) => client.subOnline);
|
const buffer = dehydrateOnlineCounter(online);
|
||||||
|
this.broadcast(buffer, (client) => client.subOnline);
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastPixelBuffer(canvasId, chunkid, buffer) {
|
broadcastPixelBuffer(canvasId, chunkid, buffer) {
|
||||||
|
|
|
@ -371,11 +371,10 @@ class MessageBroker extends SocketEvents {
|
||||||
broadcastOnlineCounter(online) {
|
broadcastOnlineCounter(online) {
|
||||||
this.updateShardOnlineCounter(this.thisShard, online);
|
this.updateShardOnlineCounter(this.thisShard, online);
|
||||||
// send our online counter to other shards
|
// send our online counter to other shards
|
||||||
let buffer = dehydrateOnlineCounter(online);
|
const buffer = dehydrateOnlineCounter(online);
|
||||||
this.publisher.publish(this.thisShard, buffer);
|
this.publisher.publish(this.thisShard, buffer);
|
||||||
// send total counter to our players
|
// send total counter to our players
|
||||||
buffer = dehydrateOnlineCounter(this.onlineCounter);
|
super.emit('onlineCounter', this.onlineCounter);
|
||||||
super.emit('onlineCounter', buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkHealth() {
|
checkHealth() {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
dehydrateOnlineCounter,
|
|
||||||
dehydratePixelUpdate,
|
dehydratePixelUpdate,
|
||||||
} from './packets/server';
|
} from './packets/server';
|
||||||
|
|
||||||
|
@ -255,8 +254,7 @@ class SocketEvents extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
broadcastOnlineCounter(online) {
|
broadcastOnlineCounter(online) {
|
||||||
this.onlineCounter = online;
|
this.onlineCounter = online;
|
||||||
const buffer = dehydrateOnlineCounter(online);
|
this.emit('onlineCounter', online);
|
||||||
this.emit('onlineCounter', buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,11 @@ import {
|
||||||
hydratePixelReturn,
|
hydratePixelReturn,
|
||||||
hydrateOnlineCounter,
|
hydrateOnlineCounter,
|
||||||
hydrateCoolDown,
|
hydrateCoolDown,
|
||||||
|
hydrateCaptchaReturn,
|
||||||
dehydrateRegCanvas,
|
dehydrateRegCanvas,
|
||||||
dehydrateRegChunk,
|
dehydrateRegChunk,
|
||||||
dehydrateRegMChunks,
|
dehydrateRegMChunks,
|
||||||
dehydrateDeRegChunk,
|
dehydrateDeRegChunk,
|
||||||
dehydrateCaptchaSolution,
|
|
||||||
dehydratePixelUpdate,
|
dehydratePixelUpdate,
|
||||||
dehydratePing,
|
dehydratePing,
|
||||||
} from './packets/client';
|
} from './packets/client';
|
||||||
|
@ -22,7 +22,20 @@ import {
|
||||||
ONLINE_COUNTER_OP,
|
ONLINE_COUNTER_OP,
|
||||||
COOLDOWN_OP,
|
COOLDOWN_OP,
|
||||||
CHANGE_ME_OP,
|
CHANGE_ME_OP,
|
||||||
|
CAPTCHA_RETURN_OP,
|
||||||
} from './packets/op';
|
} from './packets/op';
|
||||||
|
import {
|
||||||
|
socketOpen,
|
||||||
|
socketClose,
|
||||||
|
receiveOnline,
|
||||||
|
receiveCoolDown,
|
||||||
|
receiveChatMessage,
|
||||||
|
addChatChannel,
|
||||||
|
removeChatChannel,
|
||||||
|
} from '../store/actions/socket';
|
||||||
|
import {
|
||||||
|
fetchMe,
|
||||||
|
} from '../store/actions/thunks';
|
||||||
import { shardHost } from '../store/actions/fetch';
|
import { shardHost } from '../store/actions/fetch';
|
||||||
|
|
||||||
const chunks = [];
|
const chunks = [];
|
||||||
|
@ -42,6 +55,7 @@ class SocketClient extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
this.readyState = WebSocket.CLOSED;
|
this.readyState = WebSocket.CLOSED;
|
||||||
this.msgQueue = [];
|
this.msgQueue = [];
|
||||||
|
this.reqQueue = [];
|
||||||
|
|
||||||
this.checkHealth = this.checkHealth.bind(this);
|
this.checkHealth = this.checkHealth.bind(this);
|
||||||
setInterval(this.checkHealth, 2000);
|
setInterval(this.checkHealth, 2000);
|
||||||
|
@ -122,10 +136,10 @@ class SocketClient extends EventEmitter {
|
||||||
this.timeLastPing = now;
|
this.timeLastPing = now;
|
||||||
this.timeLastSent = now;
|
this.timeLastSent = now;
|
||||||
|
|
||||||
this.emit('open', {});
|
this.store.dispatch(socketOpen());
|
||||||
this.readyState = WebSocket.OPEN;
|
this.readyState = WebSocket.OPEN;
|
||||||
this.send(dehydrateRegCanvas(
|
this.send(dehydrateRegCanvas(
|
||||||
this.store.getState().canvas,
|
this.store.getState().canvas.canvasId,
|
||||||
));
|
));
|
||||||
console.log(`Register ${chunks.length} chunks`);
|
console.log(`Register ${chunks.length} chunks`);
|
||||||
this.send(dehydrateRegMChunks(chunks));
|
this.send(dehydrateRegMChunks(chunks));
|
||||||
|
@ -136,7 +150,9 @@ class SocketClient extends EventEmitter {
|
||||||
if (canvasId === null) {
|
if (canvasId === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('Notify websocket server that we changed canvas');
|
console.log(
|
||||||
|
`Notify websocket server that we changed canvas to ${canvasId}`,
|
||||||
|
);
|
||||||
chunks.length = 0;
|
chunks.length = 0;
|
||||||
this.send(dehydrateRegCanvas(canvasId));
|
this.send(dehydrateRegCanvas(canvasId));
|
||||||
}
|
}
|
||||||
|
@ -163,10 +179,28 @@ class SocketClient extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sendCaptchaSolution(solution) {
|
* send captcha solution
|
||||||
const buffer = dehydrateCaptchaSolution(solution);
|
* @param solution text
|
||||||
}
|
* @return promise that resolves when response arrives
|
||||||
*/
|
*/
|
||||||
|
sendCaptchaSolution(solution, captchaid) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let id;
|
||||||
|
const queueObj = ['cs', (args) => {
|
||||||
|
resolve(args);
|
||||||
|
clearTimeout(id);
|
||||||
|
}];
|
||||||
|
this.reqQueue.push(queueObj);
|
||||||
|
id = setTimeout(() => {
|
||||||
|
const pos = this.reqQueue.indexOf(queueObj);
|
||||||
|
if (~pos) this.reqQueue.splice(pos, 1);
|
||||||
|
reject(new Error('Timeout'));
|
||||||
|
}, 20000);
|
||||||
|
this.sendWhenReady(
|
||||||
|
`cs,${JSON.stringify([solution, captchaid])}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send pixel request
|
* Send pixel request
|
||||||
|
@ -182,7 +216,9 @@ class SocketClient extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
sendChatMessage(message, channelId) {
|
sendChatMessage(message, channelId) {
|
||||||
this.sendWhenReady(JSON.stringify([message, channelId]));
|
this.sendWhenReady(
|
||||||
|
`cm,${JSON.stringify([message, channelId])}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessage({ data: message }) {
|
onMessage({ data: message }) {
|
||||||
|
@ -201,29 +237,26 @@ class SocketClient extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
onTextMessage(message) {
|
onTextMessage(message) {
|
||||||
if (!message) return;
|
const comma = message.indexOf(',');
|
||||||
const data = JSON.parse(message);
|
if (comma === -1) {
|
||||||
|
|
||||||
if (Array.isArray(data)) {
|
|
||||||
switch (data.length) {
|
|
||||||
case 5: {
|
|
||||||
// chat message
|
|
||||||
const [name, text, country, channelId, userId] = data;
|
|
||||||
this.emit('chatMessage',
|
|
||||||
name, text, country, Number(channelId), userId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 2: {
|
const key = message.slice(0, comma);
|
||||||
// signal
|
const val = JSON.parse(message.slice(comma + 1));
|
||||||
const [signal, args] = data;
|
switch (key) {
|
||||||
this.emit(signal, args);
|
case 'cm':
|
||||||
|
this.store.dispatch(receiveChatMessage(...val));
|
||||||
|
break;
|
||||||
|
case 'ac':
|
||||||
|
this.store.dispatch(addChatChannel(val));
|
||||||
|
break;
|
||||||
|
case 'rc':
|
||||||
|
this.store.dispatch(removeChatChannel(val));
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
onBinaryMessage(buffer) {
|
onBinaryMessage(buffer) {
|
||||||
if (buffer.byteLength === 0) return;
|
if (buffer.byteLength === 0) return;
|
||||||
|
@ -240,16 +273,23 @@ class SocketClient extends EventEmitter {
|
||||||
this.emit('pixelReturn', hydratePixelReturn(data));
|
this.emit('pixelReturn', hydratePixelReturn(data));
|
||||||
break;
|
break;
|
||||||
case ONLINE_COUNTER_OP:
|
case ONLINE_COUNTER_OP:
|
||||||
this.emit('onlineCounter', hydrateOnlineCounter(data));
|
this.store.dispatch(receiveOnline(hydrateOnlineCounter(data)));
|
||||||
break;
|
break;
|
||||||
case COOLDOWN_OP:
|
case COOLDOWN_OP:
|
||||||
this.emit('cooldownPacket', hydrateCoolDown(data));
|
this.store.dispatch(receiveCoolDown(hydrateCoolDown(data)));
|
||||||
break;
|
break;
|
||||||
case CHANGE_ME_OP:
|
case CHANGE_ME_OP:
|
||||||
console.log('Websocket requested api/me reload');
|
console.log('Websocket requested api/me reload');
|
||||||
this.emit('changedMe');
|
this.store.dispatch(fetchMe());
|
||||||
this.reconnect();
|
this.reconnect();
|
||||||
break;
|
break;
|
||||||
|
case CAPTCHA_RETURN_OP: {
|
||||||
|
const pos = this.reqQueue.findIndex((q) => q[0] === 'cs');
|
||||||
|
if (~pos) {
|
||||||
|
this.reqQueue.splice(pos, 1)[0][1](hydrateCaptchaReturn(data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
console.error(`Unknown op_code ${opcode} received`);
|
console.error(`Unknown op_code ${opcode} received`);
|
||||||
break;
|
break;
|
||||||
|
@ -257,7 +297,7 @@ class SocketClient extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose(e) {
|
onClose(e) {
|
||||||
this.emit('close');
|
this.store.dispatch(socketClose());
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
this.readyState = WebSocket.CONNECTING;
|
this.readyState = WebSocket.CONNECTING;
|
||||||
// reconnect in 1s if last connect was longer than 7s ago, else 5s
|
// reconnect in 1s if last connect was longer than 7s ago, else 5s
|
||||||
|
|
|
@ -21,19 +21,19 @@ import {
|
||||||
hydrateDeRegChunk,
|
hydrateDeRegChunk,
|
||||||
hydrateRegMChunks,
|
hydrateRegMChunks,
|
||||||
hydrateDeRegMChunks,
|
hydrateDeRegMChunks,
|
||||||
hydrateCaptchaSolution,
|
|
||||||
hydratePixelUpdate,
|
hydratePixelUpdate,
|
||||||
dehydrateChangeMe,
|
dehydrateChangeMe,
|
||||||
dehydrateOnlineCounter,
|
dehydrateOnlineCounter,
|
||||||
dehydratePixelUpdate,
|
|
||||||
dehydrateCoolDown,
|
dehydrateCoolDown,
|
||||||
dehydratePixelReturn,
|
dehydratePixelReturn,
|
||||||
|
dehydrateCaptchaReturn,
|
||||||
} from './packets/server';
|
} from './packets/server';
|
||||||
import socketEvents from './socketEvents';
|
import socketEvents from './socketEvents';
|
||||||
import chatProvider, { ChatProvider } from '../core/ChatProvider';
|
import chatProvider, { ChatProvider } from '../core/ChatProvider';
|
||||||
import authenticateClient from './authenticateClient';
|
import authenticateClient from './authenticateClient';
|
||||||
import drawByOffsets from '../core/draw';
|
import drawByOffsets from '../core/draw';
|
||||||
import isIPAllowed from '../core/isAllowed';
|
import isIPAllowed from '../core/isAllowed';
|
||||||
|
import { checkCaptchaSolution } from '../data/redis/captcha';
|
||||||
|
|
||||||
|
|
||||||
const ipCounter = new Counter();
|
const ipCounter = new Counter();
|
||||||
|
@ -64,7 +64,6 @@ class SocketServer {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.CHUNK_CLIENTS = new Map();
|
this.CHUNK_CLIENTS = new Map();
|
||||||
|
|
||||||
this.broadcast = this.broadcast.bind(this);
|
|
||||||
this.broadcastPixelBuffer = this.broadcastPixelBuffer.bind(this);
|
this.broadcastPixelBuffer = this.broadcastPixelBuffer.bind(this);
|
||||||
this.reloadUser = this.reloadUser.bind(this);
|
this.reloadUser = this.reloadUser.bind(this);
|
||||||
this.onlineCounterBroadcast = this.onlineCounterBroadcast.bind(this);
|
this.onlineCounterBroadcast = this.onlineCounterBroadcast.bind(this);
|
||||||
|
@ -93,7 +92,6 @@ class SocketServer {
|
||||||
ws.canvasId = null;
|
ws.canvasId = null;
|
||||||
const { user } = req;
|
const { user } = req;
|
||||||
ws.user = user;
|
ws.user = user;
|
||||||
ws.name = user.getName();
|
|
||||||
ws.chunkCnt = 0;
|
ws.chunkCnt = 0;
|
||||||
|
|
||||||
const { ip } = user;
|
const { ip } = user;
|
||||||
|
@ -101,7 +99,8 @@ class SocketServer {
|
||||||
ws.send(dehydrateOnlineCounter(socketEvents.onlineCounter));
|
ws.send(dehydrateOnlineCounter(socketEvents.onlineCounter));
|
||||||
|
|
||||||
ws.on('error', (e) => {
|
ws.on('error', (e) => {
|
||||||
logger.error(`WebSocket Client Error for ${ws.name}: ${e.message}`);
|
// eslint-disable-next-line max-len
|
||||||
|
logger.error(`WebSocket Client Error for ${ws.user.name}: ${e.message}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('close', () => {
|
ws.on('close', () => {
|
||||||
|
@ -120,7 +119,10 @@ class SocketServer {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socketEvents.on('onlineCounter', this.broadcast);
|
socketEvents.on('onlineCounter', (online) => {
|
||||||
|
const onlineBuffer = dehydrateOnlineCounter(online);
|
||||||
|
this.broadcast(onlineBuffer);
|
||||||
|
});
|
||||||
socketEvents.on('pixelUpdate', this.broadcastPixelBuffer);
|
socketEvents.on('pixelUpdate', this.broadcastPixelBuffer);
|
||||||
socketEvents.on('reloadUser', this.reloadUser);
|
socketEvents.on('reloadUser', this.reloadUser);
|
||||||
|
|
||||||
|
@ -132,8 +134,10 @@ class SocketServer {
|
||||||
id,
|
id,
|
||||||
country,
|
country,
|
||||||
) => {
|
) => {
|
||||||
|
const text = `cm,${JSON.stringify(
|
||||||
|
[name, message, country, channelId, id],
|
||||||
|
)}`;
|
||||||
this.findAllWsByUerId(userId).forEach((ws) => {
|
this.findAllWsByUerId(userId).forEach((ws) => {
|
||||||
const text = JSON.stringify([name, message, country, channelId, id]);
|
|
||||||
ws.send(text);
|
ws.send(text);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -145,7 +149,9 @@ class SocketServer {
|
||||||
id,
|
id,
|
||||||
country,
|
country,
|
||||||
) => {
|
) => {
|
||||||
const text = JSON.stringify([name, message, country, channelId, id]);
|
const text = `cm,${JSON.stringify(
|
||||||
|
[name, message, country, channelId, id],
|
||||||
|
)}`;
|
||||||
const clientArray = [];
|
const clientArray = [];
|
||||||
this.wss.clients.forEach((ws) => {
|
this.wss.clients.forEach((ws) => {
|
||||||
if (ws.user && chatProvider.userHasChannelAccess(ws.user, channelId)) {
|
if (ws.user && chatProvider.userHasChannelAccess(ws.user, channelId)) {
|
||||||
|
@ -158,11 +164,9 @@ class SocketServer {
|
||||||
socketEvents.on('addChatChannel', (userId, channelId, channelArray) => {
|
socketEvents.on('addChatChannel', (userId, channelId, channelArray) => {
|
||||||
this.findAllWsByUerId(userId).forEach((ws) => {
|
this.findAllWsByUerId(userId).forEach((ws) => {
|
||||||
ws.user.addChannel(channelId, channelArray);
|
ws.user.addChannel(channelId, channelArray);
|
||||||
const text = JSON.stringify([
|
const text = `ac,${JSON.stringify({
|
||||||
'addch', {
|
|
||||||
[channelId]: channelArray,
|
[channelId]: channelArray,
|
||||||
},
|
})}`;
|
||||||
]);
|
|
||||||
ws.send(text);
|
ws.send(text);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -170,7 +174,7 @@ class SocketServer {
|
||||||
socketEvents.on('remChatChannel', (userId, channelId) => {
|
socketEvents.on('remChatChannel', (userId, channelId) => {
|
||||||
this.findAllWsByUerId(userId).forEach((ws) => {
|
this.findAllWsByUerId(userId).forEach((ws) => {
|
||||||
ws.user.removeChannel(channelId);
|
ws.user.removeChannel(channelId);
|
||||||
const text = JSON.stringify(['remch', channelId]);
|
const text = `rc,${JSON.stringify(channelId)}`;
|
||||||
ws.send(text);
|
ws.send(text);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -348,9 +352,8 @@ class SocketServer {
|
||||||
|
|
||||||
reloadUser(name) {
|
reloadUser(name) {
|
||||||
this.wss.clients.forEach(async (ws) => {
|
this.wss.clients.forEach(async (ws) => {
|
||||||
if (ws.name === name) {
|
if (ws.user.name === name) {
|
||||||
await ws.user.reload();
|
await ws.user.reload();
|
||||||
ws.name = ws.user.getName();
|
|
||||||
const buffer = dehydrateChangeMe();
|
const buffer = dehydrateChangeMe();
|
||||||
ws.send(buffer);
|
ws.send(buffer);
|
||||||
}
|
}
|
||||||
|
@ -419,28 +422,21 @@ class SocketServer {
|
||||||
* chat messages in [message, channelId] format
|
* chat messages in [message, channelId] format
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
let message;
|
const comma = text.indexOf(',');
|
||||||
let channelId;
|
if (comma === -1) {
|
||||||
try {
|
throw new Error('No comma');
|
||||||
const data = JSON.parse(text);
|
|
||||||
[message, channelId] = data;
|
|
||||||
channelId = Number(channelId);
|
|
||||||
if (Number.isNaN(channelId)) {
|
|
||||||
throw new Error('NaN');
|
|
||||||
}
|
}
|
||||||
} catch {
|
const key = text.slice(0, comma);
|
||||||
logger.warn(
|
const val = JSON.parse(text.slice(comma + 1));
|
||||||
`Received unparseable message from ${ws.name} on websocket: ${text}`,
|
const { user } = ws;
|
||||||
);
|
switch (key) {
|
||||||
|
case 'cm': {
|
||||||
|
// chat message
|
||||||
|
const message = val[0].trim();
|
||||||
|
if (!user.isRegistered || !message) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message = message.trim();
|
const channelId = val[1];
|
||||||
|
|
||||||
/*
|
|
||||||
* just if logged in
|
|
||||||
*/
|
|
||||||
if (ws.name && message) {
|
|
||||||
const { user } = ws;
|
|
||||||
/*
|
/*
|
||||||
* if DM channel, make sure that other user has DM open
|
* if DM channel, make sure that other user has DM open
|
||||||
* (needed because we allow user to leave one-sided
|
* (needed because we allow user to leave one-sided
|
||||||
|
@ -459,24 +455,33 @@ class SocketServer {
|
||||||
await ChatProvider.addUserToChannel(
|
await ChatProvider.addUserToChannel(
|
||||||
dmUserId,
|
dmUserId,
|
||||||
channelId,
|
channelId,
|
||||||
[ws.name, 1, Date.now(), user.id],
|
[user.name, 1, Date.now(), user.id],
|
||||||
);
|
);
|
||||||
user.addedDM.push(dmUserId);
|
user.addedDM.push(dmUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* send chat message
|
|
||||||
*/
|
|
||||||
socketEvents.recvChatMessage(user, message, channelId);
|
socketEvents.recvChatMessage(user, message, channelId);
|
||||||
} else {
|
break;
|
||||||
logger.info('Got empty message or message from unidentified ws');
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
case 'cs': {
|
||||||
logger.error('Got invalid ws text message');
|
// captcha solution
|
||||||
logger.error(error.message);
|
const [solution, captchaid] = val;
|
||||||
logger.error(error.stack);
|
const ret = await checkCaptchaSolution(
|
||||||
|
solution,
|
||||||
|
user.ip,
|
||||||
|
false,
|
||||||
|
captchaid,
|
||||||
|
);
|
||||||
|
ws.send(dehydrateCaptchaReturn(ret));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown key');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
logger.error(`Got invalid ws text message ${text}, with error: ${err.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
DEREG_CHUNK_OP,
|
DEREG_CHUNK_OP,
|
||||||
REG_MCHUNKS_OP,
|
REG_MCHUNKS_OP,
|
||||||
DEREG_MCHUNKS_OP,
|
DEREG_MCHUNKS_OP,
|
||||||
CAPTCHA_SOLUTION_OP,
|
|
||||||
PING_OP,
|
PING_OP,
|
||||||
PIXEL_UPDATE_OP,
|
PIXEL_UPDATE_OP,
|
||||||
} from './op';
|
} from './op';
|
||||||
|
@ -70,7 +69,6 @@ export function hydrateCoolDown(data) {
|
||||||
* @return see ui/placePixels
|
* @return see ui/placePixels
|
||||||
*/
|
*/
|
||||||
export function hydratePixelReturn(data) {
|
export function hydratePixelReturn(data) {
|
||||||
// Client (receiver)
|
|
||||||
const retCode = data.getUint8(1);
|
const retCode = data.getUint8(1);
|
||||||
const wait = data.getUint32(2);
|
const wait = data.getUint32(2);
|
||||||
const coolDownSeconds = data.getInt16(6);
|
const coolDownSeconds = data.getInt16(6);
|
||||||
|
@ -85,6 +83,13 @@ export function hydratePixelReturn(data) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return code of captcha success
|
||||||
|
*/
|
||||||
|
export function hydrateCaptchaReturn(data) {
|
||||||
|
return data.getUint8(1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dehydrate functions return ArrayBuffer object
|
* dehydrate functions return ArrayBuffer object
|
||||||
*/
|
*/
|
||||||
|
@ -152,18 +157,6 @@ export function dehydrateDeRegMChunks(chunks) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @param solution string of entered captcha
|
|
||||||
*/
|
|
||||||
export function dehydrateCaptchaSolution(solution) {
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
const view = encoder.encode(solution);
|
|
||||||
const buffer = new Uint8Array(view.byteLength + 1);
|
|
||||||
buffer[0] = CAPTCHA_SOLUTION_OP;
|
|
||||||
buffer.set(view, 1);
|
|
||||||
return buffer.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function dehydratePing() {
|
export function dehydratePing() {
|
||||||
return new Uint8Array([PING_OP]).buffer;
|
return new Uint8Array([PING_OP]).buffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,12 @@ export const REG_CHUNK_OP = 0xA1;
|
||||||
export const DEREG_CHUNK_OP = 0xA2;
|
export const DEREG_CHUNK_OP = 0xA2;
|
||||||
export const REG_MCHUNKS_OP = 0xA3;
|
export const REG_MCHUNKS_OP = 0xA3;
|
||||||
export const DEREG_MCHUNKS_OP = 0xA4;
|
export const DEREG_MCHUNKS_OP = 0xA4;
|
||||||
export const CAPTCHA_SOLUTION_OP = 0xA5;
|
|
||||||
export const CHANGE_ME_OP = 0xA6;
|
export const CHANGE_ME_OP = 0xA6;
|
||||||
export const ONLINE_COUNTER_OP = 0xA7;
|
export const ONLINE_COUNTER_OP = 0xA7;
|
||||||
export const PING_OP = 0xB0;
|
export const PING_OP = 0xB0;
|
||||||
export const PIXEL_UPDATE_OP = 0xC1;
|
export const PIXEL_UPDATE_OP = 0xC1;
|
||||||
export const PIXEL_UPDATE_MB_OP = 0xC1;
|
|
||||||
export const COOLDOWN_OP = 0xC2;
|
export const COOLDOWN_OP = 0xC2;
|
||||||
export const PIXEL_RETURN_OP = 0xC3;
|
export const PIXEL_RETURN_OP = 0xC3;
|
||||||
export const CHUNK_UPDATE_MB_OP = 0xC4;
|
export const CHUNK_UPDATE_MB_OP = 0xC4;
|
||||||
|
export const PIXEL_UPDATE_MB_OP = 0xC5;
|
||||||
|
export const CAPTCHA_RETURN_OP = 0xC6;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
COOLDOWN_OP,
|
COOLDOWN_OP,
|
||||||
PIXEL_RETURN_OP,
|
PIXEL_RETURN_OP,
|
||||||
CHUNK_UPDATE_MB_OP,
|
CHUNK_UPDATE_MB_OP,
|
||||||
|
CAPTCHA_RETURN_OP,
|
||||||
} from './op';
|
} from './op';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -80,13 +81,6 @@ export function hydrateDeRegMChunks(data, cb) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @return captcha solution
|
|
||||||
*/
|
|
||||||
export function hydrateCaptchaSolution(data) {
|
|
||||||
return data.toString('utf8', 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @return chunk id and array of pixel offset and color
|
* @return chunk id and array of pixel offset and color
|
||||||
*/
|
*/
|
||||||
|
@ -225,6 +219,10 @@ export function dehydratePixelReturn(
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function dehydrateCaptchaReturn(retCode) {
|
||||||
|
return Buffer.from([CAPTCHA_RETURN_OP, retCode]);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @param canvasId
|
* @param canvasId
|
||||||
* @param Array with chunk coordinates
|
* @param Array with chunk coordinates
|
||||||
|
|
|
@ -250,15 +250,6 @@ export function receiveBigChunkFailure(center, error) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function receiveCoolDown(
|
|
||||||
wait,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'REC_COOLDOWN',
|
|
||||||
wait,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function receiveMe(
|
export function receiveMe(
|
||||||
me,
|
me,
|
||||||
) {
|
) {
|
||||||
|
@ -296,13 +287,6 @@ export function receiveStats(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function receiveOnline(online) {
|
|
||||||
return {
|
|
||||||
type: 'REC_ONLINE',
|
|
||||||
online,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sendChatMessage(
|
export function sendChatMessage(
|
||||||
text,
|
text,
|
||||||
channel,
|
channel,
|
||||||
|
@ -314,27 +298,6 @@ export function sendChatMessage(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function receiveChatMessage(
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channel,
|
|
||||||
user,
|
|
||||||
isPing,
|
|
||||||
isRead,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 's/REC_CHAT_MESSAGE',
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channel,
|
|
||||||
user,
|
|
||||||
isPing,
|
|
||||||
isRead,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check socket/packets/PixelReturn.js for args
|
* check socket/packets/PixelReturn.js for args
|
||||||
*/
|
*/
|
||||||
|
@ -445,13 +408,6 @@ export function initTimer() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addChatChannel(channel) {
|
|
||||||
return {
|
|
||||||
type: 's/ADD_CHAT_CHANNEL',
|
|
||||||
channel,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function blockUser(userId, userName) {
|
export function blockUser(userId, userName) {
|
||||||
return {
|
return {
|
||||||
type: 's/BLOCK_USER',
|
type: 's/BLOCK_USER',
|
||||||
|
@ -482,13 +438,6 @@ export function privatize(priv) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeChatChannel(cid) {
|
|
||||||
return {
|
|
||||||
type: 's/REMOVE_CHAT_CHANNEL',
|
|
||||||
cid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function muteChatChannel(cid) {
|
export function muteChatChannel(cid) {
|
||||||
return {
|
return {
|
||||||
type: 's/MUTE_CHAT_CHANNEL',
|
type: 's/MUTE_CHAT_CHANNEL',
|
||||||
|
|
74
src/store/actions/socket.js
Normal file
74
src/store/actions/socket.js
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* actions that are fired when received by the websocket
|
||||||
|
*/
|
||||||
|
export function socketClose() {
|
||||||
|
return {
|
||||||
|
type: 'w/CLOSE',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function socketOpen() {
|
||||||
|
return {
|
||||||
|
type: 'w/OPEN',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function receiveChatMessage(
|
||||||
|
name,
|
||||||
|
text,
|
||||||
|
country,
|
||||||
|
channel,
|
||||||
|
user,
|
||||||
|
) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
channel = Number(channel);
|
||||||
|
const state = getState();
|
||||||
|
const isRead = state.windows.showWindows
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
&& state.windows.windows.find((win) => win.windowType === 'CHAT' && !win.hidden)
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
&& Object.values(state.windows.args).find((args) => args.chatChannel === channel);
|
||||||
|
|
||||||
|
// TODO ping doesn't work since update
|
||||||
|
// const { nameRegExp } = state.user;
|
||||||
|
// const isPing = (nameRegExp && text.match(nameRegExp));
|
||||||
|
dispatch({
|
||||||
|
type: 's/REC_CHAT_MESSAGE',
|
||||||
|
name,
|
||||||
|
text,
|
||||||
|
country,
|
||||||
|
channel,
|
||||||
|
user,
|
||||||
|
isPing: false,
|
||||||
|
isRead: !!isRead,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function receiveCoolDown(wait) {
|
||||||
|
return {
|
||||||
|
type: 'REC_COOLDOWN',
|
||||||
|
wait,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function receiveOnline(online) {
|
||||||
|
return {
|
||||||
|
type: 'REC_ONLINE',
|
||||||
|
online,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addChatChannel(channel) {
|
||||||
|
return {
|
||||||
|
type: 's/ADD_CHAT_CHANNEL',
|
||||||
|
channel,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeChatChannel(cid) {
|
||||||
|
return {
|
||||||
|
type: 's/REMOVE_CHAT_CHANNEL',
|
||||||
|
cid,
|
||||||
|
};
|
||||||
|
}
|
|
@ -11,9 +11,7 @@ import {
|
||||||
requestChatMessages,
|
requestChatMessages,
|
||||||
requestMe,
|
requestMe,
|
||||||
} from './fetch';
|
} from './fetch';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addChatChannel,
|
|
||||||
pAlert,
|
pAlert,
|
||||||
receiveStats,
|
receiveStats,
|
||||||
receiveMe,
|
receiveMe,
|
||||||
|
@ -21,8 +19,11 @@ import {
|
||||||
unblockUser,
|
unblockUser,
|
||||||
blockingDm,
|
blockingDm,
|
||||||
privatize,
|
privatize,
|
||||||
removeChatChannel,
|
|
||||||
} from './index';
|
} from './index';
|
||||||
|
import {
|
||||||
|
addChatChannel,
|
||||||
|
removeChatChannel,
|
||||||
|
} from './socket';
|
||||||
|
|
||||||
function setApiFetching(fetching) {
|
function setApiFetching(fetching) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -48,10 +48,7 @@ export default (store) => (next) => (action) => {
|
||||||
const ret = next(action);
|
const ret = next(action);
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const { canvasId } = state.canvas;
|
const { canvasId } = state.canvas;
|
||||||
if (prevState.canvas.canvasId === canvasId) {
|
if (prevState.canvas.canvasId !== canvasId) {
|
||||||
// TODO see if this is the case anywhere
|
|
||||||
console.log('Not triggering change canvas');
|
|
||||||
} else {
|
|
||||||
SocketClient.setCanvas(canvasId);
|
SocketClient.setCanvas(canvasId);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
export type CanvasState = {
|
export type CanvasState = {
|
||||||
canvasId: number,
|
canvasId: string,
|
||||||
canvasIdent: string,
|
canvasIdent: string,
|
||||||
selectedColor: number,
|
selectedColor: number,
|
||||||
is3D: boolean,
|
is3D: boolean,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user