Fixing reconnection to server on back failure

This commit is contained in:
David Négrier 2020-12-03 16:39:44 +01:00
parent 2fba6956a6
commit a19edd4dc1
6 changed files with 87 additions and 47 deletions

View File

@ -96,7 +96,6 @@ export class GameRoom {
}
const position = ProtobufUtils.toPointInterface(positionMessage);
const user = new User(this.nextUserId, joinRoomMessage.getUseruuid(), position, false, this.positionNotifier, socket, joinRoomMessage.getTagList(), joinRoomMessage.getName(), ProtobufUtils.toCharacterLayerObjects(joinRoomMessage.getCharacterlayerList()));
this.nextUserId++;
this.users.set(user.id, user);

View File

@ -1,7 +1,7 @@
import Axios from "axios";
import {API_URL} from "../Enum/EnvironmentVariable";
import {RoomConnection} from "./RoomConnection";
import {PositionInterface, ViewportInterface} from "./ConnexionModels";
import {OnConnectInterface, PositionInterface, ViewportInterface} from "./ConnexionModels";
import {GameConnexionTypes, urlManager} from "../Url/UrlManager";
import {localUserStore} from "./LocalUserStore";
import {LocalUser} from "./LocalUser";
@ -88,24 +88,29 @@ class ConnectionManager {
this.localUser = new LocalUser('', 'test', []);
}
public connectToRoomSocket(roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface): Promise<RoomConnection> {
return new Promise<RoomConnection>((resolve, reject) => {
public connectToRoomSocket(roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface): Promise<OnConnectInterface> {
return new Promise<OnConnectInterface>((resolve, reject) => {
const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport);
connection.onConnectError((error: object) => {
console.log('An error occurred while connecting to socket server. Retrying');
reject(error);
});
// FIXME: onConnect should be triggered by the first JoinRoomEvent (instead of the connection)
connection.onConnect(() => {
console.warn('CONNECT RECEIVED');
resolve(connection);
})
connection.onConnectingError((event: CloseEvent) => {
console.log('An error occurred while connecting to socket server. Retrying');
reject(new Error('An error occurred while connecting to socket server. Retrying. Code: '+event.code+', Reason: '+event.reason));
});
connection.onConnect((connect: OnConnectInterface) => {
resolve(connect);
});
}).catch((err) => {
// Let's retry in 4-6 seconds
return new Promise<RoomConnection>((resolve, reject) => {
return new Promise<OnConnectInterface>((resolve, reject) => {
setTimeout(() => {
//todo: allow a way to break recurrsion?
//todo: allow a way to break recursion?
//todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely.
this.connectToRoomSocket(roomId, name, characterLayers, position, viewport).then((connection) => resolve(connection));
}, 4000 + Math.floor(Math.random() * 2000) );
});

View File

@ -2,13 +2,14 @@ import {PlayerAnimationNames} from "../Phaser/Player/Animation";
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
import {SignalData} from "simple-peer";
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/body_character";
import {RoomConnection} from "./RoomConnection";
export enum EventMessage{
CONNECT = "connect",
WEBRTC_SIGNAL = "webrtc-signal",
WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal",
WEBRTC_START = "webrtc-start",
START_ROOM = "start-room", // From server to client: list of all room users/groups/items
//START_ROOM = "start-room", // From server to client: list of all room users/groups/items
JOIN_ROOM = "join-room", // bi-directional
USER_POSITION = "user-position", // From client to server
USER_MOVED = "user-moved", // From server to client
@ -21,6 +22,7 @@ export enum EventMessage{
ITEM_EVENT = 'item-event',
CONNECT_ERROR = "connect_error",
CONNECTING_ERROR = "connecting_error",
SET_SILENT = "set_silent", // Set or unset the silent mode for this user.
SET_VIEWPORT = "set-viewport",
BATCH = "batch",
@ -132,3 +134,8 @@ export interface PlayGlobalMessageInterface {
type: string
message: string
}
export interface OnConnectInterface {
connection: RoomConnection,
room: RoomJoinedMessageInterface
}

View File

@ -36,7 +36,7 @@ import {ProtobufClientUtils} from "../Network/ProtobufClientUtils";
import {
EventMessage,
GroupCreatedUpdatedMessageInterface, ItemEventMessageInterface,
MessageUserJoined, PlayGlobalMessageInterface, PositionInterface,
MessageUserJoined, OnConnectInterface, PlayGlobalMessageInterface, PositionInterface,
RoomJoinedMessageInterface,
ViewportInterface, WebRtcDisconnectMessageInterface,
WebRtcSignalReceivedMessageInterface,
@ -86,14 +86,26 @@ export class RoomConnection implements RoomConnection {
this.socket.binaryType = 'arraybuffer';
let interval: ReturnType<typeof setInterval>|undefined = undefined;
this.socket.onopen = (ev) => {
//we manually ping every 20s to not be logged out by the server, even when the game is in background.
const pingMessage = new PingMessage();
setInterval(() => this.socket.send(pingMessage.serializeBinary().buffer), manualPingDelay);
interval = setInterval(() => this.socket.send(pingMessage.serializeBinary().buffer), manualPingDelay);
};
this.socket.addEventListener('close', (event) => {
if (interval) {
clearInterval(interval);
}
// If we are not connected yet (if a JoinRoomMessage was not sent), we need to retry.
if (this.userId === null) {
this.dispatch(EventMessage.CONNECTING_ERROR, event);
}
});
this.socket.onmessage = (messageEvent) => {
console.warn('message received');
const arrayBuffer: ArrayBuffer = messageEvent.data;
const message = ServerToClientMessage.deserializeBinary(new Uint8Array(arrayBuffer));
@ -138,13 +150,22 @@ export class RoomConnection implements RoomConnection {
this.userId = roomJoinedMessage.getCurrentuserid();
this.tags = roomJoinedMessage.getTagList();
this.dispatch(EventMessage.CONNECT, this);
//console.log('Dispatching CONNECT')
this.dispatch(EventMessage.CONNECT, {
connection: this,
room: {
//users,
//groups,
items
} as RoomJoinedMessageInterface
});
/*console.log('Dispatching START_ROOM')
this.dispatch(EventMessage.START_ROOM, {
//users,
//groups,
items
});
});*/
} else if (message.hasErrormessage()) {
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage());
} else if (message.hasWebrtcsignaltoclientmessage()) {
@ -354,6 +375,12 @@ export class RoomConnection implements RoomConnection {
});
}
public onConnectingError(callback: (event: CloseEvent) => void): void {
this.onMessage(EventMessage.CONNECTING_ERROR, (event: CloseEvent) => {
callback(event);
});
}
public onConnectError(callback: (error: Event) => void): void {
this.socket.addEventListener('error', callback)
}
@ -361,7 +388,7 @@ export class RoomConnection implements RoomConnection {
/*public onConnect(callback: (e: Event) => void): void {
this.socket.addEventListener('open', callback)
}*/
public onConnect(callback: (roomConnection: RoomConnection) => void): void {
public onConnect(callback: (roomConnection: OnConnectInterface) => void): void {
//this.socket.addEventListener('open', callback)
this.onMessage(EventMessage.CONNECT, callback);
}
@ -369,9 +396,9 @@ export class RoomConnection implements RoomConnection {
/**
* Triggered when we receive all the details of a room (users, groups, ...)
*/
public onStartRoom(callback: (event: RoomJoinedMessageInterface) => void): void {
/*public onStartRoom(callback: (event: RoomJoinedMessageInterface) => void): void {
this.onMessage(EventMessage.START_ROOM, callback);
}
}*/
public sendWebrtcSignal(signal: unknown, receiverId: number) {
const webRtcSignal = new WebRtcSignalToServerMessage();

View File

@ -3,7 +3,7 @@ import {
GroupCreatedUpdatedMessageInterface,
MessageUserJoined,
MessageUserMovedInterface,
MessageUserPositionInterface,
MessageUserPositionInterface, OnConnectInterface,
PointInterface,
PositionInterface,
RoomJoinedMessageInterface
@ -521,23 +521,14 @@ export class GameScene extends ResizableScene implements CenterListener {
top: camera.scrollY,
right: camera.scrollX + camera.width,
bottom: camera.scrollY + camera.height,
}).then((connection: RoomConnection) => {
this.connection = connection;
}).then((onConnect: OnConnectInterface) => {
this.connection = onConnect.connection;
//this.connection.emitPlayerDetailsMessage(gameManager.getPlayerName(), gameManager.getCharacterSelected())
connection.onStartRoom((roomJoinedMessage: RoomJoinedMessageInterface) => {
//this.initUsersPosition(roomJoinedMessage.users);
this.connectionAnswerPromiseResolve(roomJoinedMessage);
// Analyze tags to find if we are admin. If yes, show console.
if (this.connection.hasTag('admin')) {
this.ConsoleGlobalMessageManager = new ConsoleGlobalMessageManager(this.connection, this.userInputManager);
}
/*this.connection.onStartRoom((roomJoinedMessage: RoomJoinedMessageInterface) => {
this.scene.wake();
this.scene.sleep(ReconnectingSceneName);
});
connection.onUserJoins((message: MessageUserJoined) => {
});*/
this.connection.onUserJoins((message: MessageUserJoined) => {
const userMessage: AddPlayerInterface = {
userId: message.userId,
characterLayers: message.characterLayers,
@ -547,7 +538,7 @@ export class GameScene extends ResizableScene implements CenterListener {
this.addPlayer(userMessage);
});
connection.onUserMoved((message: UserMovedMessage) => {
this.connection.onUserMoved((message: UserMovedMessage) => {
const position = message.getPosition();
if (position === undefined) {
throw new Error('Position missing from UserMovedMessage');
@ -562,15 +553,15 @@ export class GameScene extends ResizableScene implements CenterListener {
this.updatePlayerPosition(messageUserMoved);
});
connection.onUserLeft((userId: number) => {
this.connection.onUserLeft((userId: number) => {
this.removePlayer(userId);
});
connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.shareGroupPosition(groupPositionMessage);
})
connection.onGroupDeleted((groupId: number) => {
this.connection.onGroupDeleted((groupId: number) => {
try {
this.deleteGroup(groupId);
} catch (e) {
@ -578,7 +569,7 @@ export class GameScene extends ResizableScene implements CenterListener {
}
})
connection.onServerDisconnected(() => {
this.connection.onServerDisconnected(() => {
console.log('Player disconnected from server. Reloading scene.');
this.simplePeer.closeAllConnections();
@ -599,7 +590,7 @@ export class GameScene extends ResizableScene implements CenterListener {
this.scene.remove(this.scene.key);
})
connection.onActionableEvent((message => {
this.connection.onActionableEvent((message => {
const item = this.actionableItems.get(message.itemId);
if (item === undefined) {
console.warn('Received an event about object "' + message.itemId + '" but cannot find this item on the map.');
@ -611,7 +602,7 @@ export class GameScene extends ResizableScene implements CenterListener {
/**
* Triggered when we receive the JWT token to connect to Jitsi
*/
connection.onStartJitsiRoom((jwt, room) => {
this.connection.onStartJitsiRoom((jwt, room) => {
this.startJitsi(room, jwt);
});
@ -641,7 +632,17 @@ export class GameScene extends ResizableScene implements CenterListener {
this.gameMap.setPosition(event.x, event.y);
})
return connection;
//this.initUsersPosition(roomJoinedMessage.users);
this.connectionAnswerPromiseResolve(onConnect.room);
// Analyze tags to find if we are admin. If yes, show console.
if (this.connection.hasTag('admin')) {
this.ConsoleGlobalMessageManager = new ConsoleGlobalMessageManager(this.connection, this.userInputManager);
}
console.log('wakingup');
this.scene.wake();
this.scene.sleep(ReconnectingSceneName);
return this.connection;
});
}

View File

@ -136,13 +136,13 @@ export class SocketManager implements ZoneEventListener {
console.warn('Connection lost to back server');
// Let's close the front connection if the back connection is closed. This way, we can retry connecting from the start.
if (!client.disconnecting) {
this.closeWebsocketConnection(client);
this.closeWebsocketConnection(client, 1011, 'Connection lost to back server');
}
console.log('A user left');
}).on('error', (err: Error) => {
console.error('Error in connection to back server:', err);
if (!client.disconnecting) {
this.closeWebsocketConnection(client);
this.closeWebsocketConnection(client, 1011, 'Error while connecting to back server');
}
});
@ -208,10 +208,11 @@ export class SocketManager implements ZoneEventListener {
}
}
closeWebsocketConnection(client: ExSocketInterface) {
private closeWebsocketConnection(client: ExSocketInterface, code: number, reason: string) {
client.disconnecting = true;
//this.leaveRoom(client);
client.close();
//client.close();
client.end(code, reason);
}
handleViewport(client: ExSocketInterface, viewport: ViewportMessage.AsObject) {