refactor websocket packets
This commit is contained in:
parent
693a403460
commit
7a2053fda3
|
@ -114,7 +114,7 @@ persistStore(store, {}, () => {
|
||||||
store.dispatch(initTimer());
|
store.dispatch(initTimer());
|
||||||
|
|
||||||
store.dispatch(fetchMe());
|
store.dispatch(fetchMe());
|
||||||
SocketClient.connect();
|
SocketClient.initialize(store);
|
||||||
});
|
});
|
||||||
|
|
||||||
(function load() {
|
(function load() {
|
||||||
|
|
|
@ -23,7 +23,7 @@ const GlobalCaptcha = ({ close }) => {
|
||||||
<form
|
<form
|
||||||
onSubmit={async (e) => {
|
onSubmit={async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const text = e.target.captcha.value;
|
const text = e.target.captcha.value.slice(0, 6);
|
||||||
if (!text || text.length < 4) {
|
if (!text || text.length < 4) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import socketEvents from '../socket/socketEvents';
|
import socketEvents from '../socket/socketEvents';
|
||||||
import PixelUpdate from '../socket/packets/PixelUpdateServer';
|
import {
|
||||||
|
hydratePixelUpdate,
|
||||||
|
} from '../socket/packets/server';
|
||||||
import { setPixelByOffset } from './setPixel';
|
import { setPixelByOffset } from './setPixel';
|
||||||
import { TILE_SIZE } from './constants';
|
import { TILE_SIZE } from './constants';
|
||||||
import { CANVAS_ID } from '../data/redis/Event';
|
import { CANVAS_ID } from '../data/redis/Event';
|
||||||
|
@ -177,7 +179,7 @@ class Void {
|
||||||
i: pi,
|
i: pi,
|
||||||
j: pj,
|
j: pj,
|
||||||
pixels,
|
pixels,
|
||||||
} = PixelUpdate.hydrate(buffer);
|
} = hydratePixelUpdate(buffer);
|
||||||
const { i, j } = this;
|
const { i, j } = this;
|
||||||
// 3x3 chunk area (this is hardcoded on multiple places)
|
// 3x3 chunk area (this is hardcoded on multiple places)
|
||||||
if (pi >= i - 1 && pi <= i + 1 && pj >= j - 1 && pj <= j + 1) {
|
if (pi >= i - 1 && pi <= i + 1 && pj >= j - 1 && pj <= j + 1) {
|
||||||
|
|
|
@ -69,7 +69,7 @@ persistStore(store, {}, () => {
|
||||||
|
|
||||||
if (!parentExists()) {
|
if (!parentExists()) {
|
||||||
store.dispatch(fetchMe());
|
store.dispatch(fetchMe());
|
||||||
SocketClient.connect();
|
SocketClient.initialize(store);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,20 @@
|
||||||
|
|
||||||
import { SHARD_NAME } from '../core/config';
|
import { SHARD_NAME } from '../core/config';
|
||||||
import SocketEvents from './SockEvents';
|
import SocketEvents from './SockEvents';
|
||||||
import OnlineCounter from './packets/OnlineCounter';
|
import {
|
||||||
import PixelUpdate from './packets/PixelUpdateServer';
|
ONLINE_COUNTER_OP,
|
||||||
import PixelUpdateMB from './packets/PixelUpdateMB';
|
PIXEL_UPDATE_MB_OP,
|
||||||
import ChunkUpdate from './packets/ChunkUpdate';
|
CHUNK_UPDATE_MB_OP,
|
||||||
|
} from './packets/op';
|
||||||
|
import {
|
||||||
|
hydrateOnlineCounter,
|
||||||
|
hydratePixelUpdateMB,
|
||||||
|
hydrateChunkUpdateMB,
|
||||||
|
dehydratePixelUpdate,
|
||||||
|
dehydrateOnlineCounter,
|
||||||
|
dehydratePixelUpdateMB,
|
||||||
|
dehydrateChunkUpdateMB,
|
||||||
|
} from './packets/server';
|
||||||
import { pubsub } from '../data/redis/client';
|
import { pubsub } from '../data/redis/client';
|
||||||
import { combineObjects } from '../core/utils';
|
import { combineObjects } from '../core/utils';
|
||||||
|
|
||||||
|
@ -253,25 +263,25 @@ class MessageBroker extends SocketEvents {
|
||||||
try {
|
try {
|
||||||
const opcode = buffer[0];
|
const opcode = buffer[0];
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case PixelUpdateMB.OP_CODE: {
|
case PIXEL_UPDATE_MB_OP: {
|
||||||
const puData = PixelUpdateMB.hydrate(buffer);
|
const puData = hydratePixelUpdateMB(buffer);
|
||||||
super.emit('pixelUpdate', ...puData);
|
super.emit('pixelUpdate', ...puData);
|
||||||
const chunkId = puData[1];
|
const chunkId = puData[1];
|
||||||
const chunk = [chunkId >> 8, chunkId & 0xFF];
|
const chunk = [chunkId >> 8, chunkId & 0xFF];
|
||||||
super.emit('chunkUpdate', puData[0], chunk);
|
super.emit('chunkUpdate', puData[0], chunk);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ChunkUpdate.OP_CODE: {
|
case CHUNK_UPDATE_MB_OP: {
|
||||||
super.emit('chunkUpdate', ...ChunkUpdate.hydrate(buffer));
|
super.emit('chunkUpdate', ...hydrateChunkUpdateMB(buffer));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OnlineCounter.OP_CODE: {
|
case ONLINE_COUNTER_OP: {
|
||||||
const data = new DataView(
|
const data = new DataView(
|
||||||
buffer.buffer,
|
buffer.buffer,
|
||||||
buffer.byteOffset,
|
buffer.byteOffset,
|
||||||
buffer.length,
|
buffer.length,
|
||||||
);
|
);
|
||||||
const cnt = OnlineCounter.hydrate(data);
|
const cnt = hydrateOnlineCounter(data);
|
||||||
this.updateShardOnlineCounter(shard, cnt);
|
this.updateShardOnlineCounter(shard, cnt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -324,9 +334,9 @@ class MessageBroker extends SocketEvents {
|
||||||
const j = chunkId & 0xFF;
|
const j = chunkId & 0xFF;
|
||||||
this.publisher.publish(
|
this.publisher.publish(
|
||||||
this.thisShard,
|
this.thisShard,
|
||||||
PixelUpdateMB.dehydrate(canvasId, i, j, pixels),
|
dehydratePixelUpdateMB(canvasId, i, j, pixels),
|
||||||
);
|
);
|
||||||
const buffer = PixelUpdate.dehydrate(i, j, pixels);
|
const buffer = dehydratePixelUpdate(i, j, pixels);
|
||||||
super.emit('pixelUpdate', canvasId, chunkId, buffer);
|
super.emit('pixelUpdate', canvasId, chunkId, buffer);
|
||||||
super.emit('chunkUpdate', canvasId, [i, j]);
|
super.emit('chunkUpdate', canvasId, [i, j]);
|
||||||
}
|
}
|
||||||
|
@ -353,18 +363,18 @@ class MessageBroker extends SocketEvents {
|
||||||
) {
|
) {
|
||||||
this.publisher.publish(
|
this.publisher.publish(
|
||||||
this.thisShard,
|
this.thisShard,
|
||||||
ChunkUpdate.dehydrate(canvasId, chunk),
|
dehydrateChunkUpdateMB(canvasId, chunk),
|
||||||
);
|
);
|
||||||
super.emit('chunkUpdate', canvasId, chunk);
|
super.emit('chunkUpdate', canvasId, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastOnlineCounter(online) {
|
broadcastOnlineCounter(online) {
|
||||||
this.updateShardOnlineCounter(this.thisShard, online);
|
this.updateShardOnlineCounter(this.thisShard, online);
|
||||||
let buffer = OnlineCounter.dehydrate(online);
|
|
||||||
// send our online counter to other shards
|
// send our online counter to other shards
|
||||||
|
let 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 = OnlineCounter.dehydrate(this.onlineCounter);
|
buffer = dehydrateOnlineCounter(this.onlineCounter);
|
||||||
super.emit('onlineCounter', buffer);
|
super.emit('onlineCounter', buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
*/
|
*/
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
import OnlineCounter from './packets/OnlineCounter';
|
import {
|
||||||
import PixelUpdate from './packets/PixelUpdateServer';
|
dehydrateOnlineCounter,
|
||||||
|
dehydratePixelUpdate,
|
||||||
|
} from './packets/server';
|
||||||
|
|
||||||
class SocketEvents extends EventEmitter {
|
class SocketEvents extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -97,7 +98,7 @@ class SocketEvents extends EventEmitter {
|
||||||
) {
|
) {
|
||||||
const i = chunkId >> 8;
|
const i = chunkId >> 8;
|
||||||
const j = chunkId & 0xFF;
|
const j = chunkId & 0xFF;
|
||||||
const buffer = PixelUpdate.dehydrate(i, j, pixels);
|
const buffer = dehydratePixelUpdate(i, j, pixels);
|
||||||
this.emit('pixelUpdate', canvasId, chunkId, buffer);
|
this.emit('pixelUpdate', canvasId, chunkId, buffer);
|
||||||
this.emit('chunkUpdate', canvasId, [i, j]);
|
this.emit('chunkUpdate', canvasId, [i, j]);
|
||||||
}
|
}
|
||||||
|
@ -254,7 +255,7 @@ class SocketEvents extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
broadcastOnlineCounter(online) {
|
broadcastOnlineCounter(online) {
|
||||||
this.onlineCounter = online;
|
this.onlineCounter = online;
|
||||||
const buffer = OnlineCounter.dehydrate(online);
|
const buffer = dehydrateOnlineCounter(online);
|
||||||
this.emit('onlineCounter', buffer);
|
this.emit('onlineCounter', buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
|
|
||||||
// allow the websocket to be noisy on the console
|
// allow the websocket to be noisy on the console
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
import CoolDownPacket from './packets/CoolDownPacket';
|
import {
|
||||||
import PixelUpdate from './packets/PixelUpdateClient';
|
hydratePixelUpdate,
|
||||||
import PixelReturn from './packets/PixelReturn';
|
hydratePixelReturn,
|
||||||
import OnlineCounter from './packets/OnlineCounter';
|
hydrateOnlineCounter,
|
||||||
import RegisterCanvas from './packets/RegisterCanvas';
|
hydrateCoolDown,
|
||||||
import RegisterChunk from './packets/RegisterChunk';
|
dehydrateRegCanvas,
|
||||||
import RegisterMultipleChunks from './packets/RegisterMultipleChunks';
|
dehydrateRegChunk,
|
||||||
import DeRegisterChunk from './packets/DeRegisterChunk';
|
dehydrateRegMChunks,
|
||||||
import ChangedMe from './packets/ChangedMe';
|
dehydrateDeRegChunk,
|
||||||
import Ping from './packets/Ping';
|
dehydrateCaptchaSolution,
|
||||||
|
dehydratePixelUpdate,
|
||||||
|
dehydratePing,
|
||||||
|
} from './packets/client';
|
||||||
|
import {
|
||||||
|
PIXEL_UPDATE_OP,
|
||||||
|
PIXEL_RETURN_OP,
|
||||||
|
ONLINE_COUNTER_OP,
|
||||||
|
COOLDOWN_OP,
|
||||||
|
CHANGE_ME_OP,
|
||||||
|
} from './packets/op';
|
||||||
import { shardHost } from '../store/actions/fetch';
|
import { shardHost } from '../store/actions/fetch';
|
||||||
|
|
||||||
const chunks = [];
|
const chunks = [];
|
||||||
|
@ -22,8 +31,8 @@ class SocketClient extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
console.log('Creating WebSocketClient');
|
console.log('Creating WebSocketClient');
|
||||||
|
this.store = null;
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
this.canvasId = 0;
|
|
||||||
this.channelId = 0;
|
this.channelId = 0;
|
||||||
/*
|
/*
|
||||||
* properties set in connect and open:
|
* properties set in connect and open:
|
||||||
|
@ -38,6 +47,11 @@ class SocketClient extends EventEmitter {
|
||||||
setInterval(this.checkHealth, 2000);
|
setInterval(this.checkHealth, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialize(store) {
|
||||||
|
this.store = store;
|
||||||
|
return this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
async connect() {
|
async connect() {
|
||||||
this.readyState = WebSocket.CONNECTING;
|
this.readyState = WebSocket.CONNECTING;
|
||||||
if (this.ws) {
|
if (this.ws) {
|
||||||
|
@ -70,7 +84,7 @@ class SocketClient extends EventEmitter {
|
||||||
}
|
}
|
||||||
if (now - 23000 > this.timeLastSent) {
|
if (now - 23000 > this.timeLastSent) {
|
||||||
// make sure we send something at least all 25s
|
// make sure we send something at least all 25s
|
||||||
this.send(Ping.dehydrate());
|
this.send(dehydratePing());
|
||||||
this.timeLastSent = now;
|
this.timeLastSent = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,31 +124,28 @@ class SocketClient extends EventEmitter {
|
||||||
|
|
||||||
this.emit('open', {});
|
this.emit('open', {});
|
||||||
this.readyState = WebSocket.OPEN;
|
this.readyState = WebSocket.OPEN;
|
||||||
this.send(RegisterCanvas.dehydrate(this.canvasId));
|
this.send(dehydrateRegCanvas(
|
||||||
|
this.store.getState().canvas,
|
||||||
|
));
|
||||||
console.log(`Register ${chunks.length} chunks`);
|
console.log(`Register ${chunks.length} chunks`);
|
||||||
this.send(RegisterMultipleChunks.dehydrate(chunks));
|
this.send(dehydrateRegMChunks(chunks));
|
||||||
this.processMsgQueue();
|
this.processMsgQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
setCanvas(canvasId) {
|
setCanvas(canvasId) {
|
||||||
/* canvasId can be string or integer, thanks to
|
if (canvasId === null) {
|
||||||
* JSON not allowing integer keys
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line eqeqeq
|
|
||||||
if (this.canvasId == canvasId || canvasId === null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('Notify websocket server that we changed canvas');
|
console.log('Notify websocket server that we changed canvas');
|
||||||
this.canvasId = canvasId;
|
|
||||||
chunks.length = 0;
|
chunks.length = 0;
|
||||||
this.send(RegisterCanvas.dehydrate(this.canvasId));
|
this.send(dehydrateRegCanvas(canvasId));
|
||||||
}
|
}
|
||||||
|
|
||||||
registerChunk(cell) {
|
registerChunk(cell) {
|
||||||
const [i, j] = cell;
|
const [i, j] = cell;
|
||||||
const chunkid = (i << 8) | j;
|
const chunkid = (i << 8) | j;
|
||||||
chunks.push(chunkid);
|
chunks.push(chunkid);
|
||||||
const buffer = RegisterChunk.dehydrate(chunkid);
|
const buffer = dehydrateRegChunk(chunkid);
|
||||||
if (this.readyState === WebSocket.OPEN) {
|
if (this.readyState === WebSocket.OPEN) {
|
||||||
this.send(buffer);
|
this.send(buffer);
|
||||||
}
|
}
|
||||||
|
@ -143,7 +154,7 @@ class SocketClient extends EventEmitter {
|
||||||
deRegisterChunk(cell) {
|
deRegisterChunk(cell) {
|
||||||
const [i, j] = cell;
|
const [i, j] = cell;
|
||||||
const chunkid = (i << 8) | j;
|
const chunkid = (i << 8) | j;
|
||||||
const buffer = DeRegisterChunk.dehydrate(chunkid);
|
const buffer = dehydrateDeRegChunk(chunkid);
|
||||||
if (this.readyState === WebSocket.OPEN) {
|
if (this.readyState === WebSocket.OPEN) {
|
||||||
this.send(buffer);
|
this.send(buffer);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +162,12 @@ class SocketClient extends EventEmitter {
|
||||||
if (~pos) chunks.splice(pos, 1);
|
if (~pos) chunks.splice(pos, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
sendCaptchaSolution(solution) {
|
||||||
|
const buffer = dehydrateCaptchaSolution(solution);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send pixel request
|
* Send pixel request
|
||||||
* @param i, j chunk coordinates
|
* @param i, j chunk coordinates
|
||||||
|
@ -160,7 +177,7 @@ class SocketClient extends EventEmitter {
|
||||||
i, j,
|
i, j,
|
||||||
pixels,
|
pixels,
|
||||||
) {
|
) {
|
||||||
const buffer = PixelUpdate.dehydrate(i, j, pixels);
|
const buffer = dehydratePixelUpdate(i, j, pixels);
|
||||||
this.sendWhenReady(buffer);
|
this.sendWhenReady(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +213,6 @@ class SocketClient extends EventEmitter {
|
||||||
name, text, country, Number(channelId), userId);
|
name, text, country, Number(channelId), userId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
// signal
|
// signal
|
||||||
const [signal, args] = data;
|
const [signal, args] = data;
|
||||||
|
@ -217,19 +233,19 @@ class SocketClient extends EventEmitter {
|
||||||
this.timeLastPing = Date.now();
|
this.timeLastPing = Date.now();
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case PixelUpdate.OP_CODE:
|
case PIXEL_UPDATE_OP:
|
||||||
this.emit('pixelUpdate', PixelUpdate.hydrate(data));
|
this.emit('pixelUpdate', hydratePixelUpdate(data));
|
||||||
break;
|
break;
|
||||||
case PixelReturn.OP_CODE:
|
case PIXEL_RETURN_OP:
|
||||||
this.emit('pixelReturn', PixelReturn.hydrate(data));
|
this.emit('pixelReturn', hydratePixelReturn(data));
|
||||||
break;
|
break;
|
||||||
case OnlineCounter.OP_CODE:
|
case ONLINE_COUNTER_OP:
|
||||||
this.emit('onlineCounter', OnlineCounter.hydrate(data));
|
this.emit('onlineCounter', hydrateOnlineCounter(data));
|
||||||
break;
|
break;
|
||||||
case CoolDownPacket.OP_CODE:
|
case COOLDOWN_OP:
|
||||||
this.emit('cooldownPacket', CoolDownPacket.hydrate(data));
|
this.emit('cooldownPacket', hydrateCoolDown(data));
|
||||||
break;
|
break;
|
||||||
case ChangedMe.OP_CODE:
|
case CHANGE_ME_OP:
|
||||||
console.log('Websocket requested api/me reload');
|
console.log('Websocket requested api/me reload');
|
||||||
this.emit('changedMe');
|
this.emit('changedMe');
|
||||||
this.reconnect();
|
this.reconnect();
|
||||||
|
|
|
@ -7,18 +7,28 @@ import logger from '../core/logger';
|
||||||
import canvases from '../core/canvases';
|
import canvases from '../core/canvases';
|
||||||
import Counter from '../utils/Counter';
|
import Counter from '../utils/Counter';
|
||||||
import { getIPFromRequest, getHostFromRequest } from '../utils/ip';
|
import { getIPFromRequest, getHostFromRequest } from '../utils/ip';
|
||||||
|
import {
|
||||||
import CoolDownPacket from './packets/CoolDownPacket';
|
REG_CANVAS_OP,
|
||||||
import PixelUpdate from './packets/PixelUpdateServer';
|
PIXEL_UPDATE_OP,
|
||||||
import PixelReturn from './packets/PixelReturn';
|
REG_CHUNK_OP,
|
||||||
import RegisterCanvas from './packets/RegisterCanvas';
|
REG_MCHUNKS_OP,
|
||||||
import RegisterChunk from './packets/RegisterChunk';
|
DEREG_CHUNK_OP,
|
||||||
import RegisterMultipleChunks from './packets/RegisterMultipleChunks';
|
DEREG_MCHUNKS_OP,
|
||||||
import DeRegisterChunk from './packets/DeRegisterChunk';
|
} from './packets/op';
|
||||||
import DeRegisterMultipleChunks from './packets/DeRegisterMultipleChunks';
|
import {
|
||||||
import ChangedMe from './packets/ChangedMe';
|
hydrateRegCanvas,
|
||||||
import OnlineCounter from './packets/OnlineCounter';
|
hydrateRegChunk,
|
||||||
|
hydrateDeRegChunk,
|
||||||
|
hydrateRegMChunks,
|
||||||
|
hydrateDeRegMChunks,
|
||||||
|
hydrateCaptchaSolution,
|
||||||
|
hydratePixelUpdate,
|
||||||
|
dehydrateChangeMe,
|
||||||
|
dehydrateOnlineCounter,
|
||||||
|
dehydratePixelUpdate,
|
||||||
|
dehydrateCoolDown,
|
||||||
|
dehydratePixelReturn,
|
||||||
|
} 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';
|
||||||
|
@ -88,7 +98,7 @@ class SocketServer {
|
||||||
|
|
||||||
const { ip } = user;
|
const { ip } = user;
|
||||||
|
|
||||||
ws.send(OnlineCounter.dehydrate(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}`);
|
logger.error(`WebSocket Client Error for ${ws.name}: ${e.message}`);
|
||||||
|
@ -341,7 +351,7 @@ class SocketServer {
|
||||||
if (ws.name === name) {
|
if (ws.name === name) {
|
||||||
await ws.user.reload();
|
await ws.user.reload();
|
||||||
ws.name = ws.user.getName();
|
ws.name = ws.user.getName();
|
||||||
const buffer = ChangedMe.dehydrate();
|
const buffer = dehydrateChangeMe();
|
||||||
ws.send(buffer);
|
ws.send(buffer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -474,7 +484,7 @@ class SocketServer {
|
||||||
try {
|
try {
|
||||||
const opcode = buffer[0];
|
const opcode = buffer[0];
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case PixelUpdate.OP_CODE: {
|
case PIXEL_UPDATE_OP: {
|
||||||
const { canvasId, user } = ws;
|
const { canvasId, user } = ws;
|
||||||
const { ip } = user;
|
const { ip } = user;
|
||||||
|
|
||||||
|
@ -499,7 +509,7 @@ class SocketServer {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
i, j, pixels,
|
i, j, pixels,
|
||||||
} = PixelUpdate.hydrate(buffer);
|
} = hydratePixelUpdate(buffer);
|
||||||
const {
|
const {
|
||||||
wait,
|
wait,
|
||||||
coolDown,
|
coolDown,
|
||||||
|
@ -522,7 +532,7 @@ class SocketServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.send(PixelReturn.dehydrate(
|
ws.send(dehydratePixelReturn(
|
||||||
retCode,
|
retCode,
|
||||||
wait,
|
wait,
|
||||||
coolDown,
|
coolDown,
|
||||||
|
@ -531,42 +541,38 @@ class SocketServer {
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RegisterCanvas.OP_CODE: {
|
case REG_CANVAS_OP: {
|
||||||
const canvasId = RegisterCanvas.hydrate(buffer);
|
const canvasId = hydrateRegCanvas(buffer);
|
||||||
if (!canvases[canvasId]) return;
|
if (!canvases[canvasId]) return;
|
||||||
if (ws.canvasId !== null && ws.canvasId !== canvasId) {
|
if (ws.canvasId !== null && ws.canvasId !== canvasId) {
|
||||||
this.deleteAllChunks(ws);
|
this.deleteAllChunks(ws);
|
||||||
}
|
}
|
||||||
ws.canvasId = canvasId;
|
ws.canvasId = canvasId;
|
||||||
const wait = await ws.user.getWait(canvasId);
|
const wait = await ws.user.getWait(canvasId);
|
||||||
ws.send(CoolDownPacket.dehydrate(wait));
|
ws.send(dehydrateCoolDown(wait));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RegisterChunk.OP_CODE: {
|
case REG_CHUNK_OP: {
|
||||||
const chunkid = RegisterChunk.hydrate(buffer);
|
const chunkid = hydrateRegChunk(buffer);
|
||||||
this.pushChunk(chunkid, ws);
|
this.pushChunk(chunkid, ws);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RegisterMultipleChunks.OP_CODE: {
|
case REG_MCHUNKS_OP: {
|
||||||
this.deleteAllChunks(ws);
|
this.deleteAllChunks(ws);
|
||||||
let posu = 2;
|
hydrateRegMChunks(buffer, (chunkid) => {
|
||||||
while (posu < buffer.length) {
|
|
||||||
const chunkid = buffer[posu++] | buffer[posu++] << 8;
|
|
||||||
this.pushChunk(chunkid, ws);
|
this.pushChunk(chunkid, ws);
|
||||||
}
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DeRegisterChunk.OP_CODE: {
|
case DEREG_CHUNK_OP: {
|
||||||
const chunkidn = DeRegisterChunk.hydrate(buffer);
|
const chunkid = hydrateDeRegChunk(buffer);
|
||||||
this.deleteChunk(chunkidn, ws);
|
this.deleteChunk(chunkid, ws);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DeRegisterMultipleChunks.OP_CODE: {
|
case DEREG_MCHUNKS_OP: {
|
||||||
let posl = 2;
|
hydrateDeRegMChunks(buffer, (chunkid) => {
|
||||||
while (posl < buffer.length) {
|
|
||||||
const chunkid = buffer[posl++] | buffer[posl++] << 8;
|
|
||||||
this.deleteChunk(chunkid, ws);
|
this.deleteChunk(chunkid, ws);
|
||||||
}
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
const OP_CODE = 0xA6;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
|
|
||||||
dehydrate() {
|
|
||||||
// Server (sender)
|
|
||||||
return new Uint8Array([OP_CODE]).buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* notify that chunk changed
|
|
||||||
* (not sent over websocket, server only)
|
|
||||||
*/
|
|
||||||
|
|
||||||
const OP_CODE = 0xC4;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
/*
|
|
||||||
* @return canvasId, [i, j]
|
|
||||||
*/
|
|
||||||
hydrate(data) {
|
|
||||||
const canvasId = data[1];
|
|
||||||
const i = data.readUInt8(2);
|
|
||||||
const j = data.readUInt8(3);
|
|
||||||
return [canvasId, [i, j]];
|
|
||||||
},
|
|
||||||
/*
|
|
||||||
* @param canvasId,
|
|
||||||
* chunkid id consisting of chunk coordinates
|
|
||||||
*/
|
|
||||||
dehydrate(canvasId, [i, j]) {
|
|
||||||
return Buffer.from([
|
|
||||||
OP_CODE,
|
|
||||||
canvasId,
|
|
||||||
i,
|
|
||||||
j,
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,16 +0,0 @@
|
||||||
const OP_CODE = 0xC2;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
hydrate(data) {
|
|
||||||
// client (receiver)
|
|
||||||
return data.getUint32(1);
|
|
||||||
},
|
|
||||||
dehydrate(wait) {
|
|
||||||
// Server (sender)
|
|
||||||
const buffer = Buffer.allocUnsafe(1 + 4);
|
|
||||||
buffer.writeUInt8(OP_CODE, 0);
|
|
||||||
buffer.writeUInt32BE(wait, 1);
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,18 +0,0 @@
|
||||||
const OP_CODE = 0xA2;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
hydrate(data) {
|
|
||||||
// SERVER (Receiver)
|
|
||||||
const i = data[1] << 8 | data[2];
|
|
||||||
return i;
|
|
||||||
},
|
|
||||||
dehydrate(chunkid) {
|
|
||||||
// CLIENT (Sender)
|
|
||||||
const buffer = new ArrayBuffer(1 + 2);
|
|
||||||
const view = new DataView(buffer);
|
|
||||||
view.setInt8(0, OP_CODE);
|
|
||||||
view.setInt16(1, chunkid);
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,20 +0,0 @@
|
||||||
const OP_CODE = 0xA4;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
/*
|
|
||||||
* @param chunks Array of chunks
|
|
||||||
*/
|
|
||||||
dehydrate(chunks) {
|
|
||||||
// CLIENT (Sender)
|
|
||||||
const buffer = new ArrayBuffer(1 + 1 + chunks.length * 2);
|
|
||||||
const view = new Uint16Array(buffer);
|
|
||||||
// this will result into a double first byte, but still better than
|
|
||||||
// shifting 16bit integers around later
|
|
||||||
view[0] = OP_CODE;
|
|
||||||
for (let cnt = 0; cnt < chunks.length; cnt += 1) {
|
|
||||||
view[cnt + 1] = chunks[cnt];
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Numbers of online players per canvas
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
const OP_CODE = 0xA7;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
// CLIENT (receiver)
|
|
||||||
/*
|
|
||||||
* {
|
|
||||||
* total: totalOnline,
|
|
||||||
* canvasId: online,
|
|
||||||
* ....
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
hydrate(data) {
|
|
||||||
const online = {};
|
|
||||||
online.total = data.getUint16(1);
|
|
||||||
let off = data.byteLength;
|
|
||||||
while (off > 3) {
|
|
||||||
const onlineUsers = data.getUint16(off -= 2);
|
|
||||||
const canvas = data.getUint8(off -= 1);
|
|
||||||
online[canvas] = onlineUsers;
|
|
||||||
}
|
|
||||||
return online;
|
|
||||||
},
|
|
||||||
|
|
||||||
dehydrate(online) {
|
|
||||||
// SERVER (sender)
|
|
||||||
if (!process.env.BROWSER) {
|
|
||||||
const canvasIds = Object.keys(online).filter((id) => id !== 'total');
|
|
||||||
|
|
||||||
const buffer = Buffer.allocUnsafe(3 + canvasIds.length * (1 + 2));
|
|
||||||
buffer.writeUInt8(OP_CODE, 0);
|
|
||||||
buffer.writeUInt16BE(online.total, 1);
|
|
||||||
let cnt = 1;
|
|
||||||
for (let p = 0; p < canvasIds.length; p += 1) {
|
|
||||||
const canvasId = canvasIds[p];
|
|
||||||
const onlineUsers = online[canvasId];
|
|
||||||
buffer.writeUInt8(Number(canvasId), cnt += 2);
|
|
||||||
buffer.writeUInt16BE(onlineUsers, cnt += 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
const OP_CODE = 0xB0;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
|
|
||||||
dehydrate() {
|
|
||||||
// Client (sender)
|
|
||||||
return new Uint8Array([OP_CODE]).buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,38 +0,0 @@
|
||||||
const OP_CODE = 0xC3;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
hydrate(data) {
|
|
||||||
// Client (receiver)
|
|
||||||
const retCode = data.getUint8(1);
|
|
||||||
const wait = data.getUint32(2);
|
|
||||||
const coolDownSeconds = data.getInt16(6);
|
|
||||||
const pxlCnt = data.getUint8(8);
|
|
||||||
const rankedPxlCnt = data.getUint8(9);
|
|
||||||
return {
|
|
||||||
retCode,
|
|
||||||
wait,
|
|
||||||
coolDownSeconds,
|
|
||||||
pxlCnt,
|
|
||||||
rankedPxlCnt,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
dehydrate(
|
|
||||||
retCode,
|
|
||||||
wait,
|
|
||||||
coolDown,
|
|
||||||
pxlCnt,
|
|
||||||
rankedPxlCnt,
|
|
||||||
) {
|
|
||||||
// Server (sender)
|
|
||||||
const buffer = Buffer.allocUnsafe(1 + 1 + 4 + 2 + 1 + 1);
|
|
||||||
buffer.writeUInt8(OP_CODE, 0);
|
|
||||||
buffer.writeUInt8(retCode, 1);
|
|
||||||
buffer.writeUInt32BE(wait, 2);
|
|
||||||
const coolDownSeconds = Math.round(coolDown / 1000);
|
|
||||||
buffer.writeInt16BE(coolDownSeconds, 6);
|
|
||||||
buffer.writeUInt8(pxlCnt, 8);
|
|
||||||
buffer.writeUInt8(rankedPxlCnt, 9);
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Packet for sending and receiving pixels per chunk
|
|
||||||
* Multiple pixels can be sent at once
|
|
||||||
* Client side
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
const OP_CODE = 0xC1;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
/*
|
|
||||||
* @param data DataVies
|
|
||||||
*/
|
|
||||||
hydrate(data) {
|
|
||||||
/*
|
|
||||||
* chunk coordinates
|
|
||||||
*/
|
|
||||||
const i = data.getUint8(1);
|
|
||||||
const j = data.getUint8(2);
|
|
||||||
/*
|
|
||||||
* offset and color of every pixel
|
|
||||||
* 3 bytes offset
|
|
||||||
* 1 byte color
|
|
||||||
*/
|
|
||||||
const pixels = [];
|
|
||||||
let off = data.byteLength;
|
|
||||||
while (off > 3) {
|
|
||||||
const color = data.getUint8(off -= 1);
|
|
||||||
const offsetL = data.getUint16(off -= 2);
|
|
||||||
const offsetH = data.getUint8(off -= 1) << 16;
|
|
||||||
pixels.push([offsetH | offsetL, color]);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
i, j, pixels,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
dehydrate(i, j, pixels) {
|
|
||||||
const buffer = new ArrayBuffer(1 + 1 + 1 + pixels.length * 4);
|
|
||||||
const view = new DataView(buffer);
|
|
||||||
view.setUint8(0, OP_CODE);
|
|
||||||
/*
|
|
||||||
* chunk coordinates
|
|
||||||
*/
|
|
||||||
view.setUint8(1, i);
|
|
||||||
view.setUint8(2, j);
|
|
||||||
/*
|
|
||||||
* offset and color of every pixel
|
|
||||||
* 3 bytes offset
|
|
||||||
* 1 byte color
|
|
||||||
*/
|
|
||||||
let cnt = 2;
|
|
||||||
let p = pixels.length;
|
|
||||||
while (p) {
|
|
||||||
p -= 1;
|
|
||||||
const [offset, color] = pixels[p];
|
|
||||||
view.setUint8(cnt += 1, offset >>> 16);
|
|
||||||
view.setUint16(cnt += 1, offset & 0x00FFFF);
|
|
||||||
view.setUint8(cnt += 2, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Packet for sending and receiving pixels over Message Broker between shards
|
|
||||||
* Multiple pixels can be sent at once
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
const OP_CODE = 0xC1;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
/*
|
|
||||||
* returns info and PixelUpdate package to send to clients
|
|
||||||
*/
|
|
||||||
hydrate(data) {
|
|
||||||
const canvasId = data[1];
|
|
||||||
data.writeUInt8(OP_CODE, 1);
|
|
||||||
const chunkId = data.readUInt16BE(2);
|
|
||||||
const pixelUpdate = Buffer.from(
|
|
||||||
data.buffer,
|
|
||||||
data.byteOffset + 1,
|
|
||||||
data.length - 1,
|
|
||||||
);
|
|
||||||
return [
|
|
||||||
canvasId,
|
|
||||||
chunkId,
|
|
||||||
pixelUpdate,
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param canvasId
|
|
||||||
* @param chunkId id consisting of chunk coordinates
|
|
||||||
* @param pixels Buffer with offset and color of one or more pixels
|
|
||||||
*/
|
|
||||||
dehydrate(canvasId, i, j, pixels) {
|
|
||||||
const index = new Uint8Array([
|
|
||||||
OP_CODE,
|
|
||||||
canvasId,
|
|
||||||
i,
|
|
||||||
j,
|
|
||||||
]);
|
|
||||||
return Buffer.concat([index, pixels]);
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Packet for sending and receiving pixels per chunk
|
|
||||||
* Multiple pixels can be sent at once
|
|
||||||
* Server side.
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
|
|
||||||
const OP_CODE = 0xC1;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
hydrate(data) {
|
|
||||||
/*
|
|
||||||
* chunk coordinates
|
|
||||||
*/
|
|
||||||
const i = data.readUInt8(1);
|
|
||||||
const j = data.readUInt8(2);
|
|
||||||
/*
|
|
||||||
* offset and color of every pixel
|
|
||||||
* 3 bytes offset
|
|
||||||
* 1 byte color
|
|
||||||
*/
|
|
||||||
const pixels = [];
|
|
||||||
let off = data.length;
|
|
||||||
/*
|
|
||||||
* limit the max amount of pixels that can be
|
|
||||||
* receive to 500
|
|
||||||
*/
|
|
||||||
let pxlcnt = 0;
|
|
||||||
while (off > 3 && pxlcnt < 500) {
|
|
||||||
const color = data.readUInt8(off -= 1);
|
|
||||||
const offsetL = data.readUInt16BE(off -= 2);
|
|
||||||
const offsetH = data.readUInt8(off -= 1) << 16;
|
|
||||||
pixels.push([offsetH | offsetL, color]);
|
|
||||||
pxlcnt += 1;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
i, j, pixels,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param chunkId id consisting of chunk coordinates
|
|
||||||
* @param pixels Buffer with offset and color of one or more pixels
|
|
||||||
*/
|
|
||||||
dehydrate(i, j, pixels) {
|
|
||||||
const index = new Uint8Array([OP_CODE, i, j]);
|
|
||||||
return Buffer.concat([index, pixels]);
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,6 +1,4 @@
|
||||||
# Binary Websocket Packages
|
# Binary Websocket Packages
|
||||||
|
|
||||||
Note that the node Server receives in [Buffer](https://nodejs.org/api/buffer.html), while the client receives [DataViews](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView) and sends ArrayBuffers.
|
Note that the node Server receives and sends in [Buffer](https://nodejs.org/api/buffer.html), while the client receives [DataViews](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView) and sends ArrayBuffers.
|
||||||
Therefor the server can't share the same code with the client for hydrate / dehydrate.
|
Therefor the server can't share the same code with the client for hydrate / dehydrate and it's split in two files.
|
||||||
Most packages are unidirectional so hydrate is for either client or server and dehydrate for the other one.
|
|
||||||
Bidrectional packages have two files, one for Client, another one for Server.
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
const OP_CODE = 0xA0;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
hydrate(data) {
|
|
||||||
// SERVER (Receiver)
|
|
||||||
const canvasId = data[1];
|
|
||||||
return canvasId;
|
|
||||||
},
|
|
||||||
dehydrate(canvasId) {
|
|
||||||
// CLIENT (Sender)
|
|
||||||
const buffer = new ArrayBuffer(1 + 1);
|
|
||||||
const view = new DataView(buffer);
|
|
||||||
view.setInt8(0, OP_CODE);
|
|
||||||
view.setInt8(1, Number(canvasId));
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,18 +0,0 @@
|
||||||
const OP_CODE = 0xA1;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
hydrate(data) {
|
|
||||||
// SERVER (Receiver)
|
|
||||||
const i = data[1] << 8 | data[2];
|
|
||||||
return i;
|
|
||||||
},
|
|
||||||
dehydrate(chunkid) {
|
|
||||||
// CLIENT (Sender)
|
|
||||||
const buffer = new ArrayBuffer(1 + 2);
|
|
||||||
const view = new DataView(buffer);
|
|
||||||
view.setInt8(0, OP_CODE);
|
|
||||||
view.setInt16(1, chunkid);
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,20 +0,0 @@
|
||||||
const OP_CODE = 0xA3;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
OP_CODE,
|
|
||||||
/*
|
|
||||||
* @param chunks Array of chunks
|
|
||||||
*/
|
|
||||||
dehydrate(chunks) {
|
|
||||||
// CLIENT (Sender)
|
|
||||||
const buffer = new ArrayBuffer(1 + 1 + chunks.length * 2);
|
|
||||||
const view = new Uint16Array(buffer);
|
|
||||||
// this will result into a double first byte, but still better than
|
|
||||||
// shifting 16bit integers around later
|
|
||||||
view[0] = OP_CODE;
|
|
||||||
for (let cnt = 0; cnt < chunks.length; cnt += 1) {
|
|
||||||
view[cnt + 1] = chunks[cnt];
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
};
|
|
196
src/socket/packets/client.js
Normal file
196
src/socket/packets/client.js
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* client package hydration
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
REG_CANVAS_OP,
|
||||||
|
REG_CHUNK_OP,
|
||||||
|
DEREG_CHUNK_OP,
|
||||||
|
REG_MCHUNKS_OP,
|
||||||
|
DEREG_MCHUNKS_OP,
|
||||||
|
CAPTCHA_SOLUTION_OP,
|
||||||
|
PING_OP,
|
||||||
|
PIXEL_UPDATE_OP,
|
||||||
|
} from './op';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* data in hydrate functions is DataView
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return {
|
||||||
|
* total: totalOnline,
|
||||||
|
* canvasId: online,
|
||||||
|
* ....
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export function hydrateOnlineCounter(data) {
|
||||||
|
const online = {};
|
||||||
|
online.total = data.getUint16(1);
|
||||||
|
let off = data.byteLength;
|
||||||
|
while (off > 3) {
|
||||||
|
const onlineUsers = data.getUint16(off -= 2);
|
||||||
|
const canvas = data.getUint8(off -= 1);
|
||||||
|
online[canvas] = onlineUsers;
|
||||||
|
}
|
||||||
|
return online;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return chunk coordinates and array of pixel offset and colors
|
||||||
|
*/
|
||||||
|
export function hydratePixelUpdate(data) {
|
||||||
|
const i = data.getUint8(1);
|
||||||
|
const j = data.getUint8(2);
|
||||||
|
/*
|
||||||
|
* offset and color of every pixel
|
||||||
|
* 3 bytes offset
|
||||||
|
* 1 byte color
|
||||||
|
*/
|
||||||
|
const pixels = [];
|
||||||
|
let off = data.byteLength;
|
||||||
|
while (off > 3) {
|
||||||
|
const color = data.getUint8(off -= 1);
|
||||||
|
const offsetL = data.getUint16(off -= 2);
|
||||||
|
const offsetH = data.getUint8(off -= 1) << 16;
|
||||||
|
pixels.push([offsetH | offsetL, color]);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
i, j, pixels,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return cooldown in ms
|
||||||
|
*/
|
||||||
|
export function hydrateCoolDown(data) {
|
||||||
|
return data.getUint32(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return see ui/placePixels
|
||||||
|
*/
|
||||||
|
export function hydratePixelReturn(data) {
|
||||||
|
// Client (receiver)
|
||||||
|
const retCode = data.getUint8(1);
|
||||||
|
const wait = data.getUint32(2);
|
||||||
|
const coolDownSeconds = data.getInt16(6);
|
||||||
|
const pxlCnt = data.getUint8(8);
|
||||||
|
const rankedPxlCnt = data.getUint8(9);
|
||||||
|
return {
|
||||||
|
retCode,
|
||||||
|
wait,
|
||||||
|
coolDownSeconds,
|
||||||
|
pxlCnt,
|
||||||
|
rankedPxlCnt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dehydrate functions return ArrayBuffer object
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param canvasId
|
||||||
|
*/
|
||||||
|
export function dehydrateRegCanvas(canvasId) {
|
||||||
|
const buffer = new ArrayBuffer(1 + 1);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
view.setInt8(0, REG_CANVAS_OP);
|
||||||
|
view.setInt8(1, Number(canvasId));
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param chunkid
|
||||||
|
*/
|
||||||
|
export function dehydrateRegChunk(chunkid) {
|
||||||
|
const buffer = new ArrayBuffer(1 + 2);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
view.setInt8(0, REG_CHUNK_OP);
|
||||||
|
view.setInt16(1, chunkid);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param chunkid
|
||||||
|
*/
|
||||||
|
export function dehydrateDeRegChunk(chunkid) {
|
||||||
|
const buffer = new ArrayBuffer(1 + 2);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
view.setInt8(0, DEREG_CHUNK_OP);
|
||||||
|
view.setInt16(1, chunkid);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param chunks Array of chunkIds
|
||||||
|
*/
|
||||||
|
export function dehydrateRegMChunks(chunks) {
|
||||||
|
const buffer = new ArrayBuffer(1 + 1 + chunks.length * 2);
|
||||||
|
const view = new Uint16Array(buffer);
|
||||||
|
// this will result into a double first byte, but still better than
|
||||||
|
// shifting 16bit integers around later
|
||||||
|
view[0] = REG_MCHUNKS_OP;
|
||||||
|
for (let cnt = 0; cnt < chunks.length; cnt += 1) {
|
||||||
|
view[cnt + 1] = chunks[cnt];
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param chunks Array of chunkIds
|
||||||
|
*/
|
||||||
|
export function dehydrateDeRegMChunks(chunks) {
|
||||||
|
const buffer = new ArrayBuffer(1 + 1 + chunks.length * 2);
|
||||||
|
const view = new Uint16Array(buffer);
|
||||||
|
// this will result into a double first byte, but still better than
|
||||||
|
// shifting 16bit integers around later
|
||||||
|
view[0] = DEREG_MCHUNKS_OP;
|
||||||
|
for (let cnt = 0; cnt < chunks.length; cnt += 1) {
|
||||||
|
view[cnt + 1] = chunks[cnt];
|
||||||
|
}
|
||||||
|
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() {
|
||||||
|
return new Uint8Array([PING_OP]).buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param i, j chunk coordinates
|
||||||
|
* @param pixels array of offsets and colors of pixels
|
||||||
|
*/
|
||||||
|
export function dehydratePixelUpdate(i, j, pixels) {
|
||||||
|
const buffer = new ArrayBuffer(1 + 1 + 1 + pixels.length * 4);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
view.setUint8(0, PIXEL_UPDATE_OP);
|
||||||
|
view.setUint8(1, i);
|
||||||
|
view.setUint8(2, j);
|
||||||
|
/*
|
||||||
|
* offset and color of every pixel
|
||||||
|
* 3 bytes offset
|
||||||
|
* 1 byte color
|
||||||
|
*/
|
||||||
|
let cnt = 2;
|
||||||
|
let p = pixels.length;
|
||||||
|
while (p) {
|
||||||
|
p -= 1;
|
||||||
|
const [offset, color] = pixels[p];
|
||||||
|
view.setUint8(cnt += 1, offset >>> 16);
|
||||||
|
view.setUint16(cnt += 1, offset & 0x00FFFF);
|
||||||
|
view.setUint8(cnt += 2, color);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
21
src/socket/packets/op.js
Normal file
21
src/socket/packets/op.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* OP CODES
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we export code so that webpack can directly resolve them
|
||||||
|
*/
|
||||||
|
export const REG_CANVAS_OP = 0xA0;
|
||||||
|
export const REG_CHUNK_OP = 0xA1;
|
||||||
|
export const DEREG_CHUNK_OP = 0xA2;
|
||||||
|
export const REG_MCHUNKS_OP = 0xA3;
|
||||||
|
export const DEREG_MCHUNKS_OP = 0xA4;
|
||||||
|
export const CAPTCHA_SOLUTION_OP = 0xA5;
|
||||||
|
export const CHANGE_ME_OP = 0xA6;
|
||||||
|
export const ONLINE_COUNTER_OP = 0xA7;
|
||||||
|
export const PING_OP = 0xB0;
|
||||||
|
export const PIXEL_UPDATE_OP = 0xC1;
|
||||||
|
export const PIXEL_UPDATE_MB_OP = 0xC1;
|
||||||
|
export const COOLDOWN_OP = 0xC2;
|
||||||
|
export const PIXEL_RETURN_OP = 0xC3;
|
||||||
|
export const CHUNK_UPDATE_MB_OP = 0xC4;
|
239
src/socket/packets/server.js
Normal file
239
src/socket/packets/server.js
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* server package hydration
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
CHANGE_ME_OP,
|
||||||
|
ONLINE_COUNTER_OP,
|
||||||
|
PIXEL_UPDATE_OP,
|
||||||
|
PIXEL_UPDATE_MB_OP,
|
||||||
|
COOLDOWN_OP,
|
||||||
|
PIXEL_RETURN_OP,
|
||||||
|
CHUNK_UPDATE_MB_OP,
|
||||||
|
} from './op';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* data in hydrate function is a nodejs Buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return canvasId
|
||||||
|
*/
|
||||||
|
export function hydrateRegCanvas(data) {
|
||||||
|
const canvasId = data[1];
|
||||||
|
return canvasId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return {
|
||||||
|
* total: totalOnline,
|
||||||
|
* canvasId: online,
|
||||||
|
* ....
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export function hydrateOnlineCounter(data) {
|
||||||
|
const online = {};
|
||||||
|
online.total = data.readUInt16BE(1);
|
||||||
|
let off = data.length;
|
||||||
|
while (off > 3) {
|
||||||
|
const onlineUsers = data.readUInt16BE(off -= 2);
|
||||||
|
const canvas = data.readUInt8(off -= 1);
|
||||||
|
online[canvas] = onlineUsers;
|
||||||
|
}
|
||||||
|
return online;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return chunkId
|
||||||
|
*/
|
||||||
|
export function hydrateRegChunk(data) {
|
||||||
|
const i = data[1] << 8 | data[2];
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return chunkId
|
||||||
|
*/
|
||||||
|
export function hydrateDeRegChunk(data) {
|
||||||
|
const i = data[1] << 8 | data[2];
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cb execute with individual chunkids
|
||||||
|
*/
|
||||||
|
export function hydrateRegMChunks(data, cb) {
|
||||||
|
let posu = 2;
|
||||||
|
while (posu < data.length) {
|
||||||
|
const chunkid = data[posu++] | data[posu++] << 8;
|
||||||
|
cb(chunkid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cb execute with individual chunkids
|
||||||
|
*/
|
||||||
|
export function hydrateDeRegMChunks(data, cb) {
|
||||||
|
let posl = 2;
|
||||||
|
while (posl < data.length) {
|
||||||
|
const chunkid = data[posl++] | data[posl++] << 8;
|
||||||
|
cb(chunkid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return captcha solution
|
||||||
|
*/
|
||||||
|
export function hydrateCaptchaSolution(data) {
|
||||||
|
return data.toString('utf8', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return chunk id and array of pixel offset and color
|
||||||
|
*/
|
||||||
|
export function hydratePixelUpdate(data) {
|
||||||
|
const i = data.readUInt8(1);
|
||||||
|
const j = data.readUInt8(2);
|
||||||
|
const pixels = [];
|
||||||
|
let off = data.length;
|
||||||
|
let pxlcnt = 0;
|
||||||
|
while (off > 3 && pxlcnt < 500) {
|
||||||
|
const color = data.readUInt8(off -= 1);
|
||||||
|
const offsetL = data.readUInt16BE(off -= 2);
|
||||||
|
const offsetH = data.readUInt8(off -= 1) << 16;
|
||||||
|
pixels.push([offsetH | offsetL, color]);
|
||||||
|
pxlcnt += 1;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
i, j, pixels,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @returns info and PixelUpdate package to send to clients
|
||||||
|
*/
|
||||||
|
export function hydratePixelUpdateMB(data) {
|
||||||
|
const canvasId = data[1];
|
||||||
|
data.writeUInt8(PIXEL_UPDATE_OP, 1);
|
||||||
|
const chunkId = data.readUInt16BE(2);
|
||||||
|
const pixelUpdate = Buffer.from(
|
||||||
|
data.buffer,
|
||||||
|
data.byteOffset + 1,
|
||||||
|
data.length - 1,
|
||||||
|
);
|
||||||
|
return [
|
||||||
|
canvasId,
|
||||||
|
chunkId,
|
||||||
|
pixelUpdate,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return canvasid and chunk coords
|
||||||
|
*/
|
||||||
|
export function hydrateChunkUpdateMB(data) {
|
||||||
|
const canvasId = data[1];
|
||||||
|
const i = data.readUInt8(2);
|
||||||
|
const j = data.readUInt8(3);
|
||||||
|
return [canvasId, [i, j]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dehydrate functions return nodejs Buffer object
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns buffer with only OP_CODE
|
||||||
|
*/
|
||||||
|
export function dehydrateChangeMe() {
|
||||||
|
return Buffer.from([CHANGE_ME_OP]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param {
|
||||||
|
* total: totalOnline,
|
||||||
|
* canvasId: online,
|
||||||
|
* ....
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export function dehydrateOnlineCounter(online) {
|
||||||
|
const canvasIds = Object.keys(online).filter((id) => id !== 'total');
|
||||||
|
const buffer = Buffer.allocUnsafe(3 + canvasIds.length * (1 + 2));
|
||||||
|
buffer.writeUInt8(ONLINE_COUNTER_OP, 0);
|
||||||
|
buffer.writeUInt16BE(online.total, 1);
|
||||||
|
let cnt = 1;
|
||||||
|
for (let p = 0; p < canvasIds.length; p += 1) {
|
||||||
|
const canvasId = canvasIds[p];
|
||||||
|
const onlineUsers = online[canvasId];
|
||||||
|
buffer.writeUInt8(Number(canvasId), cnt += 2);
|
||||||
|
buffer.writeUInt16BE(onlineUsers, cnt += 1);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param chunkId id consisting of chunk coordinates
|
||||||
|
* @param pixels Buffer with offset and color of one or more pixels
|
||||||
|
*/
|
||||||
|
export function dehydratePixelUpdate(i, j, pixels) {
|
||||||
|
const index = new Uint8Array([PIXEL_UPDATE_OP, i, j]);
|
||||||
|
return Buffer.concat([index, pixels]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param canvasId
|
||||||
|
* @param chunkId id consisting of chunk coordinates
|
||||||
|
* @param pixels Buffer with offset and color of one or more pixels
|
||||||
|
*/
|
||||||
|
export function dehydratePixelUpdateMB(canvasId, i, j, pixels) {
|
||||||
|
const index = new Uint8Array([
|
||||||
|
PIXEL_UPDATE_MB_OP,
|
||||||
|
canvasId,
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
]);
|
||||||
|
return Buffer.concat([index, pixels]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param wait cooldown in ms
|
||||||
|
*/
|
||||||
|
export function dehydrateCoolDown(wait) {
|
||||||
|
const buffer = Buffer.allocUnsafe(1 + 4);
|
||||||
|
buffer.writeUInt8(COOLDOWN_OP, 0);
|
||||||
|
buffer.writeUInt32BE(wait, 1);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for params see core/draw or ui/placePixel
|
||||||
|
*/
|
||||||
|
export function dehydratePixelReturn(
|
||||||
|
retCode,
|
||||||
|
wait,
|
||||||
|
coolDown,
|
||||||
|
pxlCnt,
|
||||||
|
rankedPxlCnt,
|
||||||
|
) {
|
||||||
|
const buffer = Buffer.allocUnsafe(1 + 1 + 4 + 2 + 1 + 1);
|
||||||
|
buffer.writeUInt8(PIXEL_RETURN_OP, 0);
|
||||||
|
buffer.writeUInt8(retCode, 1);
|
||||||
|
buffer.writeUInt32BE(wait, 2);
|
||||||
|
const coolDownSeconds = Math.round(coolDown / 1000);
|
||||||
|
buffer.writeInt16BE(coolDownSeconds, 6);
|
||||||
|
buffer.writeUInt8(pxlCnt, 8);
|
||||||
|
buffer.writeUInt8(rankedPxlCnt, 9);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param canvasId
|
||||||
|
* @param Array with chunk coordinates
|
||||||
|
*/
|
||||||
|
export function dehydrateChunkUpdateMB(canvasId, [i, j]) {
|
||||||
|
return Buffer.from([
|
||||||
|
CHUNK_UPDATE_MB_OP,
|
||||||
|
canvasId,
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
]);
|
||||||
|
}
|
|
@ -148,7 +148,7 @@ export function selectColor(color) {
|
||||||
export function selectCanvas(canvasId) {
|
export function selectCanvas(canvasId) {
|
||||||
return {
|
return {
|
||||||
type: 's/SELECT_CANVAS',
|
type: 's/SELECT_CANVAS',
|
||||||
canvasId,
|
canvasId: String(canvasId),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,26 +41,25 @@ export default (store) => (next) => (action) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
const ret = next(action);
|
|
||||||
|
|
||||||
// executed after reducers
|
|
||||||
switch (action.type) {
|
|
||||||
case 'RELOAD_URL':
|
case 'RELOAD_URL':
|
||||||
case 's/SELECT_CANVAS':
|
case 's/SELECT_CANVAS':
|
||||||
case 's/REC_ME': {
|
case 's/REC_ME': {
|
||||||
|
const prevState = store.getState();
|
||||||
|
const ret = next(action);
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const { canvasId } = state.canvas;
|
const { canvasId } = state.canvas;
|
||||||
SocketClient.setCanvas(canvasId);
|
if (prevState.canvas.canvasId === canvasId) {
|
||||||
break;
|
// TODO see if this is the case anywhere
|
||||||
|
console.log('Not triggering change canvas');
|
||||||
|
} else {
|
||||||
|
SocketClient.setCanvas(canvasId);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return next(action);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
import SocketClient from '../../socket/SocketClient';
|
import SocketClient from '../../socket/SocketClient';
|
||||||
|
|
||||||
export default () => (next) => (action) => {
|
export default (store) => (next) => (action) => {
|
||||||
if (SocketClient.readyState === WebSocket.CLOSED) {
|
if (SocketClient.readyState === WebSocket.CLOSED) {
|
||||||
if (action.type === 't/PARENT_CLOSED') {
|
if (action.type === 't/PARENT_CLOSED') {
|
||||||
SocketClient.connect();
|
SocketClient.initialize(store);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user