Adding support to persist variables in Redis
This commit is contained in:
parent
18e4d2ba4e
commit
d955ddfe82
24 changed files with 397 additions and 120 deletions
|
@ -1,14 +1,16 @@
|
|||
/**
|
||||
* Handles variables shared between the scripting API and the server.
|
||||
*/
|
||||
import {ITiledMap, ITiledMapObject, ITiledMapObjectLayer} from "@workadventure/tiled-map-type-guard/dist";
|
||||
import {User} from "_Model/User";
|
||||
import { ITiledMap, ITiledMapObject, ITiledMapObjectLayer } from "@workadventure/tiled-map-type-guard/dist";
|
||||
import { User } from "_Model/User";
|
||||
import { variablesRepository } from "./Repository/VariablesRepository";
|
||||
import { redisClient } from "./RedisClient";
|
||||
|
||||
interface Variable {
|
||||
defaultValue?: string,
|
||||
persist?: boolean,
|
||||
readableBy?: string,
|
||||
writableBy?: string,
|
||||
defaultValue?: string;
|
||||
persist?: boolean;
|
||||
readableBy?: string;
|
||||
writableBy?: string;
|
||||
}
|
||||
|
||||
export class VariablesManager {
|
||||
|
@ -25,7 +27,7 @@ export class VariablesManager {
|
|||
/**
|
||||
* @param map The map can be "null" if it is hosted on a private network. In this case, we assume this is a test setup and bypass any server-side checks.
|
||||
*/
|
||||
constructor(private map: ITiledMap | null) {
|
||||
constructor(private roomUrl: string, private map: ITiledMap | null) {
|
||||
// We initialize the list of variable object at room start. The objects cannot be edited later
|
||||
// (otherwise, this would cause a security issue if the scripting API can edit this list of objects)
|
||||
if (map) {
|
||||
|
@ -40,14 +42,43 @@ export class VariablesManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Let's load data from the Redis backend.
|
||||
*/
|
||||
public async init(): Promise<void> {
|
||||
if (!this.shouldPersist()) {
|
||||
return;
|
||||
}
|
||||
const variables = await variablesRepository.loadVariables(this.roomUrl);
|
||||
console.error("LIST OF VARIABLES FETCHED", variables);
|
||||
for (const key in variables) {
|
||||
this._variables.set(key, variables[key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if saving should be enabled, and false otherwise.
|
||||
*
|
||||
* Saving is enabled if REDIS_HOST is set
|
||||
* unless we are editing a local map
|
||||
* unless we are in dev mode in which case it is ok to save
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private shouldPersist(): boolean {
|
||||
return redisClient !== null && (this.map !== null || process.env.NODE_ENV === "development");
|
||||
}
|
||||
|
||||
private static findVariablesInMap(map: ITiledMap): Map<string, Variable> {
|
||||
const objects = new Map<string, Variable>();
|
||||
for (const layer of map.layers) {
|
||||
if (layer.type === 'objectgroup') {
|
||||
if (layer.type === "objectgroup") {
|
||||
for (const object of (layer as ITiledMapObjectLayer).objects) {
|
||||
if (object.type === 'variable') {
|
||||
if (object.type === "variable") {
|
||||
if (object.template) {
|
||||
console.warn('Warning, a variable object is using a Tiled "template". WorkAdventure does not support objects generated from Tiled templates.')
|
||||
console.warn(
|
||||
'Warning, a variable object is using a Tiled "template". WorkAdventure does not support objects generated from Tiled templates.'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -67,26 +98,30 @@ export class VariablesManager {
|
|||
for (const property of object.properties) {
|
||||
const value = property.value;
|
||||
switch (property.name) {
|
||||
case 'default':
|
||||
case "default":
|
||||
variable.defaultValue = JSON.stringify(value);
|
||||
break;
|
||||
case 'persist':
|
||||
if (typeof value !== 'boolean') {
|
||||
case "persist":
|
||||
if (typeof value !== "boolean") {
|
||||
throw new Error('The persist property of variable "' + object.name + '" must be a boolean');
|
||||
}
|
||||
variable.persist = value;
|
||||
break;
|
||||
case 'writableBy':
|
||||
if (typeof value !== 'string') {
|
||||
throw new Error('The writableBy property of variable "' + object.name + '" must be a string');
|
||||
case "writableBy":
|
||||
if (typeof value !== "string") {
|
||||
throw new Error(
|
||||
'The writableBy property of variable "' + object.name + '" must be a string'
|
||||
);
|
||||
}
|
||||
if (value) {
|
||||
variable.writableBy = value;
|
||||
}
|
||||
break;
|
||||
case 'readableBy':
|
||||
if (typeof value !== 'string') {
|
||||
throw new Error('The readableBy property of variable "' + object.name + '" must be a string');
|
||||
case "readableBy":
|
||||
if (typeof value !== "string") {
|
||||
throw new Error(
|
||||
'The readableBy property of variable "' + object.name + '" must be a string'
|
||||
);
|
||||
}
|
||||
if (value) {
|
||||
variable.readableBy = value;
|
||||
|
@ -107,14 +142,27 @@ export class VariablesManager {
|
|||
throw new Error('Trying to set a variable "' + name + '" that is not defined as an object in the map.');
|
||||
}
|
||||
|
||||
if (variableObject.writableBy && user.tags.indexOf(variableObject.writableBy) === -1) {
|
||||
throw new Error('Trying to set a variable "' + name + '". User "' + user.name + '" does not have sufficient permission. Required tag: "' + variableObject.writableBy + '". User tags: ' + user.tags.join(', ') + ".");
|
||||
if (variableObject.writableBy && !user.tags.includes(variableObject.writableBy)) {
|
||||
throw new Error(
|
||||
'Trying to set a variable "' +
|
||||
name +
|
||||
'". User "' +
|
||||
user.name +
|
||||
'" does not have sufficient permission. Required tag: "' +
|
||||
variableObject.writableBy +
|
||||
'". User tags: ' +
|
||||
user.tags.join(", ") +
|
||||
"."
|
||||
);
|
||||
}
|
||||
|
||||
readableBy = variableObject.readableBy;
|
||||
}
|
||||
|
||||
this._variables.set(name, value);
|
||||
variablesRepository
|
||||
.saveVariable(this.roomUrl, name, value)
|
||||
.catch((e) => console.error("Error while saving variable in Redis:", e));
|
||||
return readableBy;
|
||||
}
|
||||
|
||||
|
@ -128,9 +176,9 @@ export class VariablesManager {
|
|||
for (const [key, value] of this._variables.entries()) {
|
||||
const variableObject = this.variableObjects.get(key);
|
||||
if (variableObject === undefined) {
|
||||
throw new Error('Unexpected variable "'+key+'" found has no associated variableObject.');
|
||||
throw new Error('Unexpected variable "' + key + '" found has no associated variableObject.');
|
||||
}
|
||||
if (!variableObject.readableBy || tags.indexOf(variableObject.readableBy) !== -1) {
|
||||
if (!variableObject.readableBy || tags.includes(variableObject.readableBy)) {
|
||||
readableVariables.set(key, value);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue