diff --git a/src/client/bridge.js b/src/client/bridge.js new file mode 100644 index 0000000..8dcaa1a --- /dev/null +++ b/src/client/bridge.js @@ -0,0 +1,96 @@ +const generateRequestDispatcher = require("./generateRequestDispatcher") +const axios = require("axios") +const camalize = require("@corenode/utils/dist/camalize").default + +const FixedMethods = { + "del": "delete" +} + +module.exports = class Bridge { + constructor(params = {}) { + this.params = params + + this.origin = this.params.origin + this.headers = { ...this.params.headers } + + this.instance = axios.create({ + baseURL: this.origin, + headers: this.headers + }) + + this.endpoints = {} + + return this + } + + initialize = async () => { + await this.updateEndpointsMap() + } + + handleRequestContext = async () => { + if (typeof this.params.onRequest === "function") { + return await this.params.onRequest() + } + + return false + } + + handleResponse = async (response) => { + if (typeof this.params.onResponse === "function") { + return await this.params.onResponse(response) + } + + return false + } + + updateEndpointsMap = async () => { + const endpointsMap = await this.instance.get("/") + .then(res => res.data.endpointsMap) + .catch(err => { + console.error(err) + throw new Error(`Could not get endpoints map from server. [${err.message}]`) + }) + + for await (let HttpMethod of Object.keys(endpointsMap)) { + HttpMethod = HttpMethod.toLowerCase() + + const fixedMethod = FixedMethods[HttpMethod] ?? HttpMethod + + if (typeof this.endpoints[fixedMethod] !== "object") { + this.endpoints[fixedMethod] = {} + } + + Object.keys(endpointsMap[HttpMethod]).forEach((route) => { + const tree = route.split("/") + const hasTree = tree.length >= 1 + + let nameKey = route + + // check if has tree + if (hasTree) { + // remove first whitespace item in route index[0] + if (tree[0] == "") { + tree.shift() + } + + nameKey = camalize(tree.join("_")) + } + + // if is an blank route, set as index + if (nameKey == "") { + nameKey = "index" + } + + this.endpoints[fixedMethod][nameKey] = generateRequestDispatcher( + this.instance, + fixedMethod, + route, + this.handleRequestContext, + this.handleResponse + ) + }) + } + + return this.endpoints + } +} \ No newline at end of file diff --git a/src/client/controller.js b/src/client/controller.js new file mode 100644 index 0000000..a5f21f7 --- /dev/null +++ b/src/client/controller.js @@ -0,0 +1,44 @@ +// TODO: AutoConnection +module.exports = class Controller { + constructor(params = {}) { + console.warn("[Linebridge] Controller is not finished yet. Please use regular bridges instead.") + + this.params = params + this.pool = [] + } + + async initialize() { + if (typeof this.params.servers !== "undefined" && Array.isArray(this.params.servers)) { + for await (let server of this.params.servers) { + await this.appendServer(server) + } + } + + for await (let server of this.pool) { + await this.connect(server) + } + } + + async appendServer(server) { + if (typeof server === "string") { + server = new Bridge({ + origin: server, + }) + } else if (typeof server === "object" && server instanceof Bridge) { + server = new Bridge(...server) + } + + this.pool.push(server) + } + + // async disconnect() { + // } + + async connect(server) { + if (server instanceof Bridge) { + await server.initialize() + } else { + throw new Error("Invalid server. Expected Bridge instance.") + } + } +} \ No newline at end of file diff --git a/src/client/generateRequestDispatcher.js b/src/client/generateRequestDispatcher.js new file mode 100644 index 0000000..111d1d0 --- /dev/null +++ b/src/client/generateRequestDispatcher.js @@ -0,0 +1,50 @@ +module.exports = function generateRequestDispatcher(instance, method, route, handleRequestContext, handleResponse) { + return function (body, query, options) { + return new Promise(async (resolve, reject) => { + let requestParams = { + parseData: true, + ...options, + method: method, + url: route, + data: body, + params: query, + } + + if (typeof handleRequestContext === "function") { + const context = await handleRequestContext() + requestParams = { ...requestParams, ...context } + } + + let result = { + response: null, + error: null, + } + + const request = await instance(requestParams) + .then((response) => { + result.response = response + + return response + }) + .catch((error) => { + result.error = error.response.data.error ?? error.response.data + + return error + }) + + if (typeof handleResponse === "function") { + await handleResponse(request) + } + + if (requestParams.parseData) { + if (result.error) { + return reject(result.error) + } + + return resolve(result.response.data) + } + + return resolve(result) + }) + } +} \ No newline at end of file diff --git a/src/client/index.js b/src/client/index.js index 06a70ca..7df6fee 100755 --- a/src/client/index.js +++ b/src/client/index.js @@ -1,191 +1,9 @@ -const axios = require("axios") -const camalize = require("@corenode/utils/dist/camalize").default - -const FixedMethods = { - "del": "delete" -} - -// TODO: AutoConnection -class Controller { - constructor(params = {}) { - console.warn("[Linebridge] Controller is not finished yet. Please use regular bridges instead.") - - this.params = params - this.pool = [] - } - - async initialize() { - if (typeof this.params.servers !== "undefined" && Array.isArray(this.params.servers)) { - for await (let server of this.params.servers) { - await this.appendServer(server) - } - } - - for await (let server of this.pool) { - await this.connect(server) - } - } - - async appendServer(server) { - if (typeof server === "string") { - server = new Bridge({ - origin: server, - }) - } else if (typeof server === "object" && server instanceof Bridge) { - server = new Bridge(...server) - } - - this.pool.push(server) - } - - // async disconnect() { - // } - - async connect(server) { - if (server instanceof Bridge) { - await server.initialize() - } else { - throw new Error("Invalid server. Expected Bridge instance.") - } - } -} - -class Bridge { - constructor(params = {}) { - this.params = params - - this.origin = this.params.origin - this.headers = { ...this.params.headers } - - this.instance = axios.create({ - baseURL: this.origin, - headers: this.headers - }) - - this.map = null - this.endpoints = {} - - return this - } - - handleRequestContext = async () => { - if (typeof this.params.onRequest === "function") { - return await this.params.onRequest() - } - - return false - } - - handleResponse = async (response) => { - if (typeof this.params.onResponse === "function") { - return await this.params.onResponse(response) - } - - return false - } - - updateEndpointMap = async () => { - this.map = await this.getMap() - - for await (let method of Object.keys(this.map)) { - method = method.toLowerCase() - - const fixedMethod = FixedMethods[method] ?? method - - if (typeof this.endpoints[fixedMethod] !== "object") { - this.endpoints[fixedMethod] = {} - } - - this.map[method].forEach((endpoint) => { - const route = endpoint.route - const tree = route.split("/") - const hasTree = tree.length >= 1 - let nameKey = route - - // check if has tree - if (hasTree) { - // remove first whitespace item in route index[0] - if (tree[0] == "") { - tree.shift() - } - - nameKey = camalize(tree.join("_")) - } - - // if is an blank route, set as index - if (nameKey == "") { - nameKey = "index" - } - - this.endpoints[fixedMethod][nameKey] = generateDispatcher(this.instance, fixedMethod, route, this.handleRequestContext, this.handleResponse) - }) - } - - return this.endpoints - } - - getMap = async () => { - const req = await this.instance.get("/map") - return req.data - } - - initialize = async () => { - await this.updateEndpointMap() - } -} - -function generateDispatcher(instance, method, route, handleRequestContext, handleResponse) { - return function (body, query, options) { - return new Promise(async (resolve, reject) => { - let requestParams = { - parseData: true, - ...options, - method: method, - url: route, - data: body, - params: query, - } - - if (typeof handleRequestContext === "function") { - const context = await handleRequestContext() - requestParams = { ...requestParams, ...context } - } - - let result = { - response: null, - error: null, - } - - const request = await instance(requestParams) - .then((response) => { - result.response = response - - return response - }) - .catch((error) => { - result.error = error.response.data.error ?? error.response.data - - return error - }) - - if (typeof handleResponse === "function") { - await handleResponse(request) - } - - if (requestParams.parseData) { - if (result.error) { - return reject(result.error) - } - - return resolve(result.response.data) - } - - return resolve(result) - }) - } -} +const Controller = require("./controller") +const Bridge = require("./bridge") +const generateRequestDispatcher = require("./generateRequestDispatcher") module.exports = { Bridge, Controller, + generateRequestDispatcher, } \ No newline at end of file