Skip to content

Commit

Permalink
Merge pull request #13 from MR-MKZ/10-plugin-system
Browse files Browse the repository at this point in the history
plugin system
  • Loading branch information
MR-MKZ authored Oct 23, 2024
2 parents 551b1a2 + b116779 commit 1ee2dfe
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 11 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Axon is a backend library who tries to be simple and powerfull.

Currently Axon is 2X faster than Express. :D please checkout [Axon Benchmarks](./benchmarks/README.md)

Latest change:
- `text/plain` response in core default response errors bug fixed.
- Plugin manager system added to core. (Document will update soon - 2024/10/24)



## Installation
Expand Down Expand Up @@ -56,20 +60,20 @@ You can checkout Axon benchmarks document and results from below link.
## Features

- Simple routing system
- Support methods: GET, POST, PUT, PATCH, DELETE, OPTIONS. more methods soon...
- Support methods: GET, POST, PUT, PATCH, DELETE, OPTIONS.
- Flexible routing system. (You can define routes in another files and then add them to core)
- Default core logger (still developing)
- Default core logger
- Configurable core
- Plugin manager (You can create your own plugins and use them in other projects)
- Controllers and Middlewares

**More features soon...**

## Roadmap (still thinking)

- Support controllers better than now.
- Support middlewares.
- Some changes in response structure.
- Response meta generator.
- Logger system. [In Progress]
- Auto error detector (maybe)
- Default schemas.
- Default database connection methods.
Expand Down
9 changes: 6 additions & 3 deletions examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import { AxonCore, Request, Response, nextFn } from "../src";
import { v1Routes } from "./routes/v1";
import { v2Routes } from "./routes/v2";
import { LogPluginTest } from "./plugins/log";

const core = new AxonCore()

core.loadConfig({
DEBUG: true, // default false
DEBUG: false, // default false
LOGGER: true, // default true
LOGGER_VERBOSE: false, // default false
RESPONSE_MESSAGES: {
Expand All @@ -18,8 +19,6 @@ core.loadConfig({
})

const testMid = async (req: Request, res: Response, next: nextFn) => {
console.log("global middleware 1");

next()
}

Expand All @@ -31,6 +30,10 @@ core.globalMiddleware(testMid);
core.loadRoute(v1Routes)
core.loadRoute(v2Routes, "/api/v1")

// using plugins for more flexible code and also using ready codes to develope faster than past.
// you can make your own plugins with AxonPlugin interface.
core.loadPlugin(new LogPluginTest());

// callback function is optional and core has default log message for on start event
// host default is 127.0.0.1 and port default is 8000
core.listen("127.0.0.1", 3000)
26 changes: 26 additions & 0 deletions examples/plugins/log/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { AxonCore, AxonPlugin, Router } from "../../../src";
export class LogPluginTest implements AxonPlugin {
private logs: number;

constructor() {
this.logs = 0;
}

name: string = "Pretty Logger";
version: string = "1.2.0-beta";

init(core: AxonCore): void {
const router = Router();

router.get('/log', async (req, res) => {
this.logs++;

return res.status(200).body({
message: "This is the fist plugin of AxonJs",
logs: this.logs
});
});

core.loadRoute(router);
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mr-mkz/axon",
"version": "0.2.2-1",
"version": "0.3.0",
"description": "A backend library who tries to be simple and powerfull.",
"author": "Mr.MKZ",
"license": "ISC",
Expand Down
25 changes: 22 additions & 3 deletions src/core/AxonCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import getRequestBody from "./utils/getRequestBody";
import { Key, pathToRegexp, Keys } from "path-to-regexp";
import { Request, Response, Headers } from "..";
import AxonResponse from "./AxonResponse";
import { PLuginLoader } from "./PluginLoader";
import { AxonPlugin } from "../types/AxonPlugin";

const defaultResponses = {
notFound: "Not found",
Expand All @@ -25,6 +27,8 @@ export default class AxonCore {
private passConfig: boolean;
private routesLoaded: boolean;

private pluginLoader: PLuginLoader = new PLuginLoader();

constructor() {
this.routes = {
GET: {},
Expand All @@ -49,13 +53,26 @@ export default class AxonCore {
this.routesLoaded = false;
}

/**
* Loads a specified Axon plugin using the plugin loader.
*
* @param {AxonPlugin} plugin - The plugin to be loaded. It should be an instance of AxonPlugin.
*/
async loadPlugin(plugin: AxonPlugin) {
await this.pluginLoader.loadPlugin(plugin);
}

async #initializePlugins() {
await this.pluginLoader.initializePlugins(this);
}

/**
* A method to config core as you want
*
* If you want to config the core, use this method before all other methods.
* @param config core config object
*/
loadConfig(config: AxonCoreConfig) {
async loadConfig(config: AxonCoreConfig) {
this.passConfig = false;
this.config.DEBUG = config.DEBUG || false
this.config.LOGGER = config.LOGGER;
Expand Down Expand Up @@ -117,7 +134,7 @@ export default class AxonCore {
}
}

logger.debug("loaded global middlewares")
logger.debug("global middlewares loaded")
}

/**
Expand Down Expand Up @@ -302,7 +319,7 @@ export default class AxonCore {
logger.request(`${req.socket.remoteAddress} - ${req.method} ${req.url} ${res.statusCode} - ${req.headers["user-agent"]}`)
}

return res.status(data.responseCode).body(JSON.stringify(data.body))
return res.status(data.responseCode).body(data.body)
}

/**
Expand Down Expand Up @@ -337,6 +354,8 @@ export default class AxonCore {
// Wait for necessary items to be loaded
await corePreloader();

await this.#initializePlugins();

const server = http.createServer(async (req: http.IncomingMessage, res: http.ServerResponse) => {
try {
await getRequestBody(req)
Expand Down
25 changes: 25 additions & 0 deletions src/core/PluginLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AxonPlugin } from "../types/AxonPlugin";
import AxonCore from "./AxonCore";
import { logger } from "./utils/coreLogger";

export class PLuginLoader {
private plugins: AxonPlugin[] = [];

async loadPlugin(plugin: AxonPlugin) {
plugin.name = plugin.name.replace(" ", "-");
plugin.version = plugin.version.replace(" ", "-");
this.plugins.push(plugin);
logger.debug(`Plugin ${plugin.name} (${plugin.version}) loaded`);
}

async initializePlugins(core: AxonCore) {
this.plugins.forEach(plugin => {
plugin.init(core);
logger.info(`Plugin ${plugin.name} (${plugin.version}) initialized`)
})
}

async getPlugins(): Promise<AxonPlugin[]> {
return this.plugins;
}
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AxonCoreConfig } from "./core/coreTypes";
import * as http from "http"
import AxonResponse from "./core/AxonResponse";
import { AxonResponseMessage } from "./core/coreTypes";
import { AxonPlugin } from "./types/AxonPlugin";

const Router = () => {
return new AxonRouter()
Expand Down Expand Up @@ -49,6 +50,7 @@ export {
Response,
Headers,
nextFn,
AxonPlugin,
Controller,
Middleware
}
8 changes: 8 additions & 0 deletions src/types/AxonPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import AxonCore from "../core/AxonCore";

export interface AxonPlugin {
name: string;
version: string;
init(core: AxonCore): void;
[methodName: string]: any;
}

0 comments on commit 1ee2dfe

Please sign in to comment.