annotations

This commit is contained in:
2024-11-27 12:46:03 +02:00
parent 54b8941f3c
commit ad4eef17f5
12 changed files with 514 additions and 36 deletions
+11 -1
View File
@@ -1,7 +1,17 @@
call jsdoc ../backend/app/App.js -t "./diagram-template/" -d "./out/App.h" call jsdoc ../backend/app/App.js -t "./diagram-template/" -d "./out/App.h"
call jsdoc ../backend/app/Config.js -t "./diagram-template/" -d "./out/Config.h" call jsdoc ../backend/app/Config.js -t "./diagram-template/" -d "./out/Config.h"
call jsdoc ../backend/app/Db.js -t "./diagram-template/" -d "./out/Db.h" call jsdoc ../backend/app/Db.js -t "./diagram-template/" -d "./out/Db.h"
call jsdoc ../backend/app/WebServer.js -t "./diagram-template/" -d "./out/WebServer.h"
call jsdoc ../backend/app/bl/GamesManager.js -t "./diagram-template/" -d "./out/bl/GamesManager.h" call jsdoc ../backend/app/bl/GamesManager.js -t "./diagram-template/" -d "./out/bl/GamesManager.h"
call jsdoc ../backend/app/bl/RulesManager.js -t "./diagram-template/" -d "./out/bl/RulesManager.h" call jsdoc ../backend/app/bl/RulesManager.js -t "./diagram-template/" -d "./out/bl/RulesManager.h"
call jsdoc ../backend/app/bl/GameObjectsManager.js -t "./diagram-template/" -d "./out/bl/GameObjectsManager.h" call jsdoc ../backend/app/bl/GameObjectsManager.js -t "./diagram-template/" -d "./out/bl/GameObjectsManager.h"
call jsdoc ../backend/app/bl/ScenariosManager.js -t "./diagram-template/" -d "./out/bl/ScenariosManager.h" call jsdoc ../backend/app/bl/ScenariosManager.js -t "./diagram-template/" -d "./out/bl/ScenariosManager.h"
call jsdoc ../backend/controllers/api/GameObjectsController.js -t "./diagram-template/" -d "./out/controllers/api/GameObjectsController.h"
call jsdoc ../backend/controllers/api/GamesController.js -t "./diagram-template/" -d "./out/controllers/api/GamesController.h"
call jsdoc ../backend/controllers/api/RulesController.js -t "./diagram-template/" -d "./out/controllers/api/RulesController.h"
call jsdoc ../backend/controllers/api/ScenariosController.js -t "./diagram-template/" -d "./out/controllers/api/ScenariosController.h"
call jsdoc ../backend/controllers/AssetController.js -t "./diagram-template/" -d "./out/controllers/AssetController.h"
+116 -1
View File
@@ -2,7 +2,7 @@ import path, { dirname } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
/** /**
* Main backend application * Main backend application class
*/ */
class App{ class App{
constructor(){ constructor(){
@@ -73,4 +73,119 @@ class App{
} }
} }
/* The following are pseudo in order to keep documentation aligned to the code */
/**
* The core application plugins
*/
class AppCore{
/**
* The configuration plugin instance
* @type Config
*/
config = undefined;
/**
* The database plugin instance
* @type Db
*/
db = undefined;
/**
* The web server plugin instance
* @type WebServer
*/
webServer = undefined;
}
/**
* The main logical part application plugins
*/
class AppManagement {
/**
* Game objects manager plugin instance
* @type GameObjectsManager
*/
gameObject = undefined;
/**
* Games manager plugin instance
* @type GamesManager
*/
games = undefined;
/**
* Rules manager plugin instance
* @type RulesManager
*/
rules = undefined;
/**
* Scenarios manager plugin instance
* @type ScenariosManager
*/
scenarios = undefined;
}
/**
* The main application controller plugin instances
*/
class AppControllerApi {
/**
* Game objects controller plugin instance
* @type GameObjectsController
*/
gameObjectsApi = undefined;
/**
* Games controller plugin instance
* @type GamesController
*/
gamesApi = undefined;
/**
* Rules controller plugin instance
* @type RulesController
*/
rulesApi = undefined;
/**
* Scenarios controller plugin instance
* @type ScenariosController
*/
scenariosApi = undefined;
/**
* Asset controller plugin instance
* @type AssetController
*/
assetApi = undefined;
}
class AppConcrete {
/**
* Application core plugins
* @type AppCore
* @memberof App
*/
core = undefined;
/**
* Application management plugins
* @type AppManagement
* @memberof App
*/
management = undefined;
/**
* Application controller API plugins
* @type AppControllerApi
* @memberof App
*/
controller = undefined
}
export default App; export default App;
+86 -3
View File
@@ -6,16 +6,40 @@ import path from 'path'
class Config{ class Config{
name = 'config'; name = 'config';
/**
* @class File system options , repository setup
* @alias FileSystemOptions
* @memberof Config
*/
fs = { fs = {
/** Repository path
* @type {string}
* @memberof FileSystemOptions
*/
repo: null repo: null
} }
/**
* @class Database options
* @alias DatabaseOptions
* @memberof Config
*/
db = { db = {
/** Database name
* @type {string}
* @memberof DatabaseOptions
*/
name:'pronature', name:'pronature',
/** Database connection string
* @type {string}
* @memberof DatabaseOptions
*/
url: "mongodb://127.0.0.1:27017/pronature" url: "mongodb://127.0.0.1:27017/pronature"
} }
/** /**
* @class web site options * @class Web site endpoint options
* @alias SiteOptions * @alias SiteOptions
* @memberof Config * @memberof Config
*/ */
@@ -25,38 +49,97 @@ class Config{
* @memberof SiteOptions * @memberof SiteOptions
*/ */
host:'https://localhost:5173', host:'https://localhost:5173',
/** Whether to use SSL
* @type {boolean}
* @memberof SiteOptions
*/
ssl: true, ssl: true,
/** Port to use
* @type {Number}
* @memberof SiteOptions
*/
port: 3000, port: 3000,
/** /**
* @class certificate data * @class Certificate data
* @alias CertificateOptions * @alias CertificateOptions
* @memberof SiteOptions * @memberof SiteOptions
*/ */
certificate: { certificate: {
/** /**
* Certificate key * Certificate private key
* @type {string} * @type {string}
* @memberof CertificateOptions * @memberof CertificateOptions
*/ */
key: './.cert/dev-key.pem', key: './.cert/dev-key.pem',
/**
* Certificate public key
* @type {string}
* @memberof CertificateOptions
*/
cert: './.cert/dev-cert.pem', cert: './.cert/dev-cert.pem',
/**
* PK Passphrase
* @type {string}
* @memberof CertificateOptions
*/
passphrase: 'parola' passphrase: 'parola'
}, },
} }
/**
* @class Access management options
* @alias AccessManagementOptions
* @memberof Config
*/
am = { am = {
/**
* Salt, a string to be used in order to make a more complex password hash
* @type {string}
* @memberof AccessManagementOptions
*/
salt : 'P@ssSal7y!!', salt : 'P@ssSal7y!!',
/**
* @class Cookie options
* @alias CookieOptions
* @memberof AccessManagementOptions
*/
cookie: { cookie: {
/**
* Cookie secret
* @type {string}
* @memberof CookieOptions
*/
secret: 'S3cret4C00k!ie$', secret: 'S3cret4C00k!ie$',
/**
* Cookie max age (in seconds)
* @type {Number}
* @memberof CookieOptions
*/
maxAge: 1000 * 60 * 60 * 24 * 7 maxAge: 1000 * 60 * 60 * 24 * 7
} }
} }
/**
* Initializes the configuration
* @param {App} app The application
*/
async init(app){ async init(app){
if (!this.fs.repo){ if (!this.fs.repo){
this.fs.repo = path.resolve(`${app.root}/repo`) + '/'; this.fs.repo = path.resolve(`${app.root}/repo`) + '/';
} }
} }
/**
* Starts the configuration plugin
* @param {App} app the application instance
*/
async start(app){ async start(app){
} }
+63 -21
View File
@@ -8,10 +8,19 @@ let dbo;
*/ */
class Db { class Db {
name = 'db'; name = 'db';
/**
* Initializes the database plugin
* @param {App} app The application instance
*/
init(app){ init(app){
} }
/**
* Starts the database plugin
* @param {App} app The application instance
*/
async start(app){ async start(app){
db = await MongoClient.connect(app.config.db.url, {maxPoolSize: 256}); db = await MongoClient.connect(app.config.db.url, {maxPoolSize: 256});
try { try {
@@ -74,6 +83,12 @@ class Db {
} }
} }
/**
* Performs a database aggregation according to a given pipeline
* @param {string} collection Database collection name
* @param {Object} specs aggregation definition (the pipeline)
* @returns {Object[]} Array of records
*/
async aggregate(collection, specs){ async aggregate(collection, specs){
try { try {
let cursor = dbo.collection(collection); let cursor = dbo.collection(collection);
@@ -84,6 +99,13 @@ class Db {
} }
} }
/**
* Finds the distinct values for a specified field across a single collection
* @param {string} collection Database collection name
* @param {Object} key The target field for the distinction
* @param {Object} query filter to be applied
* @returns {Object[]}
*/
async distinct(collection, key, query){ async distinct(collection, key, query){
try { try {
return await dbo.collection(collection).distinct(key, query); return await dbo.collection(collection).distinct(key, query);
@@ -91,6 +113,13 @@ class Db {
} }
} }
/**
* Updates a record in database by given key and value
* @param {Object} collection DB collection
* @param {Object} key The key/query which identifies the record to be updated
* @param {Object} value The new value for the record
* @returns {Object} The result from the update operation
*/
async update(collection, key, value){ async update(collection, key, value){
let r; let r;
try { try {
@@ -101,6 +130,13 @@ class Db {
} }
} }
/**
* Performs partial update on a record by given key and partial value
* @param {Object} collection Database collection
* @param {Object} key The key/query which identifies the record to be updated
* @param {Object} value The partial value to be updated
* @returns {Object} The result from the update operation
*/
async updateSet(collection, key, value){ async updateSet(collection, key, value){
let r; let r;
try { try {
@@ -110,6 +146,11 @@ class Db {
} }
} }
/**
* Removes a record from the database by given key
* @param {Object} collection Database collection
* @param {Object} key The key/query which identifies the record to be updated
*/
async remove(collection, key){ async remove(collection, key){
try { try {
await dbo.collection(collection).deleteMany(key); await dbo.collection(collection).deleteMany(key);
@@ -117,27 +158,28 @@ class Db {
} }
} }
convertToObjectId(object, key, recursive, result){
if (object && object[key]){ // convertToObjectId(object, key, recursive, result){
if (Array.isArray(object[key])){ // if (object && object[key]){
object[key].forEach((v, i, a)=>{ // if (Array.isArray(object[key])){
a[i] = this.ObjectId(v); // object[key].forEach((v, i, a)=>{
result && result.push(a[i]); // a[i] = this.ObjectId(v);
}) // result && result.push(a[i]);
}else{ // })
let oid = this.ObjectId(object[key]) // }else{
object[key] = oid; // let oid = this.ObjectId(object[key])
result && result.push(oid); // object[key] = oid;
} // result && result.push(oid);
} // }
if (recursive){ // }
for (var k in object){ // if (recursive){
if (typeof(object[k]) == 'object'){ // for (var k in object){
this.convertToObjectId(object[k], key, recursive, result); // if (typeof(object[k]) == 'object'){
} // this.convertToObjectId(object[k], key, recursive, result);
} // }
} // }
} // }
// }
sanitizeQuery(q){ sanitizeQuery(q){
if (!q) return; if (!q) return;
+11
View File
@@ -8,9 +8,16 @@ import cookieParser from 'cookie-parser';
import helmet from 'helmet'; import helmet from 'helmet';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
/**
* The Web Server class, manages all request from the web pllatform, manages the APIs
*/
class WebServer { class WebServer {
name = 'webServer'; name = 'webServer';
/**
* Initializes the web server plugin
* @param {App} app The application instance
*/
async init(app) { async init(app) {
const xapp = express(); const xapp = express();
this.xapp = xapp; this.xapp = xapp;
@@ -61,6 +68,10 @@ class WebServer {
app.config.am.helmet && xapp.use(helmet(app.config.am.helmet)); app.config.am.helmet && xapp.use(helmet(app.config.am.helmet));
} }
/**
* Starts the web server plugin
* @param {App} app The application instance
*/
async start(app) { async start(app) {
let indexFile = app.root + '/index.html'; let indexFile = app.root + '/index.html';
+10 -3
View File
@@ -8,7 +8,7 @@ import path from 'path';
const collection = 'assets'; const collection = 'assets';
/** /**
* Application layer manager * Game objects manager
*/ */
class GameObjectsManager{ class GameObjectsManager{
name = 'gameObject'; name = 'gameObject';
@@ -157,7 +157,7 @@ class GameObjectsManager{
} }
/** /**
* GameObject entity * GameObject entity, can be: panorama picture, 3d environment, 3d object, 2d object (picture), a player (3d), audio or video asset
*/ */
class GameObject { class GameObject {
/** /**
@@ -166,9 +166,16 @@ class GameObject {
*/ */
name = null; name = null;
/**
* Game object type
* @type string
*/
type = null; type = null;
/**
* Associated file
* @type File
*/
file = null; file = null;
} }
+6
View File
@@ -77,6 +77,12 @@ class Rule {
*/ */
name = null; name = null;
/**
* Rule definition
* @type Object
*/
name = null;
} }
export { RulesManager } export { RulesManager }
+16 -1
View File
@@ -1,14 +1,29 @@
import express from 'express'; import express from 'express';
/**
* Asset controller plugin
*/
class AssetController{ class AssetController{
name = 'assetController' name = 'assetApi'
route = '/asset' route = '/asset'
/**
* Initializes the AssetController plugin
* @param {App} app The application instance
*/
init(app){ init(app){
const router = express.Router(); const router = express.Router();
const {config} = app; const {config} = app;
/**
* API: GET /asset/:type/:id Retrieve asset by type and ID
* @function read
* @param {string} type Type can be "source", "default" or "thumb"
* @param {string} id The name of the asset
* @returns File
* @memberof AssetController
*/
router.get('/:where/:id(*)', async (req, res)=>{ router.get('/:where/:id(*)', async (req, res)=>{
res.sendFile(config.fs.repo + req.params.where + '/' + req.params.id, (err)=>{ res.sendFile(config.fs.repo + req.params.where + '/' + req.params.id, (err)=>{
if (err){ if (err){
@@ -2,17 +2,27 @@ import express from 'express';
import multipart from 'connect-multiparty'; import multipart from 'connect-multiparty';
const multipartMiddleware = multipart(); const multipartMiddleware = multipart();
/**
* GameObjectsController. API for the game objects manager
*/
class GameObjectsController{ class GameObjectsController{
name = 'gameObjectsApi' name = 'gameObjectsApi'
route = '/api/game-object' route = '/api/game-object'
/**
* Initializes the GameObjectsController plugin
* @param {App} app The application instance
*/
init(app){ init(app){
const { gameObject } = app; const { gameObject } = app;
const router = express.Router(); const router = express.Router();
/** /**
* Create & update * API: PUT /api/game-object/ Create or update game object
* @function createOrUpdate
* @memberof GameObjectsController
*/ */
router.put('/', multipartMiddleware, async (req, res)=>{ router.put('/', multipartMiddleware, async (req, res)=>{
try{ try{
@@ -26,22 +36,34 @@ class GameObjectsController{
}); });
/** /**
* List * API: POST /api/game-object/ List game objects by given criteria
* @function list
* @returns {GameObject[]}
* @memberof GameObjectsController
*/ */
router.post('/', async (req, res)=>{ router.post('/', async (req, res)=>{
let result = await gameObject.list(req.body); let result = await gameObject.list(req.body);
res.json(result); res.json(result);
}) })
router.get('/', async (req, res)=>{ /**
* API: GET /api/game-object/:id Retrieve game object by ID
}) * @function read
* @param {string} id The id of the game object
* @returns {GameObject}
* @memberof GameObjectsController
*/
router.get('/:id', async (req, res)=>{ router.get('/:id', async (req, res)=>{
let object = await gameObject.read(parseInt(req.params.id)); let object = await gameObject.read(parseInt(req.params.id));
res.json(object); res.json(object);
}) })
/**
* API: DELETE /api/game-object/:id Delete game object by ID
* @function remove
* @param {string} id The id of the game object
* @memberof GameObjectsController
*/
router.delete('/:id', async (req, res)=>{ router.delete('/:id', async (req, res)=>{
await gameObject.remove(req.params.id); await gameObject.remove(req.params.id);
res.json({status: 'OK'}); res.json({status: 'OK'});
@@ -1,12 +1,59 @@
import express from 'express'; import express from 'express';
/**
* GamesController. API for the games manager
*/
class GamesController{ class GamesController{
name = 'gamesApi' name = 'gamesApi'
route = '/api/game' route = '/api/game'
/**
* Initializes the GamesController plugin
* @param {App} app The application instance
*/
init(app){ init(app){
const router = express.Router(); const router = express.Router();
const { games } = app;
/**
* API: PUT /api/game/ Create or update game
* @function createOrUpdate
* @memberof GamesController
*/
router.put('/', async (req, res)=>{
});
/**
* API: POST /api/game/ List games by given criteria
* @function list
* @returns {Game[]}
* @memberof GamesController
*/
router.post('/', async (req, res)=>{
})
/**
* API: GET /api/game/:id Retrieve game by ID
* @function read
* @param {string} id The id of the game
* @returns {Game}
* @memberof GamesController
*/
router.get('/:id', async (req, res)=>{
})
/**
* API: DELETE /api/game/:id Delete game by ID
* @function remove
* @param {string} id The id of the game
* @memberof GamesController
*/
router.delete('/:id', async (req, res)=>{
})
app.webServer.xapp.use(this.route, router);
} }
} }
@@ -0,0 +1,60 @@
import express from 'express';
/**
* RulesController. API for the game rules manager
*/
class RulesController{
name = 'rulesApi'
route = '/api/rule'
/**
* Initializes the RulesController plugin
* @param {App} app The application instance
*/
init(app){
const router = express.Router();
const { rules } = app;
/**
* API: PUT /api/rule/ Create or update rule
* @function createOrUpdate
* @memberof RulesController
*/
router.put('/', async (req, res)=>{
});
/**
* API: POST /api/rule/ List rules by given criteria
* @function list
* @returns {Rule[]}
* @memberof RulesController
*/
router.post('/', async (req, res)=>{
})
/**
* API: GET /api/rule/:id Retrieve rule by ID
* @function read
* @param {string} id The id of the rule
* @returns {Rule}
* @memberof RulesController
*/
router.get('/:id', async (req, res)=>{
})
/**
* API: DELETE /api/rule/:id Delete rule by ID
* @function remove
* @param {string} id The id of the rule
* @memberof RulesController
*/
router.delete('/:id', async (req, res)=>{
})
app.webServer.xapp.use(this.route, router);
}
}
export { RulesController }
@@ -0,0 +1,60 @@
import express from 'express';
/**
* ScenariosController. API for the scenarios manager
*/
class ScenariosController{
name = 'scenariosApi'
route = '/api/scenario'
/**
* Initializes the ScenariosController plugin
* @param {App} app The application instance
*/
init(app){
const router = express.Router();
const { scenarios } = app;
/**
* API: PUT /api/scenario/ Create or update scenario
* @function createOrUpdate
* @memberof ScenariosController
*/
router.put('/', async (req, res)=>{
});
/**
* API: POST /api/scenario/ List scenarios by given criteria
* @function list
* @returns {Scenario[]}
* @memberof ScenariosController
*/
router.post('/', async (req, res)=>{
})
/**
* API: GET /api/scenario/:id Retrieve scenario by ID
* @function read
* @param {string} id The id of the scenario
* @returns {Scenario}
* @memberof ScenariosController
*/
router.get('/:id', async (req, res)=>{
})
/**
* API: DELETE /api/scenario/:id Delete scenario by ID
* @function remove
* @param {string} id The id of the scenario
* @memberof ScenariosController
*/
router.delete('/:id', async (req, res)=>{
})
app.webServer.xapp.use(this.route, router);
}
}
export { ScenariosController }