mirror of
https://github.com/pavlobu/deskreen.git
synced 2025-05-16 15:30:20 -07:00
200 lines
4.3 KiB
TypeScript
200 lines
4.3 KiB
TypeScript
/* eslint-disable no-async-promise-executor */
|
|
import _ from 'lodash';
|
|
import Io from 'socket.io';
|
|
// eslint-disable-next-line import/no-cycle
|
|
import { getIO } from './signalingServer';
|
|
import getStore from './store';
|
|
|
|
interface User {
|
|
socketId: string;
|
|
publicKey: string;
|
|
isOwner: boolean;
|
|
}
|
|
|
|
interface Room {
|
|
id: string;
|
|
users: User[];
|
|
isLocked: boolean;
|
|
createdAt: number;
|
|
}
|
|
|
|
interface SocketOPTS {
|
|
roomId: string;
|
|
socket: Io.Socket;
|
|
room: Room;
|
|
roomIdOriginal: string;
|
|
}
|
|
|
|
export default class Socket implements SocketOPTS {
|
|
roomId: string;
|
|
|
|
socket: Io.Socket;
|
|
|
|
room: Room;
|
|
|
|
roomIdOriginal: string;
|
|
|
|
constructor(opts: SocketOPTS) {
|
|
const { roomId, socket, room, roomIdOriginal } = opts;
|
|
|
|
this.roomId = roomId;
|
|
this.socket = socket;
|
|
this.roomIdOriginal = roomIdOriginal;
|
|
this.room = room;
|
|
if (room.isLocked) {
|
|
this.sendRoomLocked();
|
|
return;
|
|
}
|
|
|
|
this.init(opts);
|
|
}
|
|
|
|
async init(opts: SocketOPTS) {
|
|
const { roomId, socket } = opts;
|
|
await this.joinRoom(roomId, socket);
|
|
this.handleSocket(socket);
|
|
}
|
|
|
|
sendRoomLocked() {
|
|
this.socket.emit('ROOM_LOCKED');
|
|
}
|
|
|
|
async saveRoom(room: Room) {
|
|
const json = {
|
|
...room,
|
|
updatedAt: Date.now(),
|
|
};
|
|
|
|
return getStore().set('rooms', this.roomId, JSON.stringify(json));
|
|
}
|
|
|
|
async destroyRoom() {
|
|
return getStore().del('rooms', this.roomId);
|
|
}
|
|
|
|
fetchRoom() {
|
|
return new Promise(async (resolve) => {
|
|
const res = await getStore().get('rooms', this.roomId);
|
|
resolve(JSON.parse(res || '{}'));
|
|
});
|
|
}
|
|
|
|
// eslint-disable-next-line class-methods-use-this
|
|
joinRoom(roomId: string, socket: Io.Socket) {
|
|
return new Promise((resolve, reject) => {
|
|
if (getStore().hasSocketAdapter) {
|
|
// TODO: what is this?
|
|
// getIO()
|
|
// .of('/')
|
|
// .adapter.remoteJoin(socket.id, roomId, (err: Error) => {
|
|
// if (err) {
|
|
// reject();
|
|
// }
|
|
// resolve();
|
|
// });
|
|
} else {
|
|
socket.join(roomId, (err) => {
|
|
if (err) {
|
|
reject();
|
|
}
|
|
resolve();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
async handleSocket(socket: Io.Socket) {
|
|
socket.on('ENCRYPTED_MESSAGE', (payload) => {
|
|
socket.to(this.roomId).emit('ENCRYPTED_MESSAGE', payload);
|
|
});
|
|
|
|
socket.on('USER_ENTER', async (payload) => {
|
|
let room: Room = (await this.fetchRoom()) as Room;
|
|
if (_.isEmpty(room)) {
|
|
room = {
|
|
id: this.roomId,
|
|
users: [],
|
|
isLocked: false,
|
|
createdAt: Date.now(),
|
|
};
|
|
}
|
|
|
|
const newRoom: Room = {
|
|
...room,
|
|
users: [
|
|
...(room.users || []),
|
|
{
|
|
socketId: socket.id,
|
|
publicKey: payload.publicKey,
|
|
isOwner: (room.users || []).length === 0,
|
|
},
|
|
],
|
|
};
|
|
await this.saveRoom(newRoom);
|
|
|
|
getIO()
|
|
.to(this.roomId)
|
|
.emit('USER_ENTER', {
|
|
...newRoom,
|
|
id: this.roomIdOriginal,
|
|
});
|
|
});
|
|
|
|
socket.on('TOGGLE_LOCK_ROOM', async (__, callback) => {
|
|
const room: Room = (await this.fetchRoom()) as Room;
|
|
const user = (room.users || []).find(
|
|
(u) => u.socketId === socket.id && u.isOwner
|
|
);
|
|
|
|
if (!user) {
|
|
callback({
|
|
isLocked: room.isLocked,
|
|
});
|
|
return;
|
|
}
|
|
|
|
await this.saveRoom({
|
|
...room,
|
|
isLocked: !room.isLocked,
|
|
});
|
|
|
|
socket.to(this.roomId).emit('TOGGLE_LOCK_ROOM', {
|
|
locked: !room.isLocked,
|
|
publicKey: user && user.publicKey,
|
|
});
|
|
|
|
callback({
|
|
isLocked: !room.isLocked,
|
|
});
|
|
});
|
|
|
|
socket.on('disconnect', () => this.handleDisconnect(socket));
|
|
|
|
socket.on('USER_DISCONNECT', () => this.handleDisconnect(socket));
|
|
}
|
|
|
|
async handleDisconnect(socket: Io.Socket) {
|
|
const room: Room = (await this.fetchRoom()) as Room;
|
|
|
|
const newRoom = {
|
|
...room,
|
|
users: (room.users || [])
|
|
.filter((u) => u.socketId !== socket.id)
|
|
.map((u, index) => ({
|
|
...u,
|
|
isOwner: index === 0,
|
|
})),
|
|
};
|
|
|
|
await this.saveRoom(newRoom);
|
|
|
|
getIO().to(this.roomId).emit('USER_EXIT', newRoom.users);
|
|
|
|
if (newRoom.users && newRoom.users.length === 0) {
|
|
await this.destroyRoom();
|
|
}
|
|
|
|
socket.disconnect(true);
|
|
}
|
|
}
|