diff --git a/backend/server.js b/backend/server.js index 0c295084..1ec9150e 100755 --- a/backend/server.js +++ b/backend/server.js @@ -38,6 +38,7 @@ const io = socketIo(server, { origin: '*', } }); + socket.setIo(io); // CONNECT TO MONGODB @@ -81,12 +82,12 @@ app.use('/concept', require('./routes/concept')) app.use('/admin', require('./routes/admin')) // GET localhost:8081/concept/list -const pluginData = pluginManager.init(); -app.use('/plugins', pluginData.router); - // SETUP IO require('./io/campaign')(socket.getIo()); +// INIT PLUGINS +const pluginData = pluginManager.init(); +app.use('/plugins', pluginData.router); // DEBUG ROUTER function print (path, layer) { diff --git a/backend/services/api.js b/backend/services/api.js index 7c2d682d..79777d2a 100644 --- a/backend/services/api.js +++ b/backend/services/api.js @@ -2,7 +2,6 @@ const mongoose = require("mongoose"); const Schema = mongoose.Schema; const express = require('express'); -const router = express.Router(); /** * Class for managing the backend api @@ -12,14 +11,18 @@ class BackendApi { #_plugin; #_router; #_expressRouter; + #_internalSocket; + #_socket; /** * This object is already created for you * @param {plugin} Plugin instance */ - constructor(plugin, router){ + constructor(plugin, router, internalSocket){ this.#_plugin = plugin; this.#_expressRouter = router; + this.#_internalSocket = internalSocket; + this.#_socket = new BackendSocket(`plugin/${plugin.package}`, internalSocket); this.#_router = new BackendRouter(`plugin/${plugin.package}`, this.#_expressRouter); } @@ -31,8 +34,12 @@ class BackendApi { return this.#_router; } - get _router(){ - return router; + get socket(){ + return this.#_socket; + } + + get _socket(){ + return internalSocket; } /** @@ -53,7 +60,7 @@ class BackendApi { } createModule(id){ - return new BackendModule(this.#_plugin, id, this.#_expressRouter); + return new BackendModule(this.#_plugin, id, this.#_expressRouter, this.#_internalSocket); } }; @@ -122,17 +129,25 @@ class BackendModule { #_plugin; #_id; #_router; + #_socket; + #_internalSocket; - constructor(plugin, id, expressRouter){ + constructor(plugin, id, expressRouter, internalSocket){ this.#_plugin = plugin; this.#_id = id; + this.#_internalSocket = internalSocket; this.#_router = new BackendRouter(`module/${plugin.package}/${id}`, expressRouter) + this.#_socket = new BackendSocket(`module/${plugin.package}/${id}`, this.#_internalSocket); } get router(){ return this.#_router; } + get socket(){ + return this.#_socket; + } + // Creates a model for the Module createModel(name, schema){ return new BackendModel(name, `${this.#_plugin.package}/${this.#_id}`, schema); @@ -213,6 +228,20 @@ class BackendModel { } }; +class BackendSocket { + #_prefix; + #_internalSocket; + + constructor(prefix, internalSocket){ + this.#_prefix = prefix; + this.#_internalSocket = internalSocket; + } + + on(msg, callback){ + this.#_internalSocket[`${this.#_prefix}/${msg}`] = callback; + } +} + function ParseSchema(schema){ const typeTable = { String: String, diff --git a/backend/services/plugins.js b/backend/services/plugins.js index c533e9c6..3b9c7cf2 100644 --- a/backend/services/plugins.js +++ b/backend/services/plugins.js @@ -2,6 +2,7 @@ const fs = require('fs'); const path = require('path') const BackendApi = require('./api').BackendApi const express = require('express'); +const { getIo } = require('../io/socket'); const router = express.Router({ mergeParams: true }); @@ -11,6 +12,7 @@ console.log(basePath) let pluginsInfo = []; let plugins = {}; +let internalSocket = {}; function init(){ console.log("Initializing plugins"); @@ -29,10 +31,17 @@ function init(){ // Execute main Object.keys(plugins).forEach(k => { - let pluginApi = new BackendApi(plugins[k].info, router); + let pluginApi = new BackendApi(plugins[k].info, router, internalSocket); plugins[k].payload.Main(pluginApi); }); + console.log(internalSocket); + getIo().on('connect', (socket) => { + Object.keys(internalSocket).forEach(k => { + socket.on(k, internalSocket[k]); + }); + }) + return { router } diff --git a/client/src/services/Api.js b/client/src/services/Api.js index 64751779..b7f31cb5 100644 --- a/client/src/services/Api.js +++ b/client/src/services/Api.js @@ -152,22 +152,17 @@ class ClientModule { #_id; #_router; - #_title; - #_description; - #_version; - #_color; - #_icon; #_buttons; #_previewData; #_init; + #_socket; #_exit; - - constructor(plugin, id){ this.#_plugin = plugin; this.#_id = id; this.#_router = new ClientRouter(`/module/${plugin.package}/${id}`); + this.#_socket = new ClientSocket(`${plugin.package}/${id}`) } setData(data){ @@ -186,6 +181,10 @@ class ClientModule { return this.#_router; } + get socket(){ + return this.#_socket; + } + /** * Gets the module info in a json format * @returns {Object} @@ -195,7 +194,7 @@ class ClientModule { id: this.#_id, previewData: this.#_previewData, init: this.#_init, - exit: () => {}, + exit: this.#_exit, buttons: this.#_buttons } } @@ -206,14 +205,14 @@ class ClientModule { } class ClientSocket { - #_package + #_prefix - constructor(plugin){ - this.#_package = plugin; + constructor(prefix){ + this.#_prefix = prefix; } on(msg, callback){ - socket.on(`${this.#_package}/${msg}`, callback); + socket.on(`${this.#_prefix}/${msg}`, callback); } } @@ -243,80 +242,20 @@ class ClientRouter { this.#_path = path; } - /** - * Sends a get request to an specified route of a plugin, and then executes the routerCallback with the response - * @param {String} route - * @param {routerCallback} callback - */ - get(route, callback){ - Server().get(`${path}/${route}`).then(callback).catch(err => console.log(err)); + get(route){ + return Server().get(`${path}/${route}`); } - /** - * Sends a post request to specified plugin route - * @param {String} route - * @param {Object} data - * @param {routerCallback} callback - */ - post(route, data, callback){ - Server().post(`${path}/${route}`, data).then(callback).catch(err => console.log(err)); + post(route, data = {}){ + return Server().post(`${path}/${route}`, data); } - /** - * Sends a put request to specified plugin route - * @param {String} route - * @param {Object} data - * @param {routerCallback} callback - */ - put(route, data, callback){ - Server().put(`${path}/${route}`, data).then(callback).catch(err => console.log(err)); + put(route, data = {}){ + return Server().put(`${path}/${route}`, data); } - /** - * Sends a delete request to specified plugin route - * @param {String} route - * @param {routerCallback} callback - */ - delete(route, callback){ - Server().delete(`${route}`).then(callback).catch(err => console.log(err)); - } - - /** - * Sends a get request to an specified route - * @param {String} route - * @param {routerCallback} callback - */ - baseGet(route, callback){ - Server().get(`${route}`).then(callback).catch(err => console.log(err)); - } - - /** - * Sends a post request to specified route - * @param {String} route - * @param {Object} data - * @param {routerCallback} callback - */ - basePost(route, data, callback){ - Server().post(`${route}`, data).then(callback).catch(err => console.log(err)); - } - - /** - * Sends a put request to specified route - * @param {String} route - * @param {Object} data - * @param {routerCallback} callback - */ - basePut(route, data, callback){ - Server().put(`${route}`, data).then(callback).catch(err => console.log(err)); - } - - /** - * Sends a delete request to specified route - * @param {String} route - * @param {routerCallback} callback - */ - baseDelete(route, callback){ - Server().delete(`${route}`).then(callback).catch(err => console.log(err)); + delete(route){ + return Server().delete(`${route}`); } } diff --git a/client/src/services/Modules.js b/client/src/services/Modules.js index a3b5b158..50e104cb 100644 --- a/client/src/services/Modules.js +++ b/client/src/services/Modules.js @@ -6,21 +6,12 @@ function CreateModule(module){ let moduleInfo = module.info; let plugin = module._plugin.package; - /* - InjectWindow(`${plugin}/character_sheet`, plugin, moduleInfo.windows.character_sheet.path) - InjectWindow(`${plugin}/item_sheet`, plugin, moduleInfo.windows.item_sheet.path) - InjectWindow(`${plugin}/create_item_prompt`, plugin, moduleInfo.windows.create_item_prompt.path) - */ - modules[moduleInfo.id] = moduleInfo; } let GetModules = () => modules; -// let GetModulesToLoad = () => modulesToLoad; function GetModule(id){ - console.log(modules); - console.log(modules[id]) return modules[id]; } diff --git a/documentation/docs/client/api.md b/documentation/docs/client/api.md index e1726125..212a502b 100644 --- a/documentation/docs/client/api.md +++ b/documentation/docs/client/api.md @@ -214,29 +214,124 @@ dndModule.setData({ ### onInit +Sets a callback when the module is instantiated, i.e, when the client enters a campaign using that module + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| ``callback`` | Function() | yes | The function to call when the module is instantiated | + + ### onExit +Sets a callback when the module instance is destroyed, i.e, when the user leaves a game with a campaign using that module + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| ``callback`` | Function() | yes | The function to call when the module is destroyed | + ### setButtons ### router +Gets the [ClientRouter](#clientrouter) associated with that module. The paths of this router can be easily catched by the same BackendRouter associated with the module with the same id. + +#### Returns + +| Type | Description | +| ---- | ----------- | +| [ClientRouter](#clientrouter) | The router associated with the module | + +### socket + +Gets the [ClientSocket](#clientsocket) object associated with the Module. + +#### Returns + +| Type | Description | +| ---- | ----------- | +| [ClientSocket](#clientsocket) | The module socket | + +### baseSocket + +Gets the [ClientSocket](#clientsocket) pointing to the root of the application. Use it only for calling internal socket.io events of Dragonroll. + +#### Returns + +| Type | Description | +| ---- | ----------- | +| [ClientSocket](#clientsocket) | The socket object | + ## ClientRouter +The `ClientRouter` class is used to make http requests between the Dragonroll client and the Dragonroll backend. To make the routing process easier, Dragonroll provides different instances of the `ClientRouter` class depending on the context. For example, you can have a ClientRouter for registering routes for an specific module inside your plugin, and another for registering more general routes that you may want to create within the backend part of your plugin. It is also possible to make http requests +to the internal Dragonroll routes using the `baseRouter` + ### get +#### Parameters + +Creates a `GET` request to the backend + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| ``path`` | String | yes | The path to the route to make the HTTP request | + +#### Returns + +| Type | Description | +| ---- | ----------- | +| Callback\ | A callback with data about the result of the request | + ### post +#### Parameters + +Creates a `POST` request to the backend + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| ``path`` | String | yes | The path to the route to make the HTTP request | +| ``data`` | Object | no | The body of the request | + +#### Returns + +| Type | Description | +| ---- | ----------- | +| Callback\ | A callback with data about the result of the request | + ### put +#### Parameters + +Creates a `PUT` request to the backend + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| ``path`` | String | yes | The path to the route to make the HTTP request | +| ``data`` | Object | no | The body of the request | + +#### Returns + +| Type | Description | +| ---- | ----------- | +| Callback\ | A callback with data about the result of the request | + ### delete -### baseGet -### basePost +#### Parameters -### basePut +Creates a `GET` request to the backend -### baseDelete +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| ``path`` | String | yes | The path to the route to make the HTTP request | + +#### Returns + +| Type | Description | +| ---- | ----------- | +| Callback\ | A callback with data about the result of the request | ## ClientSocket diff --git a/documentation/docs/server/api.md b/documentation/docs/server/api.md index 28ac49d5..9029b792 100644 --- a/documentation/docs/server/api.md +++ b/documentation/docs/server/api.md @@ -1,11 +1,13 @@ # ServerApi -## BakcendApi +## BackendApi The BackendApi object is used for interacting with everything related to the Dragonroll backend. It is passed to the `Main` function at the entrypoint defined in the [plugin.json](/plugin/plugin.json) file ### router +### socket + ### createModel ### createModule @@ -26,6 +28,8 @@ The BackendApi object is used for interacting with everything related to the Dra ### router +### socket + ### createModel ## BackendModel diff --git a/plugins/dnd-5e/backend/main.js b/plugins/dnd-5e/backend/main.js index 8b59f2c6..ce83b457 100644 --- a/plugins/dnd-5e/backend/main.js +++ b/plugins/dnd-5e/backend/main.js @@ -33,6 +33,7 @@ function Main(api){ }) }) + Api.socket.on("test", () => console.log("test")); // Api.router.createModelRoutes(itemModel, 'item'); } diff --git a/plugins/dnd-5e/client/data.js b/plugins/dnd-5e/client/data.js index 047e51d9..980c1221 100644 --- a/plugins/dnd-5e/client/data.js +++ b/plugins/dnd-5e/client/data.js @@ -14,7 +14,6 @@ function InitData(){ } function FetchConcepts(){ - Server().get('/concept/list?campaign=' + GetCampaign()._id).then(response => { data.value.concepts = response.data.data; }).catch((err) => console.log(err)); @@ -23,16 +22,6 @@ function FetchConcepts(){ function FetchData(){ FetchConcepts(); } -/* -Api.socket.on('update-concepts', () => { - FetchConcepts(); -}); - -/* -socket.on('update-concepts', () => { - FetchConcepts(); -}); -*/ let GetConcepts = () => data.value.concepts; let GetConcept = (id) => Server().get('/concept/get?campaign=' + GetCampaign()._id + "&id=" + id) diff --git a/plugins/dnd-5e/client/main.js b/plugins/dnd-5e/client/main.js index 711a71ff..f4f73eb2 100644 --- a/plugins/dnd-5e/client/main.js +++ b/plugins/dnd-5e/client/main.js @@ -1,4 +1,4 @@ -import { FetchData, InitData } from "./data"; +import { FetchConcepts, FetchData, InitData } from "./data"; // Entrypoint let Api; @@ -29,12 +29,6 @@ function Main(api){ let characterSheetWindow = Api.registerWindow('character_sheet', Api.createView('CharacterSheet')); let itemSheetWindow = Api.registerWindow('item_sheet', Api.createView('ItemSheet')); let createItemPromptWindow = Api.registerWindow('create_item_prompt', Api.createView('CreateItemPrompt')); - - /* - dndModule.setCharacterSheet(Api.createView('CharacterSheet')); - dndModule.setItemSheet(Api.createView('ItemSheet')); - dndModule.setItemPrompt(Api.createView('CreateItemPrompt')); - */ dndModule.setButtons({ right: [ @@ -61,6 +55,12 @@ function Main(api){ }] }); + + Api.socket.on('update-concepts', () => { + FetchConcepts(); + }); + + // Api.windows.registerWindow('character_sheet', Api.createView('CharacterSheet')); // Api.windows.registerWindow('item_sheet', Api.createView('ItemSheet')); // Api.windows.registerWindow('create_item_prompt', Api.createView('CreateItemPrompt'));