Merge pull request #355 from thecodingmachine/user-limit-grp

Create and send close message
This commit is contained in:
grégoire parant 2020-10-22 01:47:53 +02:00 committed by GitHub
commit f002170ed5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 284 additions and 70 deletions

View file

@ -162,11 +162,13 @@ export class IoSocketController {
let memberTags: string[] = []; let memberTags: string[] = [];
let memberTextures: CharacterTexture[] = []; let memberTextures: CharacterTexture[] = [];
const room = await socketManager.getOrCreateRoom(roomId); const room = await socketManager.getOrCreateRoom(roomId);
if (room.isFull()) { //TODO http return status
res.writeStatus("503").end('Too many users'); /*if (room.isFull) {
return; throw new Error('Room is full');
} }*/
try { try {
const userData = await adminApi.fetchMemberDataByUuid(userUuid); const userData = await adminApi.fetchMemberDataByUuid(userUuid);
//console.log('USERDATA', userData) //console.log('USERDATA', userData)
@ -234,30 +236,46 @@ export class IoSocketController {
}, },
/* Handlers */ /* Handlers */
open: (ws) => { open: (ws) => {
// Let's join the room (async () => {
const client = this.initClient(ws); //todo: into the upgrade instead? // Let's join the room
socketManager.handleJoinRoom(client); const client = this.initClient(ws); //todo: into the upgrade instead?
resetPing(client);
//get data information and shwo messages const room = socketManager.getRoomById(client.roomId);
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => { if (room && room.isFull) {
if (!res.messages) { socketManager.emitCloseMessage(client, 302);
return; }else {
socketManager.handleJoinRoom(client);
resetPing(client);
} }
res.messages.forEach((c: unknown) => {
const messageToSend = c as { type: string, message: string }; //get data information and shwo messages
socketManager.emitSendUserMessage({ try {
userUuid: client.userUuid, const res: FetchMemberDataByUuidResponse = await adminApi.fetchMemberDataByUuid(client.userUuid);
type: messageToSend.type, if (!res.messages) {
message: messageToSend.message return;
}) }
}); res.messages.forEach((c: unknown) => {
}).catch((err) => { const messageToSend = c as { type: string, message: string };
console.error('fetchMemberDataByUuid => err', err); socketManager.emitSendUserMessage({
}); userUuid: client.userUuid,
type: messageToSend.type,
message: messageToSend.message
})
});
} catch (err) {
console.error('fetchMemberDataByUuid => err', err);
}
})();
}, },
message: (ws, arrayBuffer, isBinary): void => { message: (ws, arrayBuffer, isBinary): void => {
const client = ws as ExSocketInterface; const client = ws as ExSocketInterface;
const room = socketManager.getRoomById(client.roomId);
if (room && room.isFull) {
return;
}
const message = ClientToServerMessage.deserializeBinary(new Uint8Array(arrayBuffer)); const message = ClientToServerMessage.deserializeBinary(new Uint8Array(arrayBuffer));
if (message.hasViewportmessage()) { if (message.hasViewportmessage()) {
@ -281,7 +299,6 @@ export class IoSocketController {
} else if (message.hasQueryjitsijwtmessage()){ } else if (message.hasQueryjitsijwtmessage()){
socketManager.handleQueryJitsiJwtMessage(client, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage); socketManager.handleQueryJitsiJwtMessage(client, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
} }
/* Ok is false if backpressure was built up, wait for drain */ /* Ok is false if backpressure was built up, wait for drain */
//let ok = ws.send(message, isBinary); //let ok = ws.send(message, isBinary);
}, },

View file

@ -85,7 +85,7 @@ export class MapController extends BaseController{
res.writeStatus('404').end('No room found'); res.writeStatus('404').end('No room found');
return; return;
} }
res.writeStatus("200").end(world.isFull() ? '1':'0'); res.writeStatus("200").end(world.isFull ? '1':'0');
}); });
} }
} }

View file

@ -10,7 +10,7 @@ import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {Movable} from "_Model/Movable"; import {Movable} from "_Model/Movable";
import {extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous} from "./RoomIdentifier"; import {extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous} from "./RoomIdentifier";
import {arrayIntersect} from "../Services/ArrayHelper"; import {arrayIntersect} from "../Services/ArrayHelper";
import {MAX_USERS_PER_ROOM} from "_Enum/EnvironmentVariable"; import {MAX_USERS_PER_ROOM} from "../Enum/EnvironmentVariable";
export type ConnectCallback = (user: User, group: Group) => void; export type ConnectCallback = (user: User, group: Group) => void;
export type DisconnectCallback = (user: User, group: Group) => void; export type DisconnectCallback = (user: User, group: Group) => void;
@ -180,7 +180,7 @@ export class GameRoom {
} }
} }
isFull() : boolean { get isFull() : boolean {
return this.getUsers().size > MAX_USERS_PER_ROOM; return this.getUsers().size > MAX_USERS_PER_ROOM;
} }

View file

@ -117,4 +117,8 @@ export class Group implements Movable {
this.leave(user); this.leave(user);
} }
} }
get getSize(){
return this.users.size;
}
} }

View file

@ -24,7 +24,8 @@ import {
QueryJitsiJwtMessage, QueryJitsiJwtMessage,
SendJitsiJwtMessage, SendJitsiJwtMessage,
CharacterLayerMessage, CharacterLayerMessage,
SendUserMessage SendUserMessage,
CloseMessage
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
import {PointInterface} from "../Model/Websocket/PointInterface"; import {PointInterface} from "../Model/Websocket/PointInterface";
import {User} from "../Model/User"; import {User} from "../Model/User";
@ -130,6 +131,7 @@ export class SocketManager {
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position)); userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position));
roomJoinedMessage.addUser(userJoinedMessage); roomJoinedMessage.addUser(userJoinedMessage);
roomJoinedMessage.setTagList(client.tags);
} else if (thing instanceof Group) { } else if (thing instanceof Group) {
const groupUpdateMessage = new GroupUpdateMessage(); const groupUpdateMessage = new GroupUpdateMessage();
groupUpdateMessage.setGroupid(thing.getId()); groupUpdateMessage.setGroupid(thing.getId());
@ -406,6 +408,10 @@ export class SocketManager {
return Promise.resolve(world) return Promise.resolve(world)
} }
getRoomById(roomId: string) {
return this.Worlds.get(roomId);
}
private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom { private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom {
const roomId = client.roomId; const roomId = client.roomId;
@ -493,6 +499,7 @@ export class SocketManager {
const groupUpdateMessage = new GroupUpdateMessage(); const groupUpdateMessage = new GroupUpdateMessage();
groupUpdateMessage.setGroupid(group.getId()); groupUpdateMessage.setGroupid(group.getId());
groupUpdateMessage.setPosition(pointMessage); groupUpdateMessage.setPosition(pointMessage);
groupUpdateMessage.setGroupsize(group.getSize);
const subMessage = new SubMessage(); const subMessage = new SubMessage();
subMessage.setGroupupdatemessage(groupUpdateMessage); subMessage.setGroupupdatemessage(groupUpdateMessage);
@ -692,6 +699,19 @@ export class SocketManager {
return socket; return socket;
} }
public emitCloseMessage(socket: ExSocketInterface, status: number): ExSocketInterface {
const closeMessage = new CloseMessage();
closeMessage.setStatus(status);
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setClosemessage(closeMessage);
if (!socket.disconnecting) {
socket.send(serverToClientMessage.serializeBinary().buffer, true);
}
return socket;
}
/** /**
* Merges the characterLayers received from the front (as an array of string) with the custom textures from the back. * Merges the characterLayers received from the front (as an array of string) with the custom textures from the back.
*/ */

View file

@ -81,10 +81,12 @@ class ConnectionManager {
await Axios.get(`${API_URL}/verify`, {params: {token}}); await Axios.get(`${API_URL}/verify`, {params: {token}});
} }
private async anonymousLogin(): Promise<void> { public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
const data = await Axios.post(`${API_URL}/anonymLogin`).then(res => res.data); const data = await Axios.post(`${API_URL}/anonymLogin`).then(res => res.data);
this.localUser = new LocalUser(data.userUuid, data.authToken, []); this.localUser = new LocalUser(data.userUuid, data.authToken, []);
localUserStore.saveUser(this.localUser); if (!isBenchmark) { // In benchmark, we don't have a local storage.
localUserStore.saveUser(this.localUser);
}
} }
public initBenchmark(): void { public initBenchmark(): void {
@ -95,8 +97,7 @@ class ConnectionManager {
return new Promise<RoomConnection>((resolve, reject) => { return new Promise<RoomConnection>((resolve, reject) => {
const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport); const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport);
connection.onConnectError((error: object) => { connection.onConnectError((error: object) => {
console.log(error); if (error) { //todo: how to check error type?
if (false) { //todo: how to check error type?
reject(connexionErrorTypes.tooManyUsers); reject(connexionErrorTypes.tooManyUsers);
} else { } else {
reject(connexionErrorTypes.serverError); reject(connexionErrorTypes.serverError);

View file

@ -30,6 +30,8 @@ export enum EventMessage{
TELEPORT = "teleport", TELEPORT = "teleport",
USER_MESSAGE = "user-message", USER_MESSAGE = "user-message",
START_JITSI_ROOM = "start-jitsi-room", START_JITSI_ROOM = "start-jitsi-room",
CLOSE_MESSAGE = "close-message",
} }
export interface PointInterface { export interface PointInterface {
@ -73,7 +75,8 @@ export interface PositionInterface {
export interface GroupCreatedUpdatedMessageInterface { export interface GroupCreatedUpdatedMessageInterface {
position: PositionInterface, position: PositionInterface,
groupId: number groupId: number,
groupSize: number
} }
export interface WebRtcStartMessageInterface { export interface WebRtcStartMessageInterface {

View file

@ -26,7 +26,8 @@ import {
QueryJitsiJwtMessage, QueryJitsiJwtMessage,
SendJitsiJwtMessage, SendJitsiJwtMessage,
CharacterLayerMessage, CharacterLayerMessage,
SendUserMessage SendUserMessage,
CloseMessage
} from "../Messages/generated/messages_pb" } from "../Messages/generated/messages_pb"
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer"; import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
@ -157,10 +158,11 @@ export class RoomConnection implements RoomConnection {
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage()); this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
} else if (message.hasSendusermessage()) { } else if (message.hasSendusermessage()) {
this.dispatch(EventMessage.USER_MESSAGE, message.getSendusermessage()); this.dispatch(EventMessage.USER_MESSAGE, message.getSendusermessage());
} else if (message.hasClosemessage()) {
this.dispatch(EventMessage.CLOSE_MESSAGE, message.getClosemessage());
} else { } else {
throw new Error('Unknown message received'); throw new Error('Unknown message received');
} }
} }
} }
@ -335,7 +337,8 @@ export class RoomConnection implements RoomConnection {
return { return {
groupId: message.getGroupid(), groupId: message.getGroupid(),
position: position.toObject() position: position.toObject(),
groupSize: message.getGroupsize()
} }
} }
@ -540,6 +543,12 @@ export class RoomConnection implements RoomConnection {
}); });
} }
public onCloseMessage(callback: (status: number) => void): void {
return this.onMessage(EventMessage.CLOSE_MESSAGE, (message: CloseMessage) => {
callback(message.getStatus());
});
}
public hasTag(tag: string): boolean { public hasTag(tag: string): boolean {
return this.tags.includes(tag); return this.tags.includes(tag);
} }

View file

@ -1,5 +1,5 @@
const DEBUG_MODE: boolean = process.env.DEBUG_MODE == "true"; const DEBUG_MODE: boolean = process.env.DEBUG_MODE == "true";
const API_URL = (typeof(window) !== 'undefined' ? window.location.protocol : 'http:') + '//' + (process.env.API_URL || "api.workadventure.localhost"); const API_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.API_URL || "api.workadventure.localhost");
const TURN_SERVER: string = process.env.TURN_SERVER || "turn:numb.viagenie.ca"; const TURN_SERVER: string = process.env.TURN_SERVER || "turn:numb.viagenie.ca";
const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com'; const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com';
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$'; const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$';

View file

@ -56,6 +56,7 @@ import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMes
import {ResizableScene} from "../Login/ResizableScene"; import {ResizableScene} from "../Login/ResizableScene";
import {Room} from "../../Connexion/Room"; import {Room} from "../../Connexion/Room";
import {MessageUI} from "../../Logger/MessageUI"; import {MessageUI} from "../../Logger/MessageUI";
import {WaitScene} from "../Reconnecting/WaitScene";
export enum Textures { export enum Textures {
@ -110,6 +111,7 @@ export class GameScene extends ResizableScene implements CenterListener {
startX!: number; startX!: number;
startY!: number; startY!: number;
circleTexture!: CanvasTexture; circleTexture!: CanvasTexture;
circleRedTexture!: CanvasTexture;
pendingEvents: Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface> = new Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface>(); pendingEvents: Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface> = new Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface>();
private initPosition: PositionInterface|null = null; private initPosition: PositionInterface|null = null;
private playersPositionInterpolator = new PlayersPositionInterpolator(); private playersPositionInterpolator = new PlayersPositionInterpolator();
@ -411,11 +413,18 @@ export class GameScene extends ResizableScene implements CenterListener {
this.initCamera(); this.initCamera();
// Let's generate the circle for the group delimiter // Let's generate the circle for the group delimiter
const circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite'); let circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-white');
if (circleElement) { if (circleElement) {
this.textures.remove('circleSprite'); this.textures.remove('circleSprite-white');
} }
this.circleTexture = this.textures.createCanvas('circleSprite', 96, 96);
circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-red');
if (circleElement) {
this.textures.remove('circleSprite-red');
}
//create white circle canvas use to create sprite
this.circleTexture = this.textures.createCanvas('circleSprite-white', 96, 96);
const context = this.circleTexture.context; const context = this.circleTexture.context;
context.beginPath(); context.beginPath();
context.arc(48, 48, 48, 0, 2 * Math.PI, false); context.arc(48, 48, 48, 0, 2 * Math.PI, false);
@ -424,6 +433,16 @@ export class GameScene extends ResizableScene implements CenterListener {
context.stroke(); context.stroke();
this.circleTexture.refresh(); this.circleTexture.refresh();
//create red circle canvas use to create sprite
this.circleRedTexture = this.textures.createCanvas('circleSprite-red', 96, 96);
const contextRed = this.circleRedTexture.context;
contextRed.beginPath();
contextRed.arc(48, 48, 48, 0, 2 * Math.PI, false);
// context.lineWidth = 5;
contextRed.strokeStyle = '#ff0000';
contextRed.stroke();
this.circleRedTexture.refresh();
// Let's pause the scene if the connection is not established yet // Let's pause the scene if the connection is not established yet
if (this.connection === undefined) { if (this.connection === undefined) {
// Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking // Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking
@ -600,6 +619,36 @@ export class GameScene extends ResizableScene implements CenterListener {
this.startJitsi(room, jwt); this.startJitsi(room, jwt);
}); });
connection.onCloseMessage((status: number) => {
console.log(`close message status : ${status}`);
//TODO show wait room
this.connection.closeConnection();
this.simplePeer.unregister();
connection.closeConnection();
const waitGameSceneKey = 'somekey' + Math.round(Math.random() * 10000);
//show wait scene
setTimeout(() => {
const game: Phaser.Scene = new WaitScene(waitGameSceneKey, status);
this.scene.add(waitGameSceneKey, game, true, {
initPosition: {
x: this.CurrentPlayer.x,
y: this.CurrentPlayer.y
}
});
this.scene.stop(this.scene.key);
this.scene.start(waitGameSceneKey);
}, 500);
//trying to reload map
setTimeout(() => {
this.scene.stop(waitGameSceneKey);
this.scene.remove(waitGameSceneKey);
this.scene.start(this.scene.key);
}, 30000);
});
// When connection is performed, let's connect SimplePeer // When connection is performed, let's connect SimplePeer
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic); this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic);
this.GlobalMessageManager = new GlobalMessageManager(this.connection); this.GlobalMessageManager = new GlobalMessageManager(this.connection);
@ -1135,18 +1184,28 @@ export class GameScene extends ResizableScene implements CenterListener {
private doShareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) { private doShareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
const groupId = groupPositionMessage.groupId; const groupId = groupPositionMessage.groupId;
const groupSize = groupPositionMessage.groupSize;
const group = this.groups.get(groupId); const group = this.groups.get(groupId);
if (group !== undefined) { if (group !== undefined) {
group.setPosition(Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.y)); group.setPosition(Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.y));
} else { } else {
// TODO: circle radius should not be hard stored // TODO: circle radius should not be hard stored
const positionX = 48;
const positionY = 48;
console.log('doShareGroupPosition', groupSize);
let texture = 'circleSprite-red';
if(groupSize < 4){
texture = 'circleSprite-white';
}
const sprite = new Sprite( const sprite = new Sprite(
this, this,
Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.x),
Math.round(groupPositionMessage.position.y), Math.round(groupPositionMessage.position.y),
'circleSprite'); texture
sprite.setDisplayOrigin(48, 48); );
sprite.setDisplayOrigin(positionX, positionY);
this.add.existing(sprite); this.add.existing(sprite);
this.groups.set(groupId, sprite); this.groups.set(groupId, sprite);
} }
@ -1278,6 +1337,10 @@ export class GameScene extends ResizableScene implements CenterListener {
private loadSpritesheet(name: string, url: string): Promise<void> { private loadSpritesheet(name: string, url: string): Promise<void> {
return new Promise<void>(((resolve, reject) => { return new Promise<void>(((resolve, reject) => {
if (this.textures.exists(name)) {
resolve();
return;
}
this.load.spritesheet( this.load.spritesheet(
name, name,
url, url,

View file

@ -0,0 +1,70 @@
import {TextField} from "../Components/TextField";
import Image = Phaser.GameObjects.Image;
enum ReconnectingTextures {
icon = "icon",
mainFont = "main_font"
}
export class WaitScene extends Phaser.Scene {
private reconnectingField!: TextField;
private logo!: Image;
private text: string = '';
constructor(key: string, private readonly status: number) {
super({
key: key
});
this.initialiseText();
}
initialiseText() {
this.text = `${this.status}` + '\n' + '\n';
switch (this.status) {
case 302:
this.text += 'Aie ! Work Adventure est victime de son succes, ' +
'\n' +
'\n' +
'le nombre maximum de joueurs a ete atteint !' +
'\n' +
'\n' +
`Reconnexion dans 30 secondes ...`;
break;
}
}
preload() {
this.load.image(ReconnectingTextures.icon, "resources/logos/tcm_full.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(ReconnectingTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
this.load.spritesheet(
'cat',
'resources/characters/pipoya/Cat 01-1.png',
{frameWidth: 32, frameHeight: 32}
);
}
create() {
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, ReconnectingTextures.icon);
this.add.existing(this.logo);
this.reconnectingField = new TextField(
this,
this.game.renderer.width / 2,
this.game.renderer.height / 2,
this.text);
const cat = this.physics.add.sprite(
this.game.renderer.width / 2,
this.game.renderer.height / 2 - 70,
'cat');
this.anims.create({
key: 'right',
frames: this.anims.generateFrameNumbers('cat', {start: 6, end: 8}),
frameRate: 10,
repeat: -1
});
cat.play('right');
}
}

View file

@ -13,6 +13,8 @@ export class ScreenSharingPeer extends Peer {
* Whether this connection is currently receiving a video stream from a remote user. * Whether this connection is currently receiving a video stream from a remote user.
*/ */
private isReceivingStream:boolean = false; private isReceivingStream:boolean = false;
public toClose: boolean = false;
public _connected: boolean = false;
constructor(private userId: number, initiator: boolean, private connection: RoomConnection) { constructor(private userId: number, initiator: boolean, private connection: RoomConnection) {
super({ super({
@ -42,6 +44,8 @@ export class ScreenSharingPeer extends Peer {
}); });
this.on('close', () => { this.on('close', () => {
this._connected = false;
this.toClose = true;
this.destroy(); this.destroy();
}); });
@ -62,11 +66,16 @@ export class ScreenSharingPeer extends Peer {
}); });
this.on('connect', () => { this.on('connect', () => {
this._connected = true;
// FIXME: we need to put the loader on the screen sharing connection // FIXME: we need to put the loader on the screen sharing connection
mediaManager.isConnected("" + this.userId); mediaManager.isConnected("" + this.userId);
console.info(`connect => ${this.userId}`); console.info(`connect => ${this.userId}`);
}); });
this.once('finish', () => {
this._onFinish();
});
this.pushScreenSharingToRemoteUser(); this.pushScreenSharingToRemoteUser();
} }
@ -100,6 +109,10 @@ export class ScreenSharingPeer extends Peer {
public destroy(error?: Error): void { public destroy(error?: Error): void {
try { try {
this._connected = false
if(!this.toClose){
return;
}
mediaManager.removeActiveScreenSharingVideo("" + this.userId); mediaManager.removeActiveScreenSharingVideo("" + this.userId);
// FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray" // FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray"
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel. // I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
@ -111,6 +124,18 @@ export class ScreenSharingPeer extends Peer {
} }
} }
_onFinish () {
if (this.destroyed) return
const destroySoon = () => {
this.destroy();
}
if (this._connected) {
destroySoon();
} else {
this.once('connect', destroySoon);
}
}
private pushScreenSharingToRemoteUser() { private pushScreenSharingToRemoteUser() {
const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture; const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture;
if(!localScreenCapture){ if(!localScreenCapture){

View file

@ -108,44 +108,30 @@ export class SimplePeer {
this.createPeerConnection(user); this.createPeerConnection(user);
} }
/**
* server has two people connected, start the meet
*/
private startWebRtc() {
console.warn('startWebRtc startWebRtc');
this.Users.forEach((user: UserSimplePeerInterface) => {
//if it's not an initiator, peer connection will be created when gamer will receive offer signal
if(!user.initiator){
return;
}
this.createPeerConnection(user);
});
}
/** /**
* create peer connection to bind users * create peer connection to bind users
*/ */
private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null{ private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null {
const peerConnection = this.PeerConnectionArray.get(user.userId) const peerConnection = this.PeerConnectionArray.get(user.userId)
if(peerConnection){ if (peerConnection) {
if(peerConnection.destroyed){ if (peerConnection.destroyed) {
peerConnection.toClose = true; peerConnection.toClose = true;
peerConnection.destroy(); peerConnection.destroy();
const peerConnexionDeleted = this.PeerConnectionArray.delete(user.userId); const peerConnexionDeleted = this.PeerConnectionArray.delete(user.userId);
if(!peerConnexionDeleted){ if (!peerConnexionDeleted) {
throw 'Error to delete peer connection'; throw 'Error to delete peer connection';
} }
this.createPeerConnection(user); this.createPeerConnection(user);
}else { } else {
peerConnection.toClose = false; peerConnection.toClose = false;
} }
return null; return null;
} }
let name = user.name; let name = user.name;
if(!name){ if (!name) {
const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === user.userId); const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === user.userId);
if(userSearch) { if (userSearch) {
name = userSearch.name; name = userSearch.name;
} }
} }
@ -153,8 +139,8 @@ export class SimplePeer {
mediaManager.removeActiveVideo("" + user.userId); mediaManager.removeActiveVideo("" + user.userId);
const reportCallback = this.enableReporting ? (comment: string) => { const reportCallback = this.enableReporting ? (comment: string) => {
this.reportUser(user.userId, comment); this.reportUser(user.userId, comment);
}: undefined; } : undefined;
mediaManager.addActiveVideo("" + user.userId, reportCallback, name); mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
@ -179,9 +165,19 @@ export class SimplePeer {
* create peer connection to bind users * create peer connection to bind users
*/ */
private createPeerScreenSharingConnection(user : UserSimplePeerInterface) : ScreenSharingPeer | null{ private createPeerScreenSharingConnection(user : UserSimplePeerInterface) : ScreenSharingPeer | null{
if( const peerConnection = this.PeerScreenSharingConnectionArray.get(user.userId);
this.PeerScreenSharingConnectionArray.has(user.userId) if(peerConnection){
){ if(peerConnection.destroyed){
peerConnection.toClose = true;
peerConnection.destroy();
const peerConnexionDeleted = this.PeerScreenSharingConnectionArray.delete(user.userId);
if(!peerConnexionDeleted){
throw 'Error to delete peer connection';
}
this.createPeerConnection(user);
}else {
peerConnection.toClose = false;
}
return null; return null;
} }

View file

@ -39,13 +39,13 @@ export class VideoPeer extends Peer {
urls: 'stun:stun.l.google.com:19302' urls: 'stun:stun.l.google.com:19302'
}, },
{ {
urls: TURN_SERVER, urls: TURN_SERVER.split(','),
username: TURN_USER, username: TURN_USER,
credential: TURN_PASSWORD credential: TURN_PASSWORD
}, },
] ]
} }
}) });
//start listen signal for the peer connection //start listen signal for the peer connection
this.on('signal', (data: unknown) => { this.on('signal', (data: unknown) => {

View file

@ -125,6 +125,7 @@ message BatchMessage {
message GroupUpdateMessage { message GroupUpdateMessage {
int32 groupId = 1; int32 groupId = 1;
PointMessage position = 2; PointMessage position = 2;
int32 groupSize = 3;
} }
message GroupDeleteMessage { message GroupDeleteMessage {
@ -188,6 +189,10 @@ message SendUserMessage{
string message = 2; string message = 2;
} }
message CloseMessage{
int32 status = 1;
}
message ServerToClientMessage { message ServerToClientMessage {
oneof message { oneof message {
BatchMessage batchMessage = 1; BatchMessage batchMessage = 1;
@ -202,5 +207,6 @@ message ServerToClientMessage {
TeleportMessageMessage teleportMessageMessage = 10; TeleportMessageMessage teleportMessageMessage = 10;
SendJitsiJwtMessage sendJitsiJwtMessage = 11; SendJitsiJwtMessage sendJitsiJwtMessage = 11;
SendUserMessage sendUserMessage = 12; SendUserMessage sendUserMessage = 12;
CloseMessage closeMessage = 13;
} }
} }