mirror of
https://github.com/darkwire/darkwire.io.git
synced 2025-07-18 18:54:52 +00:00
This reverts commit 2a8d3281db851d15f9402d0fe69291255c6b250b.
This commit is contained in:
parent
5affceb47e
commit
18065f9652
16
readme.md
16
readme.md
@ -16,22 +16,6 @@ The Darkwire.io [web client](/client) is written in JavaScript with React JS and
|
|||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
#### Prerequisites
|
|
||||||
|
|
||||||
Copy `.env.dist` files in `server/` and `client/` directories without the `.dist`
|
|
||||||
extensions and adapt them to your needs.
|
|
||||||
|
|
||||||
You need [Redis](https://redis.io/) in order to make the server works.
|
|
||||||
A simple way to achieve this, if you have docker, is to execute the following
|
|
||||||
command:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run --name darkwire-redis --rm -p 6379:6379 -d redis redis-server --appendonly yes
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, you can select the _memory_ `STORE_BACKEND` instead of _redis_
|
|
||||||
in your server `.env` file to avoid Redis use.
|
|
||||||
|
|
||||||
#### Setup
|
#### Setup
|
||||||
|
|
||||||
Install dependencies
|
Install dependencies
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
# Abuse mail configuration
|
|
||||||
MAILGUN_API_KEY=api-key
|
MAILGUN_API_KEY=api-key
|
||||||
MAILGUN_DOMAIN=darkwire.io
|
MAILGUN_DOMAIN=darkwire.io
|
||||||
ABUSE_TO_EMAIL_ADDRESS=abuse@darkwire.io
|
ABUSE_TO_EMAIL_ADDRESS=abuse@darkwire.io
|
||||||
ABUSE_FROM_EMAIL_ADDRESS=Darkwire <no-reply@darkwire.io>
|
ABUSE_FROM_EMAIL_ADDRESS=Darkwire <no-reply@darkwire.io>
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
CLIENT_DIST_DIRECTORY='client/dist/path'
|
CLIENT_DIST_DIRECTORY='client/dist/path'
|
||||||
|
|
||||||
ROOM_HASH_SECRET='some-uuid'
|
ROOM_HASH_SECRET='some-uuid'
|
||||||
|
|
||||||
SITE_URL=https://darkwire.io
|
SITE_URL=https://darkwire.io
|
||||||
|
|
||||||
# Store configuration
|
|
||||||
STORE_BACKEND=redis
|
|
||||||
STORE_HOST=redis://localhost:6379
|
|
@ -1,25 +1,21 @@
|
|||||||
import getStore from './store';
|
import { getRedis } from './index'
|
||||||
|
|
||||||
export async function pollForInactiveRooms() {
|
export async function pollForInactiveRooms() {
|
||||||
const store = getStore();
|
const redis = getRedis();
|
||||||
|
|
||||||
console.log('Checking for inactive rooms...');
|
console.log('Checking for inactive rooms...');
|
||||||
const rooms = (await store.getAll('rooms')) || {};
|
const rooms = await redis.hgetallAsync('rooms') || {};
|
||||||
console.log(`${Object.keys(rooms).length} rooms found`);
|
console.log(`${Object.keys(rooms).length} rooms found`);
|
||||||
|
|
||||||
Object.keys(rooms).forEach(async (roomId) => {
|
Object.keys(rooms).forEach(async roomId => {
|
||||||
const room = JSON.parse(rooms[roomId]);
|
const room = JSON.parse(rooms[roomId]);
|
||||||
const timeSinceUpdatedInSeconds = (Date.now() - room.updatedAt) / 1000;
|
const timeSinceUpdatedInSeconds = (Date.now() - room.updatedAt) / 1000;
|
||||||
const timeSinceUpdatedInDays = Math.round(
|
const timeSinceUpdatedInDays = Math.round(timeSinceUpdatedInSeconds / 60 / 60 / 24);
|
||||||
timeSinceUpdatedInSeconds / 60 / 60 / 24
|
|
||||||
);
|
|
||||||
if (timeSinceUpdatedInDays > 7) {
|
if (timeSinceUpdatedInDays > 7) {
|
||||||
console.log(
|
console.log(`Deleting roomId ${roomId} which hasn't been used in ${timeSinceUpdatedInDays} days`);
|
||||||
`Deleting roomId ${roomId} which hasn't been used in ${timeSinceUpdatedInDays} days`
|
await redis.hdelAsync('rooms', roomId);
|
||||||
);
|
|
||||||
await store.del('rooms', roomId);
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
setTimeout(pollForInactiveRooms, 1000 * 60 * 60 * 12); // every 12 hours
|
setTimeout(pollForInactiveRooms, (1000 * 60 * 60 * 12)); // every 12 hours
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
require('dotenv').config();
|
require('dotenv').config()
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import https from 'https';
|
import https from 'https';
|
||||||
import Koa from 'koa';
|
import Koa from 'koa';
|
||||||
@ -6,13 +6,22 @@ import Io from 'socket.io';
|
|||||||
import KoaBody from 'koa-body';
|
import KoaBody from 'koa-body';
|
||||||
import cors from 'kcors';
|
import cors from 'kcors';
|
||||||
import Router from 'koa-router';
|
import Router from 'koa-router';
|
||||||
|
import bluebird from 'bluebird';
|
||||||
|
import Redis from 'redis';
|
||||||
|
import socketRedis from 'socket.io-redis';
|
||||||
import Socket from './socket';
|
import Socket from './socket';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto'
|
||||||
import mailer from './utils/mailer';
|
import mailer from './utils/mailer';
|
||||||
import koaStatic from 'koa-static';
|
import koaStatic from 'koa-static';
|
||||||
import koaSend from 'koa-send';
|
import koaSend from 'koa-send';
|
||||||
import {pollForInactiveRooms} from './inactive_rooms';
|
import {pollForInactiveRooms} from './inactive_rooms';
|
||||||
import getStore from './store';
|
|
||||||
|
bluebird.promisifyAll(Redis.RedisClient.prototype);
|
||||||
|
bluebird.promisifyAll(Redis.Multi.prototype);
|
||||||
|
|
||||||
|
const redis = Redis.createClient(process.env.REDIS_URL)
|
||||||
|
|
||||||
|
export const getRedis = () => redis
|
||||||
|
|
||||||
const env = process.env.NODE_ENV || 'development';
|
const env = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
@ -26,16 +35,12 @@ const appName = process.env.HEROKU_APP_NAME;
|
|||||||
const isReviewApp = /-pr-/.test(appName);
|
const isReviewApp = /-pr-/.test(appName);
|
||||||
const siteURL = process.env.SITE_URL;
|
const siteURL = process.env.SITE_URL;
|
||||||
|
|
||||||
const store = getStore();
|
|
||||||
|
|
||||||
if ((siteURL || env === 'development') && !isReviewApp) {
|
if ((siteURL || env === 'development') && !isReviewApp) {
|
||||||
app.use(
|
app.use(cors({
|
||||||
cors({
|
|
||||||
origin: env === 'development' ? '*' : siteURL,
|
origin: env === 'development' ? '*' : siteURL,
|
||||||
allowMethods: ['GET','HEAD','POST'],
|
allowMethods: ['GET','HEAD','POST'],
|
||||||
credentials: true,
|
credentials: true,
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
router.post('/abuse/:roomId', koaBody, async (ctx) => {
|
router.post('/abuse/:roomId', koaBody, async (ctx) => {
|
||||||
@ -43,22 +48,19 @@ router.post('/abuse/:roomId', koaBody, async (ctx) => {
|
|||||||
|
|
||||||
roomId = roomId.trim();
|
roomId = roomId.trim();
|
||||||
|
|
||||||
if (
|
if (process.env.ABUSE_FROM_EMAIL_ADDRESS && process.env.ABUSE_TO_EMAIL_ADDRESS) {
|
||||||
process.env.ABUSE_FROM_EMAIL_ADDRESS &&
|
const abuseForRoomExists = await redis.hgetAsync('abuse', roomId);
|
||||||
process.env.ABUSE_TO_EMAIL_ADDRESS
|
|
||||||
) {
|
|
||||||
const abuseForRoomExists = await store.get('abuse', roomId);
|
|
||||||
if (!abuseForRoomExists) {
|
if (!abuseForRoomExists) {
|
||||||
mailer.send({
|
mailer.send({
|
||||||
from: process.env.ABUSE_FROM_EMAIL_ADDRESS,
|
from: process.env.ABUSE_FROM_EMAIL_ADDRESS,
|
||||||
to: process.env.ABUSE_TO_EMAIL_ADDRESS,
|
to: process.env.ABUSE_TO_EMAIL_ADDRESS,
|
||||||
subject: 'Darkwire Abuse Notification',
|
subject: 'Darkwire Abuse Notification',
|
||||||
text: `Room ID: ${roomId}`,
|
text: `Room ID: ${roomId}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await store.inc('abuse', roomId);
|
await redis.hincrbyAsync('abuse', roomId, 1);
|
||||||
|
|
||||||
ctx.status = 200;
|
ctx.status = 200;
|
||||||
});
|
});
|
||||||
@ -66,9 +68,7 @@ router.post('/abuse/:roomId', koaBody, async (ctx) => {
|
|||||||
app.use(router.routes());
|
app.use(router.routes());
|
||||||
|
|
||||||
const apiHost = process.env.API_HOST;
|
const apiHost = process.env.API_HOST;
|
||||||
const cspDefaultSrc = `'self'${
|
const cspDefaultSrc = `'self'${apiHost ? ` https://${apiHost} wss://${apiHost}` : ''}`
|
||||||
apiHost ? ` https://${apiHost} wss://${apiHost}` : ''
|
|
||||||
}`;
|
|
||||||
|
|
||||||
function setStaticFileHeaders(ctx) {
|
function setStaticFileHeaders(ctx) {
|
||||||
ctx.set({
|
ctx.set({
|
||||||
@ -78,8 +78,7 @@ function setStaticFileHeaders(ctx) {
|
|||||||
'X-XSS-Protection': '1; mode=block',
|
'X-XSS-Protection': '1; mode=block',
|
||||||
'X-Content-Type-Options': 'nosniff',
|
'X-Content-Type-Options': 'nosniff',
|
||||||
'Referrer-Policy': 'no-referrer',
|
'Referrer-Policy': 'no-referrer',
|
||||||
'Feature-Policy':
|
'Feature-Policy': "geolocation 'none'; vr 'none'; payment 'none'; microphone 'none'",
|
||||||
"geolocation 'none'; vr 'none'; payment 'none'; microphone 'none'",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,16 +87,16 @@ if (clientDistDirectory) {
|
|||||||
app.use(async (ctx, next) => {
|
app.use(async (ctx, next) => {
|
||||||
setStaticFileHeaders(ctx);
|
setStaticFileHeaders(ctx);
|
||||||
await koaStatic(clientDistDirectory, {
|
await koaStatic(clientDistDirectory, {
|
||||||
maxage: ctx.req.url === '/' ? 60 * 1000 : 365 * 24 * 60 * 60 * 1000, // one minute in ms for html doc, one year for css, js, etc
|
maxage: ctx.req.url === '/' ? 60 * 1000 : 365 * 24 * 60 * 60 * 1000 // one minute in ms for html doc, one year for css, js, etc
|
||||||
})(ctx, next);
|
})(ctx, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(async (ctx) => {
|
app.use(async (ctx) => {
|
||||||
setStaticFileHeaders(ctx);
|
setStaticFileHeaders(ctx);
|
||||||
await koaSend(ctx, 'index.html', { root: clientDistDirectory });
|
await koaSend(ctx, 'index.html', { root: clientDistDirectory });
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
app.use(async (ctx) => {
|
app.use(async ctx => {
|
||||||
ctx.body = { ready: true };
|
ctx.body = { ready: true };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -107,52 +106,52 @@ const protocol = (process.env.PROTOCOL || 'http') === 'http' ? http : https;
|
|||||||
const server = protocol.createServer(app.callback());
|
const server = protocol.createServer(app.callback());
|
||||||
const io = Io(server, {
|
const io = Io(server, {
|
||||||
pingInterval: 20000,
|
pingInterval: 20000,
|
||||||
pingTimeout: 5000,
|
pingTimeout: 5000
|
||||||
});
|
});
|
||||||
|
io.adapter(socketRedis(process.env.REDIS_URL));
|
||||||
// Only use socket adapter if store has one
|
|
||||||
if (store.hasSocketAdapter) {
|
|
||||||
io.adapter(store.getSocketAdapter());
|
|
||||||
}
|
|
||||||
|
|
||||||
const roomHashSecret = process.env.ROOM_HASH_SECRET;
|
const roomHashSecret = process.env.ROOM_HASH_SECRET;
|
||||||
|
|
||||||
const getRoomIdHash = (id) => {
|
const getRoomIdHash = (id) => {
|
||||||
if (env === 'development') {
|
if (env === 'development') {
|
||||||
return id;
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roomHashSecret) {
|
if (roomHashSecret) {
|
||||||
return crypto.createHmac('sha256', roomHashSecret).update(id).digest('hex');
|
return crypto
|
||||||
|
.createHmac('sha256', roomHashSecret)
|
||||||
|
.update(id)
|
||||||
|
.digest('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
return crypto.createHash('sha256').update(id).digest('hex');
|
return crypto.createHash('sha256').update(id).digest('hex');
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getIO = () => io;
|
export const getIO = () => io
|
||||||
|
|
||||||
io.on('connection', async (socket) => {
|
io.on('connection', async (socket) => {
|
||||||
const roomId = socket.handshake.query.roomId;
|
const roomId = socket.handshake.query.roomId
|
||||||
|
|
||||||
const roomIdHash = getRoomIdHash(roomId);
|
const roomIdHash = getRoomIdHash(roomId)
|
||||||
|
|
||||||
let room = await store.get('rooms', roomIdHash);
|
let room = await redis.hgetAsync('rooms', roomIdHash)
|
||||||
room = JSON.parse(room || '{}');
|
room = JSON.parse(room || '{}')
|
||||||
|
|
||||||
new Socket({
|
new Socket({
|
||||||
roomIdOriginal: roomId,
|
roomIdOriginal: roomId,
|
||||||
roomId: roomIdHash,
|
roomId: roomIdHash,
|
||||||
socket,
|
socket,
|
||||||
room,
|
room,
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log(`Darkwire is online at port ${PORT}`);
|
console.log(`Darkwire is online at port ${PORT}`);
|
||||||
});
|
})
|
||||||
|
|
||||||
pollForInactiveRooms();
|
pollForInactiveRooms();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
init()
|
||||||
|
|
||||||
init();
|
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { getIO } from './index';
|
import uuid from 'uuid/v4';
|
||||||
import getStore from './store';
|
import { getIO, getRedis } from './index'
|
||||||
|
|
||||||
export default class Socket {
|
export default class Socket {
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
const { roomId, socket, room, roomIdOriginal } = opts;
|
const { roomId, socket, room, roomIdOriginal } = opts
|
||||||
|
|
||||||
this._roomId = roomId;
|
this._roomId = roomId
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.roomIdOriginal = roomIdOriginal;
|
this.roomIdOriginal = roomIdOriginal;
|
||||||
this.room = room;
|
this.room = room;
|
||||||
if (room.isLocked) {
|
if (room.isLocked) {
|
||||||
this.sendRoomLocked();
|
this.sendRoomLocked();
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.init(opts);
|
this.init(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(opts) {
|
async init(opts) {
|
||||||
const { roomId, socket, room } = opts;
|
const { roomId, socket, room } = opts
|
||||||
await this.joinRoom(roomId, socket);
|
await this.joinRoom(roomId, socket.id)
|
||||||
this.handleSocket(socket);
|
this.handleSocket(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRoomLocked() {
|
sendRoomLocked() {
|
||||||
@ -32,41 +32,30 @@ export default class Socket {
|
|||||||
const json = {
|
const json = {
|
||||||
...room,
|
...room,
|
||||||
updatedAt: Date.now(),
|
updatedAt: Date.now(),
|
||||||
};
|
}
|
||||||
|
|
||||||
return getStore().set('rooms', this._roomId, JSON.stringify(json));
|
return getRedis().hsetAsync('rooms', this._roomId, JSON.stringify(json))
|
||||||
}
|
}
|
||||||
|
|
||||||
async destroyRoom() {
|
async destroyRoom() {
|
||||||
return getStore().del('rooms', this._roomId);
|
return getRedis().hdel('rooms', this._roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchRoom() {
|
fetchRoom() {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const res = await getStore().get('rooms', this._roomId);
|
const res = await getRedis().hgetAsync('rooms', this._roomId)
|
||||||
resolve(JSON.parse(res || '{}'));
|
resolve(JSON.parse(res || '{}'))
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
joinRoom(roomId, socket) {
|
joinRoom(roomId, socketId) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (getStore().hasSocketAdapter) {
|
getIO().of('/').adapter.remoteJoin(socketId, roomId, (err) => {
|
||||||
getIO()
|
|
||||||
.of('/')
|
|
||||||
.adapter.remoteJoin(socket.id, roomId, (err) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
reject();
|
reject()
|
||||||
}
|
}
|
||||||
resolve();
|
resolve()
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
socket.join(roomId, (err) => {
|
|
||||||
if (err) {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,63 +65,56 @@ export default class Socket {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('USER_ENTER', async (payload) => {
|
socket.on('USER_ENTER', async (payload) => {
|
||||||
let room = await this.fetchRoom();
|
let room = await this.fetchRoom()
|
||||||
if (_.isEmpty(room)) {
|
if (_.isEmpty(room)) {
|
||||||
room = {
|
room = {
|
||||||
id: this._roomId,
|
id: this._roomId,
|
||||||
users: [],
|
users: [],
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newRoom = {
|
const newRoom = {
|
||||||
...room,
|
...room,
|
||||||
users: [
|
users: [...(room.users || []), {
|
||||||
...(room.users || []),
|
|
||||||
{
|
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
publicKey: payload.publicKey,
|
publicKey: payload.publicKey,
|
||||||
isOwner: (room.users || []).length === 0,
|
isOwner: (room.users || []).length === 0,
|
||||||
},
|
}]
|
||||||
],
|
}
|
||||||
};
|
await this.saveRoom(newRoom)
|
||||||
await this.saveRoom(newRoom);
|
|
||||||
|
|
||||||
getIO()
|
getIO().to(this._roomId).emit('USER_ENTER', {
|
||||||
.to(this._roomId)
|
|
||||||
.emit('USER_ENTER', {
|
|
||||||
...newRoom,
|
...newRoom,
|
||||||
id: this.roomIdOriginal,
|
id: this.roomIdOriginal
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
|
||||||
socket.on('TOGGLE_LOCK_ROOM', async (data, callback) => {
|
socket.on('TOGGLE_LOCK_ROOM', async (data, callback) => {
|
||||||
const room = await this.fetchRoom();
|
const room = await this.fetchRoom()
|
||||||
const user = (room.users || []).find(
|
const user = (room.users || []).find(u => u.socketId === socket.id && u.isOwner)
|
||||||
(u) => u.socketId === socket.id && u.isOwner
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
callback({
|
callback({
|
||||||
isLocked: room.isLocked,
|
isLocked: room.isLocked,
|
||||||
});
|
})
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.saveRoom({
|
await this.saveRoom({
|
||||||
...room,
|
...room,
|
||||||
isLocked: !room.isLocked,
|
isLocked: !room.isLocked,
|
||||||
});
|
})
|
||||||
|
|
||||||
socket.to(this._roomId).emit('TOGGLE_LOCK_ROOM', {
|
socket.to(this._roomId).emit('TOGGLE_LOCK_ROOM', {
|
||||||
locked: !room.isLocked,
|
locked: !room.isLocked,
|
||||||
publicKey: user && user.publicKey,
|
publicKey: user && user.publicKey
|
||||||
});
|
});
|
||||||
|
|
||||||
callback({
|
callback({
|
||||||
isLocked: !room.isLocked,
|
isLocked: !room.isLocked,
|
||||||
});
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('disconnect', () => this.handleDisconnect(socket));
|
socket.on('disconnect', () => this.handleDisconnect(socket));
|
||||||
@ -141,26 +123,25 @@ export default class Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleDisconnect(socket) {
|
async handleDisconnect(socket) {
|
||||||
let room = await this.fetchRoom();
|
let room = await this.fetchRoom()
|
||||||
|
|
||||||
const newRoom = {
|
const newRoom = {
|
||||||
...room,
|
...room,
|
||||||
users: (room.users || [])
|
users: (room.users || []).filter(u => u.socketId !== socket.id).map((u, index) => ({
|
||||||
.filter((u) => u.socketId !== socket.id)
|
|
||||||
.map((u, index) => ({
|
|
||||||
...u,
|
...u,
|
||||||
isOwner: index === 0,
|
isOwner: index === 0,
|
||||||
})),
|
}))
|
||||||
};
|
}
|
||||||
|
|
||||||
await this.saveRoom(newRoom);
|
await this.saveRoom(newRoom)
|
||||||
|
|
||||||
getIO().to(this._roomId).emit('USER_EXIT', newRoom.users);
|
getIO().to(this._roomId).emit('USER_EXIT', newRoom.users);
|
||||||
|
|
||||||
if (newRoom.users && newRoom.users.length === 0) {
|
if (newRoom.users && newRoom.users.length === 0) {
|
||||||
await this.destroyRoom();
|
await this.destroyRoom()
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.disconnect(true);
|
socket.disconnect(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
/**
|
|
||||||
* Memory store more for testing purpose than production use.
|
|
||||||
*/
|
|
||||||
export class MemoryStore {
|
|
||||||
constructor() {
|
|
||||||
this.store = {};
|
|
||||||
this.hasSocketAdapter = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async get(key, field) {
|
|
||||||
if (this.store[key] === undefined || this.store[key][field] === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.store[key][field];
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAll(key) {
|
|
||||||
if (this.store[key] === undefined) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.store[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
async set(key, field, value) {
|
|
||||||
if (this.store[key] === undefined) {
|
|
||||||
this.store[key] = {};
|
|
||||||
}
|
|
||||||
this.store[key][field] = value;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
async del(key, field) {
|
|
||||||
if (this.store[key] === undefined || this.store[key][field] === undefined) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
delete this.store[key][field];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
async inc(key, field, inc = 1) {
|
|
||||||
this.store[key][field] += inc;
|
|
||||||
return this.store[key][field];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MemoryStore
|
|
@ -1,42 +0,0 @@
|
|||||||
import Redis from 'redis';
|
|
||||||
import bluebird from 'bluebird';
|
|
||||||
import socketRedis from 'socket.io-redis';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redis store.
|
|
||||||
*/
|
|
||||||
export class RedisStore {
|
|
||||||
constructor(redisUrl) {
|
|
||||||
bluebird.promisifyAll(Redis.RedisClient.prototype);
|
|
||||||
bluebird.promisifyAll(Redis.Multi.prototype);
|
|
||||||
this.redisUrl = redisUrl;
|
|
||||||
this.redis = Redis.createClient(redisUrl);
|
|
||||||
this.hasSocketAdapter = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key, field) {
|
|
||||||
return this.redis.hgetAsync(key, field);
|
|
||||||
}
|
|
||||||
|
|
||||||
getAll(key) {
|
|
||||||
return this.redis.hgetallAsync(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key, field, value) {
|
|
||||||
return this.redis.hsetAsync(key, field, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
del(key, field) {
|
|
||||||
return this.hdelAsync(key, field);
|
|
||||||
}
|
|
||||||
|
|
||||||
inc(key, field, inc = 1) {
|
|
||||||
return this.redis.incrbyAsync(key, field, inc);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSocketAdapter() {
|
|
||||||
return socketRedis(this.redisUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RedisStore
|
|
@ -1,19 +0,0 @@
|
|||||||
import MemoryStore from './Memory';
|
|
||||||
import RedisStore from './Redis';
|
|
||||||
|
|
||||||
const storeBackend = process.env.STORE_BACKEND || 'redis';
|
|
||||||
|
|
||||||
let store;
|
|
||||||
switch (storeBackend) {
|
|
||||||
case 'memory':
|
|
||||||
store = new MemoryStore();
|
|
||||||
break;
|
|
||||||
case 'redis':
|
|
||||||
default:
|
|
||||||
store = new RedisStore(process.env.STORE_HOST);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStore = () => store;
|
|
||||||
|
|
||||||
export default getStore;
|
|
Loading…
x
Reference in New Issue
Block a user