Create and send close message
# TODO - Show error or wait room
This commit is contained in:
parent
326c2e4183
commit
7ac4a2b849
17 changed files with 700 additions and 1846 deletions
|
@ -81,10 +81,12 @@ class ConnectionManager {
|
|||
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);
|
||||
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 {
|
||||
|
|
|
@ -30,6 +30,8 @@ export enum EventMessage{
|
|||
TELEPORT = "teleport",
|
||||
USER_MESSAGE = "user-message",
|
||||
START_JITSI_ROOM = "start-jitsi-room",
|
||||
|
||||
CLOSE_MESSAGE = "close-message",
|
||||
}
|
||||
|
||||
export interface PointInterface {
|
||||
|
@ -73,7 +75,8 @@ export interface PositionInterface {
|
|||
|
||||
export interface GroupCreatedUpdatedMessageInterface {
|
||||
position: PositionInterface,
|
||||
groupId: number
|
||||
groupId: number,
|
||||
groupSize: number
|
||||
}
|
||||
|
||||
export interface WebRtcStartMessageInterface {
|
||||
|
|
|
@ -26,7 +26,8 @@ import {
|
|||
QueryJitsiJwtMessage,
|
||||
SendJitsiJwtMessage,
|
||||
CharacterLayerMessage,
|
||||
SendUserMessage
|
||||
SendUserMessage,
|
||||
CloseMessage
|
||||
} from "../Messages/generated/messages_pb"
|
||||
|
||||
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||
|
@ -157,10 +158,11 @@ export class RoomConnection implements RoomConnection {
|
|||
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
|
||||
} else if (message.hasSendusermessage()) {
|
||||
this.dispatch(EventMessage.USER_MESSAGE, message.getSendusermessage());
|
||||
} else if (message.hasClosemessage()) {
|
||||
this.dispatch(EventMessage.CLOSE_MESSAGE, message.getClosemessage());
|
||||
} else {
|
||||
throw new Error('Unknown message received');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +337,8 @@ export class RoomConnection implements RoomConnection {
|
|||
|
||||
return {
|
||||
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 {
|
||||
return this.tags.includes(tag);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com';
|
||||
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$';
|
||||
|
|
|
@ -110,6 +110,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
startX!: number;
|
||||
startY!: number;
|
||||
circleTexture!: CanvasTexture;
|
||||
circleRedTexture!: CanvasTexture;
|
||||
pendingEvents: Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface> = new Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface>();
|
||||
private initPosition: PositionInterface|null = null;
|
||||
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
||||
|
@ -411,11 +412,18 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
this.initCamera();
|
||||
|
||||
// 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) {
|
||||
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;
|
||||
context.beginPath();
|
||||
context.arc(48, 48, 48, 0, 2 * Math.PI, false);
|
||||
|
@ -424,6 +432,16 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
context.stroke();
|
||||
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
|
||||
if (this.connection === undefined) {
|
||||
// Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking
|
||||
|
@ -600,6 +618,11 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
this.startJitsi(room, jwt);
|
||||
});
|
||||
|
||||
connection.onCloseMessage((status: number) => {
|
||||
console.log(`close message status : ${status}`);
|
||||
//TODO show wait room
|
||||
});
|
||||
|
||||
// When connection is performed, let's connect SimplePeer
|
||||
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic);
|
||||
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
||||
|
@ -1135,18 +1158,27 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
|
||||
private doShareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
|
||||
const groupId = groupPositionMessage.groupId;
|
||||
const groupSize = groupPositionMessage.groupSize;
|
||||
|
||||
const group = this.groups.get(groupId);
|
||||
if (group !== undefined) {
|
||||
group.setPosition(Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.y));
|
||||
} else {
|
||||
// TODO: circle radius should not be hard stored
|
||||
const positionX = 48;
|
||||
const positionY = 48;
|
||||
|
||||
let texture = 'circleSprite-red';
|
||||
if(groupSize < 4){
|
||||
texture = 'circleSprite-white';
|
||||
}
|
||||
const sprite = new Sprite(
|
||||
this,
|
||||
Math.round(groupPositionMessage.position.x),
|
||||
Math.round(groupPositionMessage.position.y),
|
||||
'circleSprite');
|
||||
sprite.setDisplayOrigin(48, 48);
|
||||
texture
|
||||
);
|
||||
sprite.setDisplayOrigin(positionX, positionY);
|
||||
this.add.existing(sprite);
|
||||
this.groups.set(groupId, sprite);
|
||||
}
|
||||
|
@ -1278,6 +1310,10 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
|
||||
private loadSpritesheet(name: string, url: string): Promise<void> {
|
||||
return new Promise<void>(((resolve, reject) => {
|
||||
if (this.textures.exists(name)) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
this.load.spritesheet(
|
||||
name,
|
||||
url,
|
||||
|
|
|
@ -13,6 +13,8 @@ export class ScreenSharingPeer extends Peer {
|
|||
* Whether this connection is currently receiving a video stream from a remote user.
|
||||
*/
|
||||
private isReceivingStream:boolean = false;
|
||||
public toClose: boolean = false;
|
||||
public _connected: boolean = false;
|
||||
|
||||
constructor(private userId: number, initiator: boolean, private connection: RoomConnection) {
|
||||
super({
|
||||
|
@ -42,6 +44,8 @@ export class ScreenSharingPeer extends Peer {
|
|||
});
|
||||
|
||||
this.on('close', () => {
|
||||
this._connected = false;
|
||||
this.toClose = true;
|
||||
this.destroy();
|
||||
});
|
||||
|
||||
|
@ -62,11 +66,16 @@ export class ScreenSharingPeer extends Peer {
|
|||
});
|
||||
|
||||
this.on('connect', () => {
|
||||
this._connected = true;
|
||||
// FIXME: we need to put the loader on the screen sharing connection
|
||||
mediaManager.isConnected("" + this.userId);
|
||||
console.info(`connect => ${this.userId}`);
|
||||
});
|
||||
|
||||
this.once('finish', () => {
|
||||
this._onFinish();
|
||||
});
|
||||
|
||||
this.pushScreenSharingToRemoteUser();
|
||||
}
|
||||
|
||||
|
@ -100,6 +109,10 @@ export class ScreenSharingPeer extends Peer {
|
|||
|
||||
public destroy(error?: Error): void {
|
||||
try {
|
||||
this._connected = false
|
||||
if(!this.toClose){
|
||||
return;
|
||||
}
|
||||
mediaManager.removeActiveScreenSharingVideo("" + this.userId);
|
||||
// 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.
|
||||
|
@ -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() {
|
||||
const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture;
|
||||
if(!localScreenCapture){
|
||||
|
|
|
@ -108,44 +108,30 @@ export class SimplePeer {
|
|||
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
|
||||
*/
|
||||
private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null{
|
||||
private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null {
|
||||
const peerConnection = this.PeerConnectionArray.get(user.userId)
|
||||
if(peerConnection){
|
||||
if(peerConnection.destroyed){
|
||||
if (peerConnection) {
|
||||
if (peerConnection.destroyed) {
|
||||
peerConnection.toClose = true;
|
||||
peerConnection.destroy();
|
||||
const peerConnexionDeleted = this.PeerConnectionArray.delete(user.userId);
|
||||
if(!peerConnexionDeleted){
|
||||
if (!peerConnexionDeleted) {
|
||||
throw 'Error to delete peer connection';
|
||||
}
|
||||
this.createPeerConnection(user);
|
||||
}else {
|
||||
} else {
|
||||
peerConnection.toClose = false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let name = user.name;
|
||||
if(!name){
|
||||
if (!name) {
|
||||
const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === user.userId);
|
||||
if(userSearch) {
|
||||
if (userSearch) {
|
||||
name = userSearch.name;
|
||||
}
|
||||
}
|
||||
|
@ -153,8 +139,8 @@ export class SimplePeer {
|
|||
mediaManager.removeActiveVideo("" + user.userId);
|
||||
|
||||
const reportCallback = this.enableReporting ? (comment: string) => {
|
||||
this.reportUser(user.userId, comment);
|
||||
}: undefined;
|
||||
this.reportUser(user.userId, comment);
|
||||
} : undefined;
|
||||
|
||||
mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
|
||||
|
||||
|
@ -179,9 +165,19 @@ export class SimplePeer {
|
|||
* create peer connection to bind users
|
||||
*/
|
||||
private createPeerScreenSharingConnection(user : UserSimplePeerInterface) : ScreenSharingPeer | null{
|
||||
if(
|
||||
this.PeerScreenSharingConnectionArray.has(user.userId)
|
||||
){
|
||||
const peerConnection = this.PeerScreenSharingConnectionArray.get(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,13 +39,13 @@ export class VideoPeer extends Peer {
|
|||
urls: 'stun:stun.l.google.com:19302'
|
||||
},
|
||||
{
|
||||
urls: TURN_SERVER,
|
||||
urls: TURN_SERVER.split(','),
|
||||
username: TURN_USER,
|
||||
credential: TURN_PASSWORD
|
||||
},
|
||||
]
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
//start listen signal for the peer connection
|
||||
this.on('signal', (data: unknown) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue