Switching WebRTC to protobuf + uws

This commit is contained in:
David Négrier 2020-09-29 16:01:22 +02:00
parent a9b1313d39
commit b485c9bf46
7 changed files with 253 additions and 129 deletions

View file

@ -37,7 +37,12 @@ import {
ErrorMessage,
RoomJoinedMessage,
ItemStateMessage,
ServerToClientMessage, SetUserIdMessage, SilentMessage
ServerToClientMessage,
SetUserIdMessage,
SilentMessage,
WebRtcSignalToClientMessage,
WebRtcSignalToServerMessage,
WebRtcStartMessage, WebRtcDisconnectMessage
} from "../Messages/generated/messages_pb";
import {UserMovesMessage} from "../Messages/generated/messages_pb";
import Direction = PositionMessage.Direction;
@ -186,7 +191,7 @@ export class IoSocketController {
/* Options */
//compression: uWS.SHARED_COMPRESSOR,
maxPayloadLength: 16 * 1024 * 1024,
idleTimeout: 10,
//idleTimeout: 10,
/* Handlers */
open: (ws) => {
this.authenticate(ws);
@ -222,6 +227,10 @@ export class IoSocketController {
this.handleSilentMessage(client, message.getSilentmessage() as SilentMessage);
} else if (message.hasItemeventmessage()) {
this.handleItemEvent(client, message.getItemeventmessage() as ItemEventMessage);
} else if (message.hasWebrtcsignaltoservermessage()) {
this.emitVideo(client, message.getWebrtcsignaltoservermessage() as WebRtcSignalToServerMessage)
} else if (message.hasWebrtcscreensharingsignaltoservermessage()) {
this.emitScreenSharing(client, message.getWebrtcscreensharingsignaltoservermessage() as WebRtcSignalToServerMessage)
}
/* Ok is false if backpressure was built up, wait for drain */
@ -282,7 +291,7 @@ export class IoSocketController {
serverToClientMessage.setErrormessage(errorMessage);
if (!Client.disconnecting) {
Client.send(serverToClientMessage.serializeBinary().buffer);
Client.send(serverToClientMessage.serializeBinary().buffer, true);
}
console.warn(message);
}
@ -496,40 +505,44 @@ export class IoSocketController {
}
}
emitVideo(socket: ExSocketInterface, data: unknown){
if (!isWebRtcSignalMessageInterface(data)) {
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SIGNAL message.'});
console.warn('Invalid WEBRTC_SIGNAL message received: ', data);
return;
}
emitVideo(socket: ExSocketInterface, data: WebRtcSignalToServerMessage): void {
//send only at user
const client = this.sockets.get(data.receiverId);
const client = this.sockets.get(data.getReceiverid());
if (client === undefined) {
console.warn("While exchanging a WebRTC signal: client with id ", data.receiverId, " does not exist. This might be a race condition.");
console.warn("While exchanging a WebRTC signal: client with id ", data.getReceiverid(), " does not exist. This might be a race condition.");
return;
}
return client.emit(SocketIoEvent.WEBRTC_SIGNAL, {
userId: socket.userId,
signal: data.signal
});
const webrtcSignalToClient = new WebRtcSignalToClientMessage();
webrtcSignalToClient.setUserid(socket.userId);
webrtcSignalToClient.setSignal(data.getSignal());
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setWebrtcsignaltoclientmessage(webrtcSignalToClient);
if (!client.disconnecting) {
client.send(serverToClientMessage.serializeBinary().buffer, true);
}
}
emitScreenSharing(socket: ExSocketInterface, data: unknown){
if (!isWebRtcSignalMessageInterface(data)) {
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SCREEN_SHARING message.'});
console.warn('Invalid WEBRTC_SCREEN_SHARING message received: ', data);
return;
}
emitScreenSharing(socket: ExSocketInterface, data: WebRtcSignalToServerMessage): void {
//send only at user
const client = this.sockets.get(data.receiverId);
const client = this.sockets.get(data.getReceiverid());
if (client === undefined) {
console.warn("While exchanging a WEBRTC_SCREEN_SHARING signal: client with id ", data.receiverId, " does not exist. This might be a race condition.");
console.warn("While exchanging a WEBRTC_SCREEN_SHARING signal: client with id ", data.getReceiverid(), " does not exist. This might be a race condition.");
return;
}
return client.emit(SocketIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, {
userId: socket.userId,
signal: data.signal
});
const webrtcSignalToClient = new WebRtcSignalToClientMessage();
webrtcSignalToClient.setUserid(socket.userId);
webrtcSignalToClient.setSignal(data.getSignal());
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setWebrtcscreensharingsignaltoclientmessage(webrtcSignalToClient);
if (!client.disconnecting) {
client.send(serverToClientMessage.serializeBinary().buffer, true);
}
}
searchClientByIdOrFail(userId: number): ExSocketInterface {
@ -571,9 +584,9 @@ export class IoSocketController {
//check and create new world for a room
let world = this.Worlds.get(roomId)
if(world === undefined){
world = new World((user1: number, group: Group) => {
this.connectedUser(user1, group);
}, (user1: number, group: Group) => {
world = new World((user1: User, group: Group) => {
this.joinWebRtcRoom(user1, group);
}, (user1: User, group: Group) => {
this.disConnectedUser(user1, group);
}, MINIMUM_DISTANCE, GROUP_RADIUS, (thing: Movable, listener: User) => {
const clientListener = this.searchClientByIdOrFail(listener.id);
@ -677,20 +690,49 @@ export class IoSocketController {
emitInBatch(client, subMessage);
}
/**
*
* @param socket
* @param roomId
*/
joinWebRtcRoom(socket: ExSocketInterface, roomId: string) {
// TODO: REBUILD THIS
return;
/* if (socket.webRtcRoomId === roomId) {
joinWebRtcRoom(user: User, group: Group) {
/*const roomId: string = "webrtcroom"+group.getId();
if (user.socket.webRtcRoomId === roomId) {
return;
}*/
// TODO: joinWebRtcRoom will be trigerred twice when joining the first time! Maybe we should fix the GROUP constructor to trigger only one event
console.log('joinWebRtcRoom FOR '+user.socket.name+" "+user.socket.userId);
for (const otherUser of group.getUsers()) {
if (user === otherUser) {
continue;
}
// Let's send 2 messages: one to the user joining the group and one to the other user
const webrtcStartMessage1 = new WebRtcStartMessage();
webrtcStartMessage1.setUserid(otherUser.id);
webrtcStartMessage1.setName(otherUser.socket.name);
webrtcStartMessage1.setInitiator(true);
const serverToClientMessage1 = new ServerToClientMessage();
serverToClientMessage1.setWebrtcstartmessage(webrtcStartMessage1);
if (!user.socket.disconnecting) {
user.socket.send(serverToClientMessage1.serializeBinary().buffer, true);
console.log('Sending webrtcstart initiator to '+user.socket.userId)
}
const webrtcStartMessage2 = new WebRtcStartMessage();
webrtcStartMessage2.setUserid(user.id);
webrtcStartMessage2.setName(user.socket.name);
webrtcStartMessage2.setInitiator(false);
const serverToClientMessage2 = new ServerToClientMessage();
serverToClientMessage2.setWebrtcstartmessage(webrtcStartMessage2);
if (!otherUser.socket.disconnecting) {
otherUser.socket.send(serverToClientMessage2.serializeBinary().buffer, true);
console.log('Sending webrtcstart to '+otherUser.socket.userId)
}
}
socket.join(roomId);
/* socket.join(roomId);
socket.webRtcRoomId = roomId;
//if two persons in room share
if (this.Io.sockets.adapter.rooms[roomId].length < 2) {
@ -737,43 +779,49 @@ export class IoSocketController {
]
**/
//connected user
connectedUser(userId: number, group: Group) {
/*let Client = this.sockets.get(userId);
if (Client === undefined) {
return;
}*/
const Client = this.searchClientByIdOrFail(userId);
this.joinWebRtcRoom(Client, "webrtcroom"+group.getId());
}
//disconnect user
disConnectedUser(userId: number, group: Group) {
// TODO: rebuild this
return;
disConnectedUser(user: User, group: Group) {
const Client = this.searchClientByIdOrFail(userId);
Client.to("webrtcroom"+group.getId()).emit(SocketIoEvent.WEBRTC_DISCONNECT, {
userId: userId
});
const Client = user.socket;
// Most of the time, sending a disconnect event to one of the players is enough (the player will close the connection
// which will be shut for the other player).
// However! In the rare case where the WebRTC connection is not yet established, if we close the connection on one of the player,
// the other player will try connecting until a timeout happens (during this time, the connection icon will be displayed for nothing).
// So we also send the disconnect event to the other player.
for (const user of group.getUsers()) {
Client.emit(SocketIoEvent.WEBRTC_DISCONNECT, {
userId: user.id
});
for (const otherUser of group.getUsers()) {
if (user === otherUser) {
continue;
}
const webrtcDisconnectMessage1 = new WebRtcDisconnectMessage();
webrtcDisconnectMessage1.setUserid(user.id);
const serverToClientMessage1 = new ServerToClientMessage();
serverToClientMessage1.setWebrtcdisconnectmessage(webrtcDisconnectMessage1);
if (!otherUser.socket.disconnecting) {
otherUser.socket.send(serverToClientMessage1.serializeBinary().buffer, true);
}
const webrtcDisconnectMessage2 = new WebRtcDisconnectMessage();
webrtcDisconnectMessage2.setUserid(otherUser.id);
const serverToClientMessage2 = new ServerToClientMessage();
serverToClientMessage2.setWebrtcdisconnectmessage(webrtcDisconnectMessage2);
if (!user.socket.disconnecting) {
user.socket.send(serverToClientMessage2.serializeBinary().buffer, true);
}
}
//disconnect webrtc room
if(!Client.webRtcRoomId){
/*if(!Client.webRtcRoomId){
return;
}
Client.leave(Client.webRtcRoomId);
delete Client.webRtcRoomId;
}*/
//Client.leave(Client.webRtcRoomId);
//delete Client.webRtcRoomId;
}
public getWorlds(): Map<string, World> {

View file

@ -87,7 +87,7 @@ export class Group implements Movable {
join(user: User): void
{
// Broadcast on the right event
this.connectCallback(user.id, this);
this.connectCallback(user, this);
this.users.add(user);
user.group = this;
}
@ -105,7 +105,7 @@ export class Group implements Movable {
}
// Broadcast on the right event
this.disconnectCallback(user.id, this);
this.disconnectCallback(user, this);
}
/**

View file

@ -4,6 +4,7 @@ import {Zone} from "_Model/Zone";
import {Movable} from "_Model/Movable";
import {PositionInterface} from "_Model/PositionInterface";
import {PositionNotifier} from "_Model/PositionNotifier";
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
export class User implements Movable {
public listenedZones: Set<Zone>;
@ -13,7 +14,8 @@ export class User implements Movable {
public id: number,
private position: PointInterface,
public silent: boolean,
private positionNotifier: PositionNotifier
private positionNotifier: PositionNotifier,
public readonly socket: ExSocketInterface
) {
this.listenedZones = new Set<Zone>();

View file

@ -11,8 +11,8 @@ import {PositionNotifier} from "./PositionNotifier";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {Movable} from "_Model/Movable";
export type ConnectCallback = (user: number, group: Group) => void;
export type DisconnectCallback = (user: number, group: Group) => void;
export type ConnectCallback = (user: User, group: Group) => void;
export type DisconnectCallback = (user: User, group: Group) => void;
export class World {
private readonly minDistance: number;
@ -55,8 +55,8 @@ export class World {
return this.users;
}
public join(socket : Identificable, userPosition: PointInterface): void {
const user = new User(socket.userId, userPosition, false, this.positionNotifier);
public join(socket : ExSocketInterface, userPosition: PointInterface): void {
const user = new User(socket.userId, userPosition, false, this.positionNotifier, socket);
this.users.set(socket.userId, user);
// Let's call update position to trigger the join / leave room
//this.updatePosition(socket, userPosition);