2021-05-25 17:35:26 +10:00
|
|
|
import io, { Socket } from "socket.io-client";
|
2021-03-19 12:22:59 +11:00
|
|
|
import msgParser from "socket.io-msgpack-parser";
|
2020-07-16 17:27:39 +10:00
|
|
|
import { EventEmitter } from "events";
|
|
|
|
|
|
|
|
|
|
import Connection from "./Connection";
|
|
|
|
|
|
2020-10-23 10:27:22 +11:00
|
|
|
import { omit } from "../helpers/shared";
|
2020-10-27 10:26:55 +11:00
|
|
|
import { logError } from "../helpers/logging";
|
2021-05-25 17:35:26 +10:00
|
|
|
import { SimplePeerData } from "simple-peer";
|
2020-07-20 20:54:21 +10:00
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
/**
|
|
|
|
|
* @typedef {object} SessionPeer
|
|
|
|
|
* @property {string} id - The socket id of the peer
|
|
|
|
|
* @property {Connection} connection - The actual peer connection
|
|
|
|
|
* @property {boolean} initiator - Is this peer the initiator of the connection
|
2020-12-12 17:36:56 +11:00
|
|
|
* @property {boolean} ready - Ready for data to be sent
|
2020-12-12 16:08:10 +11:00
|
|
|
*/
|
2021-06-03 15:31:18 +10:00
|
|
|
export type SessionPeer = {
|
2021-05-25 17:35:26 +10:00
|
|
|
id: string;
|
|
|
|
|
connection: Connection;
|
|
|
|
|
initiator: boolean;
|
|
|
|
|
ready: boolean;
|
|
|
|
|
};
|
2020-12-12 16:08:10 +11:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @callback peerReply
|
|
|
|
|
* @param {string} id - The id of the event
|
|
|
|
|
* @param {object} data - The data to send
|
2021-04-29 13:49:39 +10:00
|
|
|
* @param {string=} channel - The channel to send to
|
|
|
|
|
* @param {string=} chunkId
|
2020-07-16 17:27:39 +10:00
|
|
|
*/
|
|
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
type peerReply = (id: string, data: SimplePeerData, channel: string) => void;
|
|
|
|
|
|
2021-02-20 14:40:00 +11:00
|
|
|
/**
|
|
|
|
|
* Session Status Event - Status of the session has changed
|
|
|
|
|
*
|
|
|
|
|
* @event Session#status
|
2021-04-11 18:01:34 +10:00
|
|
|
* @property {"ready"|"joining"|"joined"|"offline"|"reconnecting"|"auth"|"needs_update"} status
|
2021-02-20 14:40:00 +11:00
|
|
|
*/
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* Handles connections to multiple peers
|
|
|
|
|
*
|
2020-12-12 16:08:10 +11:00
|
|
|
* @fires Session#peerConnect
|
|
|
|
|
* @fires Session#peerData
|
|
|
|
|
* @fires Session#peerTrackAdded
|
|
|
|
|
* @fires Session#peerTrackRemoved
|
|
|
|
|
* @fires Session#peerDisconnect
|
|
|
|
|
* @fires Session#peerError
|
2021-02-20 14:40:00 +11:00
|
|
|
* @fires Session#status
|
2020-12-12 16:08:10 +11:00
|
|
|
* @fires Session#playerJoined
|
|
|
|
|
* @fires Session#playerLeft
|
2021-02-20 18:09:49 +11:00
|
|
|
* @fires Session#gameExpired
|
2020-07-16 17:27:39 +10:00
|
|
|
*/
|
|
|
|
|
class Session extends EventEmitter {
|
|
|
|
|
/**
|
|
|
|
|
* The socket io connection
|
|
|
|
|
*
|
2021-02-20 16:23:48 +11:00
|
|
|
* @type {io.Socket}
|
2020-07-16 17:27:39 +10:00
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
socket: Socket = io();
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A mapping of socket ids to session peers
|
|
|
|
|
*
|
|
|
|
|
* @type {Object.<string, SessionPeer>}
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
peers: Record<string, SessionPeer>;
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
get id() {
|
2020-11-26 11:09:48 +11:00
|
|
|
return this.socket && this.socket.id;
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
_iceServers: string[] = [];
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
// Store party id and password for reconnect
|
2021-05-25 17:35:26 +10:00
|
|
|
_gameId: string = "";
|
|
|
|
|
_password: string = "";
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
super();
|
|
|
|
|
this.peers = {};
|
|
|
|
|
// Signal connected peers of a closure on refresh
|
|
|
|
|
window.addEventListener("beforeunload", this._handleUnload.bind(this));
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Connect to the websocket
|
|
|
|
|
*/
|
2020-11-26 11:09:48 +11:00
|
|
|
async connect() {
|
|
|
|
|
try {
|
2021-05-25 17:35:26 +10:00
|
|
|
if (!process.env.REACT_APP_ICE_SERVERS_URL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-11-26 11:09:48 +11:00
|
|
|
const response = await fetch(process.env.REACT_APP_ICE_SERVERS_URL);
|
2020-11-26 18:54:32 +11:00
|
|
|
if (!response.ok) {
|
2020-11-26 18:55:27 +11:00
|
|
|
throw Error("Unable to fetch ICE servers");
|
2020-11-26 18:54:32 +11:00
|
|
|
}
|
2020-11-26 11:09:48 +11:00
|
|
|
const data = await response.json();
|
|
|
|
|
this._iceServers = data.iceServers;
|
|
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
if (!process.env.REACT_APP_BROKER_URL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-11-26 11:09:48 +11:00
|
|
|
this.socket = io(process.env.REACT_APP_BROKER_URL, {
|
2020-11-27 19:20:57 +11:00
|
|
|
withCredentials: true,
|
2021-03-19 12:22:59 +11:00
|
|
|
parser: msgParser,
|
2020-11-26 11:09:48 +11:00
|
|
|
});
|
|
|
|
|
|
2020-12-05 17:16:06 +11:00
|
|
|
this.socket.on("player_joined", this._handlePlayerJoined.bind(this));
|
|
|
|
|
this.socket.on("player_left", this._handlePlayerLeft.bind(this));
|
|
|
|
|
this.socket.on("joined_game", this._handleJoinedGame.bind(this));
|
2020-11-26 11:09:48 +11:00
|
|
|
this.socket.on("signal", this._handleSignal.bind(this));
|
2020-12-05 17:16:06 +11:00
|
|
|
this.socket.on("auth_error", this._handleAuthError.bind(this));
|
2021-02-20 18:09:49 +11:00
|
|
|
this.socket.on("game_expired", this._handleGameExpired.bind(this));
|
2020-11-26 11:09:48 +11:00
|
|
|
this.socket.on("disconnect", this._handleSocketDisconnect.bind(this));
|
|
|
|
|
this.socket.io.on("reconnect", this._handleSocketReconnect.bind(this));
|
2021-04-11 18:01:34 +10:00
|
|
|
this.socket.on("force_update", this._handleForceUpdate.bind(this));
|
2020-11-26 11:09:48 +11:00
|
|
|
|
2021-02-20 14:40:00 +11:00
|
|
|
this.emit("status", "ready");
|
2020-11-26 11:09:48 +11:00
|
|
|
} catch (error) {
|
|
|
|
|
logError(error);
|
2021-02-20 14:40:00 +11:00
|
|
|
this.emit("status", "offline");
|
2020-11-26 11:09:48 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-20 16:23:37 +11:00
|
|
|
disconnect() {
|
2021-04-23 11:47:08 +10:00
|
|
|
this.socket?.disconnect();
|
2021-02-20 16:23:37 +11:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
/**
|
2020-12-12 16:30:55 +11:00
|
|
|
* Send data to a single peer
|
2020-07-16 17:27:39 +10:00
|
|
|
*
|
2020-12-12 16:30:55 +11:00
|
|
|
* @param {string} sessionId - The socket id of the player to send to
|
|
|
|
|
* @param {string} eventId - The id of the event to send
|
2020-07-16 17:27:39 +10:00
|
|
|
* @param {object} data
|
2021-04-29 13:49:39 +10:00
|
|
|
* @param {string=} channel
|
|
|
|
|
* @param {string=} chunkId
|
2020-07-16 17:27:39 +10:00
|
|
|
*/
|
2021-07-16 14:55:33 +10:00
|
|
|
sendTo(
|
|
|
|
|
sessionId: string,
|
|
|
|
|
eventId: string,
|
|
|
|
|
data,
|
|
|
|
|
channel?: string,
|
|
|
|
|
chunkId?: string
|
|
|
|
|
) {
|
2020-12-12 16:30:55 +11:00
|
|
|
if (!(sessionId in this.peers)) {
|
2021-01-21 08:44:46 +11:00
|
|
|
if (!this._addPeer(sessionId, true)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-12-12 17:36:56 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.peers[sessionId].ready) {
|
2020-12-12 16:30:55 +11:00
|
|
|
this.peers[sessionId].connection.once("connect", () => {
|
2021-01-20 18:07:23 +11:00
|
|
|
this.peers[sessionId].connection.sendObject(
|
|
|
|
|
{ id: eventId, data },
|
2021-04-29 13:49:39 +10:00
|
|
|
channel,
|
|
|
|
|
chunkId
|
2021-01-20 18:07:23 +11:00
|
|
|
);
|
2020-12-12 16:30:55 +11:00
|
|
|
});
|
|
|
|
|
} else {
|
2021-01-20 18:07:23 +11:00
|
|
|
this.peers[sessionId].connection.sendObject(
|
|
|
|
|
{ id: eventId, data },
|
|
|
|
|
channel
|
|
|
|
|
);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-11 13:24:39 +11:00
|
|
|
/**
|
2020-12-12 16:30:55 +11:00
|
|
|
* Start streaming to a peer
|
2020-12-11 13:24:39 +11:00
|
|
|
*
|
2020-12-12 16:30:55 +11:00
|
|
|
* @param {string} sessionId - The socket id of the player to stream to
|
|
|
|
|
* @param {MediaStreamTrack} track
|
|
|
|
|
* @param {MediaStream} stream
|
2020-12-11 13:24:39 +11:00
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
startStreamTo(
|
|
|
|
|
sessionId: string,
|
|
|
|
|
track: MediaStreamTrack,
|
|
|
|
|
stream: MediaStream
|
|
|
|
|
) {
|
2020-12-11 13:24:39 +11:00
|
|
|
if (!(sessionId in this.peers)) {
|
2021-01-21 08:44:46 +11:00
|
|
|
if (!this._addPeer(sessionId, true)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-12-12 17:36:56 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.peers[sessionId].ready) {
|
2020-12-11 13:24:39 +11:00
|
|
|
this.peers[sessionId].connection.once("connect", () => {
|
2020-12-12 16:30:55 +11:00
|
|
|
this.peers[sessionId].connection.addTrack(track, stream);
|
2020-12-11 13:24:39 +11:00
|
|
|
});
|
|
|
|
|
} else {
|
2020-12-12 16:30:55 +11:00
|
|
|
this.peers[sessionId].connection.addTrack(track, stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* End streaming to a peer
|
|
|
|
|
*
|
|
|
|
|
* @param {string} sessionId - The socket id of the player to stream to
|
|
|
|
|
* @param {MediaStreamTrack} track
|
|
|
|
|
* @param {MediaStream} stream
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
endStreamTo(sessionId: string, track: MediaStreamTrack, stream: MediaStream) {
|
2020-12-12 16:30:55 +11:00
|
|
|
if (sessionId in this.peers) {
|
|
|
|
|
this.peers[sessionId].connection.removeTrack(track, stream);
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
/**
|
|
|
|
|
* Join a party
|
|
|
|
|
*
|
2020-12-05 17:16:06 +11:00
|
|
|
* @param {string} gameId - the id of the party to join
|
2020-07-16 17:27:39 +10:00
|
|
|
* @param {string} password - the password of the party
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
async joinGame(gameId: string, password: string) {
|
2020-12-05 17:16:06 +11:00
|
|
|
if (typeof gameId !== "string" || typeof password !== "string") {
|
2020-07-20 20:54:21 +10:00
|
|
|
console.error(
|
2020-12-05 17:16:06 +11:00
|
|
|
"Unable to join game: invalid game ID or password",
|
|
|
|
|
gameId,
|
2020-07-20 20:54:21 +10:00
|
|
|
password
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-05 17:16:06 +11:00
|
|
|
this._gameId = gameId;
|
2020-07-16 17:27:39 +10:00
|
|
|
this._password = password;
|
2021-05-25 17:35:26 +10:00
|
|
|
this.socket.emit(
|
|
|
|
|
"join_game",
|
|
|
|
|
gameId,
|
|
|
|
|
password,
|
|
|
|
|
process.env.REACT_APP_VERSION
|
|
|
|
|
);
|
2021-02-20 14:40:00 +11:00
|
|
|
this.emit("status", "joining");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-01-21 08:44:46 +11:00
|
|
|
/**
|
|
|
|
|
* Add a new peer connection
|
|
|
|
|
* @param {string} id
|
|
|
|
|
* @param {boolean} initiator
|
|
|
|
|
* @returns {boolean} True if peer was added successfully
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
_addPeer(id: string, initiator: boolean) {
|
2020-07-16 17:27:39 +10:00
|
|
|
try {
|
|
|
|
|
const connection = new Connection({
|
|
|
|
|
initiator,
|
|
|
|
|
trickle: true,
|
|
|
|
|
config: { iceServers: this._iceServers },
|
|
|
|
|
});
|
2021-01-20 18:07:23 +11:00
|
|
|
|
|
|
|
|
// Up max listeners to 100 to account for up to 100 tokens on load
|
|
|
|
|
connection.setMaxListeners && connection.setMaxListeners(100);
|
|
|
|
|
|
2020-12-12 17:36:56 +11:00
|
|
|
const peer = { id, connection, initiator, ready: false };
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-07-16 14:55:33 +10:00
|
|
|
function reply(id: string, data, channel?: string, chunkId?: string) {
|
2021-04-29 13:49:39 +10:00
|
|
|
peer.connection.sendObject({ id, data }, channel, chunkId);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-07-16 14:55:33 +10:00
|
|
|
const handleSignal = (signal) => {
|
2020-07-16 17:27:39 +10:00
|
|
|
this.socket.emit("signal", JSON.stringify({ to: peer.id, signal }));
|
2021-05-25 17:35:26 +10:00
|
|
|
};
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
const handleConnect = () => {
|
2020-12-12 17:36:56 +11:00
|
|
|
if (peer.id in this.peers) {
|
|
|
|
|
this.peers[peer.id].ready = true;
|
|
|
|
|
}
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Peer Connect Event - A peer has connected
|
|
|
|
|
*
|
|
|
|
|
* @event Session#peerConnect
|
|
|
|
|
* @type {object}
|
|
|
|
|
* @property {SessionPeer} peer
|
|
|
|
|
* @property {peerReply} reply
|
|
|
|
|
*/
|
2021-04-29 13:49:39 +10:00
|
|
|
this.emit("peerConnect", { peer, reply });
|
2021-07-16 14:55:33 +10:00
|
|
|
};
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-07-16 14:55:33 +10:00
|
|
|
const handleDataComplete = (data) => {
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Peer Data Event - Data received by a peer
|
|
|
|
|
*
|
|
|
|
|
* @event Session#peerData
|
|
|
|
|
* @type {object}
|
|
|
|
|
* @property {SessionPeer} peer
|
|
|
|
|
* @property {string} id
|
|
|
|
|
* @property {object} data
|
|
|
|
|
* @property {peerReply} reply
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
let peerDataEvent: {
|
|
|
|
|
peer: SessionPeer;
|
|
|
|
|
id: string;
|
2021-07-16 14:55:33 +10:00
|
|
|
data;
|
2021-05-25 17:35:26 +10:00
|
|
|
reply: peerReply;
|
|
|
|
|
} = {
|
2020-07-16 17:27:39 +10:00
|
|
|
peer,
|
|
|
|
|
id: data.id,
|
|
|
|
|
data: data.data,
|
2021-07-02 15:54:54 +10:00
|
|
|
reply: reply,
|
2021-05-25 17:35:26 +10:00
|
|
|
};
|
2021-07-16 14:55:33 +10:00
|
|
|
console.log(`Data: ${JSON.stringify(data)}`);
|
2021-05-25 17:35:26 +10:00
|
|
|
this.emit("peerData", peerDataEvent);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDataProgress = ({
|
|
|
|
|
id,
|
|
|
|
|
count,
|
|
|
|
|
total,
|
|
|
|
|
}: {
|
|
|
|
|
id: string;
|
|
|
|
|
count: number;
|
|
|
|
|
total: number;
|
|
|
|
|
}) => {
|
2021-01-01 13:25:35 +11:00
|
|
|
this.emit("peerDataProgress", {
|
|
|
|
|
peer,
|
|
|
|
|
id,
|
|
|
|
|
count,
|
|
|
|
|
total,
|
2021-04-29 13:49:39 +10:00
|
|
|
reply,
|
2021-01-01 13:25:35 +11:00
|
|
|
});
|
2021-05-25 17:35:26 +10:00
|
|
|
};
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
const handleTrack = (track: MediaStreamTrack, stream: MediaStream) => {
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Peer Track Added Event - A `MediaStreamTrack` was added by a peer
|
|
|
|
|
*
|
|
|
|
|
* @event Session#peerTrackAdded
|
|
|
|
|
* @type {object}
|
|
|
|
|
* @property {SessionPeer} peer
|
|
|
|
|
* @property {MediaStreamTrack} track
|
|
|
|
|
* @property {MediaStream} stream
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
let peerTrackAddedEvent: {
|
|
|
|
|
peer: SessionPeer;
|
|
|
|
|
track: MediaStreamTrack;
|
|
|
|
|
stream: MediaStream;
|
|
|
|
|
} = { peer, track, stream };
|
|
|
|
|
this.emit("peerTrackAdded", peerTrackAddedEvent);
|
2020-07-16 17:27:39 +10:00
|
|
|
track.addEventListener("mute", () => {
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Peer Track Removed Event - A `MediaStreamTrack` was removed by a peer
|
|
|
|
|
*
|
|
|
|
|
* @event Session#peerTrackRemoved
|
|
|
|
|
* @type {object}
|
|
|
|
|
* @property {SessionPeer} peer
|
|
|
|
|
* @property {MediaStreamTrack} track
|
|
|
|
|
* @property {MediaStream} stream
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
let peerTrackRemovedEvent: {
|
|
|
|
|
peer: SessionPeer;
|
|
|
|
|
track: MediaStreamTrack;
|
|
|
|
|
stream: MediaStream;
|
|
|
|
|
} = { peer, track, stream };
|
|
|
|
|
this.emit("peerTrackRemoved", peerTrackRemovedEvent);
|
2020-07-16 17:27:39 +10:00
|
|
|
});
|
2021-05-25 17:35:26 +10:00
|
|
|
};
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
const handleClose = () => {
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Peer Disconnect Event - A peer has disconnected
|
|
|
|
|
*
|
|
|
|
|
* @event Session#peerDisconnect
|
|
|
|
|
* @type {object}
|
|
|
|
|
* @property {SessionPeer} peer
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
let peerDisconnectEvent: { peer: SessionPeer } = { peer };
|
|
|
|
|
this.emit("peerDisconnect", peerDisconnectEvent);
|
2020-10-27 16:02:20 +11:00
|
|
|
if (peer.id in this.peers) {
|
|
|
|
|
peer.connection.destroy();
|
|
|
|
|
this.peers = omit(this.peers, [peer.id]);
|
|
|
|
|
}
|
2021-05-25 17:35:26 +10:00
|
|
|
};
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
const handleError = (error: Error) => {
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Peer Error Event - An error occured with a peer connection
|
|
|
|
|
*
|
|
|
|
|
* @event Session#peerError
|
|
|
|
|
* @type {object}
|
|
|
|
|
* @property {SessionPeer} peer
|
|
|
|
|
* @property {Error} error
|
|
|
|
|
*/
|
2021-05-25 17:35:26 +10:00
|
|
|
let peerErrorEvent: { peer: SessionPeer; error: Error } = {
|
|
|
|
|
peer,
|
|
|
|
|
error,
|
|
|
|
|
};
|
|
|
|
|
this.emit("peerError", peerErrorEvent);
|
2020-10-27 16:02:20 +11:00
|
|
|
if (peer.id in this.peers) {
|
|
|
|
|
peer.connection.destroy();
|
|
|
|
|
this.peers = omit(this.peers, [peer.id]);
|
2020-10-27 13:42:23 +11:00
|
|
|
}
|
2021-05-25 17:35:26 +10:00
|
|
|
};
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
peer.connection.on("signal", handleSignal.bind(this));
|
|
|
|
|
peer.connection.on("connect", handleConnect.bind(this));
|
|
|
|
|
peer.connection.on("dataComplete", handleDataComplete.bind(this));
|
|
|
|
|
peer.connection.on("dataProgress", handleDataProgress.bind(this));
|
|
|
|
|
peer.connection.on("track", handleTrack.bind(this));
|
|
|
|
|
peer.connection.on("close", handleClose.bind(this));
|
|
|
|
|
peer.connection.on("error", handleError.bind(this));
|
|
|
|
|
|
|
|
|
|
this.peers[id] = peer;
|
2021-01-21 08:44:46 +11:00
|
|
|
|
|
|
|
|
return true;
|
2020-07-16 17:27:39 +10:00
|
|
|
} catch (error) {
|
2020-10-27 10:26:55 +11:00
|
|
|
logError(error);
|
2020-12-12 16:08:10 +11:00
|
|
|
this.emit("peerError", { error });
|
2020-10-27 15:03:50 +11:00
|
|
|
for (let peer of Object.values(this.peers)) {
|
|
|
|
|
peer.connection && peer.connection.destroy();
|
|
|
|
|
}
|
2021-01-21 08:44:46 +11:00
|
|
|
return false;
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-11 13:24:39 +11:00
|
|
|
_handleJoinedGame() {
|
2021-02-20 14:40:00 +11:00
|
|
|
this.emit("status", "joined");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-02-20 18:09:49 +11:00
|
|
|
_handleGameExpired() {
|
|
|
|
|
/**
|
|
|
|
|
* Game Expired Event - A joining game has expired
|
|
|
|
|
*
|
|
|
|
|
* @event Session#gameExpired
|
|
|
|
|
*/
|
|
|
|
|
this.emit("gameExpired");
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
_handlePlayerJoined(id: string) {
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Player Joined Event - A player has joined the game
|
|
|
|
|
*
|
|
|
|
|
* @event Session#playerJoined
|
|
|
|
|
* @property {string} id
|
|
|
|
|
*/
|
2020-12-11 13:24:39 +11:00
|
|
|
this.emit("playerJoined", id);
|
2020-12-05 17:16:06 +11:00
|
|
|
}
|
|
|
|
|
|
2021-05-25 17:35:26 +10:00
|
|
|
_handlePlayerLeft(id: string) {
|
2020-12-12 16:08:10 +11:00
|
|
|
/**
|
|
|
|
|
* Player Left Event - A player has left the game
|
|
|
|
|
*
|
|
|
|
|
* @event Session#playerLeft
|
|
|
|
|
* @property {string} id
|
|
|
|
|
*/
|
2020-12-11 13:24:39 +11:00
|
|
|
this.emit("playerLeft", id);
|
2020-12-05 17:16:06 +11:00
|
|
|
if (id in this.peers) {
|
|
|
|
|
this.peers[id].connection.destroy();
|
|
|
|
|
delete this.peers[id];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 14:55:33 +10:00
|
|
|
_handleSignal(data) {
|
2020-11-21 16:15:04 +11:00
|
|
|
const { from, signal } = data;
|
2020-12-11 13:24:39 +11:00
|
|
|
if (!(from in this.peers)) {
|
2021-01-21 08:44:46 +11:00
|
|
|
if (!this._addPeer(from, false)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
this.peers[from].connection.signal(signal);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_handleAuthError() {
|
2021-02-20 14:40:00 +11:00
|
|
|
this.emit("status", "auth");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_handleUnload() {
|
|
|
|
|
for (let peer of Object.values(this.peers)) {
|
2021-01-03 17:52:14 +11:00
|
|
|
peer.connection && peer.connection.destroy();
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_handleSocketDisconnect() {
|
2021-02-20 14:40:00 +11:00
|
|
|
this.emit("status", "reconnecting");
|
2020-10-27 15:03:50 +11:00
|
|
|
for (let peer of Object.values(this.peers)) {
|
|
|
|
|
peer.connection && peer.connection.destroy();
|
|
|
|
|
}
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_handleSocketReconnect() {
|
2020-12-05 17:16:06 +11:00
|
|
|
if (this._gameId) {
|
|
|
|
|
this.joinGame(this._gameId, this._password);
|
2020-08-28 20:21:03 +10:00
|
|
|
}
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
2021-04-11 18:01:34 +10:00
|
|
|
|
|
|
|
|
_handleForceUpdate() {
|
|
|
|
|
/**
|
|
|
|
|
* Force Update Event - An update has been released
|
|
|
|
|
*
|
|
|
|
|
* @event Session#forceUpdate
|
|
|
|
|
*/
|
|
|
|
|
this.socket.disconnect();
|
|
|
|
|
this.emit("status", "needs_update");
|
|
|
|
|
}
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default Session;
|