Retry loading map on variable error
If the back is getting an error (because the user has no right to set a variable), instead of failing directly, let's try to reload the map (maybe we have cached a wrong version of the map).
This commit is contained in:
parent
3487fa90e0
commit
82a1a5fc1e
@ -26,6 +26,7 @@ import { VariablesManager } from "../Services/VariablesManager";
|
|||||||
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
||||||
import { LocalUrlError } from "../Services/LocalUrlError";
|
import { LocalUrlError } from "../Services/LocalUrlError";
|
||||||
import { emitErrorOnRoomSocket } from "../Services/MessageHelpers";
|
import { emitErrorOnRoomSocket } from "../Services/MessageHelpers";
|
||||||
|
import { VariableError } from "../Services/VariableError";
|
||||||
|
|
||||||
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;
|
||||||
@ -336,30 +337,61 @@ export class GameRoom {
|
|||||||
// First, let's check if "user" is allowed to modify the variable.
|
// First, let's check if "user" is allowed to modify the variable.
|
||||||
const variableManager = await this.getVariableManager();
|
const variableManager = await this.getVariableManager();
|
||||||
|
|
||||||
const readableBy = variableManager.setVariable(name, value, user);
|
try {
|
||||||
|
const readableBy = variableManager.setVariable(name, value, user);
|
||||||
|
|
||||||
// If the variable was not changed, let's not dispatch anything.
|
// If the variable was not changed, let's not dispatch anything.
|
||||||
if (readableBy === false) {
|
if (readableBy === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should we batch those every 100ms?
|
// TODO: should we batch those every 100ms?
|
||||||
const variableMessage = new VariableWithTagMessage();
|
const variableMessage = new VariableWithTagMessage();
|
||||||
variableMessage.setName(name);
|
variableMessage.setName(name);
|
||||||
variableMessage.setValue(value);
|
variableMessage.setValue(value);
|
||||||
if (readableBy) {
|
if (readableBy) {
|
||||||
variableMessage.setReadableby(readableBy);
|
variableMessage.setReadableby(readableBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
const subMessage = new SubToPusherRoomMessage();
|
const subMessage = new SubToPusherRoomMessage();
|
||||||
subMessage.setVariablemessage(variableMessage);
|
subMessage.setVariablemessage(variableMessage);
|
||||||
|
|
||||||
const batchMessage = new BatchToPusherRoomMessage();
|
const batchMessage = new BatchToPusherRoomMessage();
|
||||||
batchMessage.addPayload(subMessage);
|
batchMessage.addPayload(subMessage);
|
||||||
|
|
||||||
// Dispatch the message on the room listeners
|
// Dispatch the message on the room listeners
|
||||||
for (const socket of this.roomListeners) {
|
for (const socket of this.roomListeners) {
|
||||||
socket.write(batchMessage);
|
socket.write(batchMessage);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof VariableError) {
|
||||||
|
// Ok, we have an error setting a variable. Either the user is trying to hack the map... or the map
|
||||||
|
// is not up to date. So let's try to reload the map from scratch.
|
||||||
|
if (this.variableManagerLastLoad === undefined) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
const lastLoaded = new Date().getTime() - this.variableManagerLastLoad.getTime();
|
||||||
|
if (lastLoaded < 10000) {
|
||||||
|
console.log(
|
||||||
|
'An error occurred while setting the "' +
|
||||||
|
name +
|
||||||
|
"\" variable. But we tried to reload the map less than 10 seconds ago, so let's fail."
|
||||||
|
);
|
||||||
|
// Do not try to reload if we tried to reload less than 10 seconds ago.
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the variable manager
|
||||||
|
this.variableManagerPromise = undefined;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'An error occurred while setting the "' + name + "\" variable. Let's reload the map and try again"
|
||||||
|
);
|
||||||
|
// Try to set the variable again!
|
||||||
|
await this.setVariable(name, value, user);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,11 +481,13 @@ export class GameRoom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private variableManagerPromise: Promise<VariablesManager> | undefined;
|
private variableManagerPromise: Promise<VariablesManager> | undefined;
|
||||||
|
private variableManagerLastLoad: Date | undefined;
|
||||||
|
|
||||||
private getVariableManager(): Promise<VariablesManager> {
|
private getVariableManager(): Promise<VariablesManager> {
|
||||||
if (!this.variableManagerPromise) {
|
if (!this.variableManagerPromise) {
|
||||||
this.variableManagerPromise = this.getMap()
|
this.variableManagerPromise = this.getMap()
|
||||||
.then((map) => {
|
.then((map) => {
|
||||||
|
this.variableManagerLastLoad = new Date();
|
||||||
const variablesManager = new VariablesManager(this.roomUrl, map);
|
const variablesManager = new VariablesManager(this.roomUrl, map);
|
||||||
return variablesManager.init();
|
return variablesManager.init();
|
||||||
})
|
})
|
||||||
|
9
back/src/Services/VariableError.ts
Normal file
9
back/src/Services/VariableError.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Errors related to variable handling.
|
||||||
|
*/
|
||||||
|
export class VariableError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
Object.setPrototypeOf(this, VariableError.prototype);
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import {
|
|||||||
import { User } from "_Model/User";
|
import { User } from "_Model/User";
|
||||||
import { variablesRepository } from "./Repository/VariablesRepository";
|
import { variablesRepository } from "./Repository/VariablesRepository";
|
||||||
import { redisClient } from "./RedisClient";
|
import { redisClient } from "./RedisClient";
|
||||||
|
import { VariableError } from "./VariableError";
|
||||||
|
|
||||||
interface Variable {
|
interface Variable {
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
@ -174,11 +175,13 @@ export class VariablesManager {
|
|||||||
if (this.variableObjects) {
|
if (this.variableObjects) {
|
||||||
variableObject = this.variableObjects.get(name);
|
variableObject = this.variableObjects.get(name);
|
||||||
if (variableObject === undefined) {
|
if (variableObject === undefined) {
|
||||||
throw new Error('Trying to set a variable "' + name + '" that is not defined as an object in the map.');
|
throw new VariableError(
|
||||||
|
'Trying to set a variable "' + name + '" that is not defined as an object in the map.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variableObject.writableBy && !user.tags.includes(variableObject.writableBy)) {
|
if (variableObject.writableBy && !user.tags.includes(variableObject.writableBy)) {
|
||||||
throw new Error(
|
throw new VariableError(
|
||||||
'Trying to set a variable "' +
|
'Trying to set a variable "' +
|
||||||
name +
|
name +
|
||||||
'". User "' +
|
'". User "' +
|
||||||
|
Loading…
Reference in New Issue
Block a user