Skip to content

Commit

Permalink
support https #17
Browse files Browse the repository at this point in the history
feat(core): https server config added to core configs.
  • Loading branch information
MR-MKZ authored Nov 28, 2024
2 parents 337f1fd + 0ef771f commit 9c126a2
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 33 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ 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:
- fixed core freeze when load route function didn't bind. [#3](https://github.com/MR-MKZ/AxonJs/issues/3)
- Https support added to AxonCore. [#17](https://github.com/MR-MKZ/AxonJs/issues/17)
- Plugin manager system added to core. (Document will update soon - 2024/10/24)


Expand Down Expand Up @@ -58,6 +58,7 @@ You can checkout Axon benchmarks document and results from below link.
- Plugin manager (You can create your own plugins and use them in other projects)
- Controllers and Middlewares
- Default cors configuration method
- Support https server

**More features soon...**

Expand Down Expand Up @@ -157,6 +158,7 @@ AxonJs has some types which can help you in developing your applications for aut
- `AxonCoreConfig`: Type of core config object for configuration Axon core as you want.
- `AxonResponseMessage`: Type of core config option RESPONSE_MESSAGES.
- `AxonCorsConfig`: Type of core config option CORS.
- `AxonHttpsConfig`: Type of core config option HTTPS.
- `Request`: Type of controller request param. (IncomingMessage)
- `Response`: Type of controller response param. (ServerResponse)
- `Headers`: Type of response headers. (OutgoingHeaders)
Expand All @@ -183,11 +185,23 @@ Configs:
- `LOGGER_VERBOSE`: boolean to set core logger in verbose mode. (default false)
- `RESPONSE_MESSAGES`: object to change default value of some core responses. (type: AxonResponseMessage)
- `CORS`: object to change core cors settings. (type: AxonCorsConfig)
- `HTTPS`: object to config server for https. (type: AxonHttpsConfig)

### Running server

`listen` method runs your webserver.

**If you want to run your server on https, you have to set key and cert file in HTTPS config of core to run https server automatically by core**

```js
core.loadConfig({
HTTPS: {
key: fs.readFileSync(path.join("server.key")),
cert: fs.readFileSync(path.join("server.crt"))
}
})
```

**`core.listen()` has some default values**
1. host: default value of host in 127.0.0.1
2. port: default value of port is 8000
Expand Down
6 changes: 6 additions & 0 deletions examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/

import { Axon, Router } from "../src";
import path from "path";
import fs from "fs";

const core = Axon();

Expand All @@ -19,6 +21,10 @@ core.loadConfig({
},
CORS: {
origin: 'https://github.com'
},
HTTPS: {
key: fs.readFileSync(path.join("examples", "server.key")),
cert: fs.readFileSync(path.join("examples", "server.crt"))
}
})

Expand Down
6 changes: 6 additions & 0 deletions examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Axon, Request, Response, nextFn } from "../src";
import { v1Routes } from "./routes/v1";
import { v2Routes } from "./routes/v2";
import { LogPluginTest } from "./plugins/log";
import path from "path";
import fs from "fs";

const core = Axon()

Expand All @@ -18,6 +20,10 @@ core.loadConfig({
},
CORS: {
origin: 'https://github.com'
},
HTTPS: {
key: fs.readFileSync(path.join("examples", "server.key")),
cert: fs.readFileSync(path.join("examples", "server.crt"))
}
})

Expand Down
3 changes: 0 additions & 3 deletions examples/routes/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ const router = Router();
// you can add another middleware by repeating this function. they will run in order.
// example: router.get().middleware().middleware()
router.get('/user/:name', async (req, res) => {

console.log("Controller");

return res.status(201).body({ message: `Hello ${req.params.name}` })
}).middleware(async (req, res, next) => {
next()
Expand Down
11 changes: 11 additions & 0 deletions examples/server.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBnzCCAQgCCQC1x1LJh4G1AzANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDEwls
b2NhbGhvc3QwHhcNMDkxMTEwMjM0ODQ3WhcNMTkxMTA4MjM0ODQ3WjAUMRIwEAYD
VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMEl0yfj
7K0Ng2pt51+adRAj4pCdoGOVjx1BmljVnGOMW3OGkHnMw9ajibh1vB6UfHxu463o
J1wLxgxq+Q8y/rPEehAjBCspKNSq+bMvZhD4p8HNYMRrKFfjZzv3ns1IItw46kgT
gDpAl1cMRzVGPXFimu5TnWMOZ3ooyaQ0/xntAgMBAAEwDQYJKoZIhvcNAQEFBQAD
gYEAavHzSWz5umhfb/MnBMa5DL2VNzS+9whmmpsDGEG+uR0kM1W2GQIdVHHJTyFd
aHXzgVJBQcWTwhp84nvHSiQTDBSaT6cQNQpvag/TaED/SEQpm0VqDFwpfFYuufBL
vVNbLkKxbK2XwUvu0RxoLdBMC/89HqrZ0ppiONuQ+X2MtxE=
-----END CERTIFICATE-----
15 changes: 15 additions & 0 deletions examples/server.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDBJdMn4+ytDYNqbedfmnUQI+KQnaBjlY8dQZpY1ZxjjFtzhpB5
zMPWo4m4dbwelHx8buOt6CdcC8YMavkPMv6zxHoQIwQrKSjUqvmzL2YQ+KfBzWDE
ayhX42c7957NSCLcOOpIE4A6QJdXDEc1Rj1xYpruU51jDmd6KMmkNP8Z7QIDAQAB
AoGBAJvUs58McihQrcVRdIoaqPXjrei1c/DEepnFEw03EpzyYdo8KBZM0Xg7q2KK
gsM9U45lPQZTNmY6DYh5SgYsQ3dGvocvwndq+wK+QsWH8ngTYqYqwUBBCaX3kwgk
nAc++EpRRVmV0dJMdXt3xAUKSXnDP9fLPdKXffJoG7C1HHVVAkEA+087rR2FLCjd
Rq/9WhIT/p2U0RRQnMJyQ74chIJSbeyXg8Ell5QxhSg7skrHSZ0cBPhyaLNDIZkn
3NMnK2UqhwJBAMTAsUorHNo4dGpO8y2HE6QXxeuX05OhjiO8H2hmmcuMi2C9OwGI
rI+lx1Q8mK261NKJh7sSVwQikh5YQYLKcOsCQQD6YqcChDb7GHvewdmatAhX1ok/
Bw6KIPHXrMKdA3s9KkyLaRUbQPtVwBA6Q2brYS1Zhm/3ASQRhZbB3V9ZTSJhAkB7
72097P5Vr24VcPnZWdbTbG4twwtxWTix5dRa7RY/k55QJ6K9ipw4OBLhSvJZrPBW
Vm97NUg+wJAOMUXC30ZVAkA6pDgLbxVqkCnNgh2eNzhxQtvEGE4a8yFSUfSktS9U
bjAATRYXNv2mAms32aAVKTzgSTapEX9M1OWdk+/yJrJs
-----END RSA PRIVATE KEY-----
95 changes: 68 additions & 27 deletions src/core/AxonCore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as http from "http";
import * as https from "https";
import { colors } from "@spacingbat3/kolor"
import { Key, pathToRegexp, Keys } from "path-to-regexp";

Expand All @@ -23,6 +24,7 @@ import Router from "../Router/AxonRouter";
import { PLuginLoader } from "./plugin/PluginLoader";
import AxonResponse from "./response/AxonResponse";
import AxonCors from "./cors/AxonCors";
import { log } from "console";

// Default values
const defaultResponses = {
Expand Down Expand Up @@ -65,7 +67,8 @@ export default class AxonCore {
LOGGER: true,
LOGGER_VERBOSE: false,
RESPONSE_MESSAGES: defaultResponses,
CORS: defaultCors
CORS: defaultCors,
HTTPS: {}
};

this.configsLoaded = false;
Expand Down Expand Up @@ -100,6 +103,7 @@ export default class AxonCore {
this.config.LOGGER_VERBOSE = config.LOGGER_VERBOSE || false
this.config.RESPONSE_MESSAGES = { ...config.RESPONSE_MESSAGES }
this.config.CORS = { ...config.CORS }
this.config.HTTPS = { ...config.HTTPS }

if (this.config.DEBUG) {
logger.level = "debug"
Expand Down Expand Up @@ -206,7 +210,7 @@ export default class AxonCore {
})
}

return Object.keys(this.routes[method]).forEach(async (path, index) => {
Object.keys(this.routes[method]).forEach(async (path, index) => {
let keys: Keys;
const regexp = pathToRegexp(path);
keys = regexp.keys
Expand Down Expand Up @@ -238,29 +242,28 @@ export default class AxonCore {

const axonCors = await AxonCors.middlewareWrapper(this.config.CORS);

return this.handleMiddleware(req, res, async () => {
return await this.handleMiddleware(req, res, async () => {
return await this.handleMiddleware(req, res, async () => {
await this.handleMiddleware(req, res, async () => {
await this.handleMiddleware(req, res, async () => {
await this.handleMiddleware(req, res, async () => {
await controller(req, res);

// log incoming requests
if (this.config.LOGGER_VERBOSE) {
logger.request({
ip: req.socket.remoteAddress,
url: req.url,
method: req.method,
headers: req.headers,
body: req.body,
code: res.statusCode
}, "new http request")
} else {
logger.request(`${req.socket.remoteAddress} - ${req.method} ${req.url} ${res.statusCode} - ${req.headers["user-agent"]}`)
}

}, middlewares);
}, this.globalMiddlewares);
}, [axonCors]);

// log incoming requests
if (this.config.LOGGER_VERBOSE) {
logger.request({
ip: req.socket.remoteAddress,
url: req.url,
method: req.method,
headers: req.headers,
body: req.body,
code: res.statusCode
}, "new http request")
} else {
logger.request(`${req.socket.remoteAddress} - ${req.method} ${req.url} ${res.statusCode} - ${req.headers["user-agent"]}`)
}

} else {
return;
}
Expand Down Expand Up @@ -362,7 +365,7 @@ export default class AxonCore {
* @param {number} port server port
* @param {Function} [callback] callback a function to run after starting to listen
*/
async listen(host: string = "127.0.0.1", port: number = 8000, callback?: () => void) {
async listen(host: string = "127.0.0.1", port: number | { https: number, http: number } = 8000, callback?: (mode?: string) => void) {

// Wait until some necessary items are loaded before starting the server
const corePreloader = async (): Promise<void> => {
Expand Down Expand Up @@ -393,25 +396,63 @@ export default class AxonCore {

await this.#initializePlugins();

const server = http.createServer(async (req: http.IncomingMessage, res: http.ServerResponse) => {
const httpHandler = async (req: http.IncomingMessage, res: http.ServerResponse) => {
try {
await getRequestBody(req)

this.#handleRequest(req, res)
} catch (error) {
logger.error(error, "Unexpected core error")
}
})
}

const portHandler = (mode: string) => {
switch (mode) {
case "http":
if (typeof port === "object") {
return port.http
} else {
return port
}
case "https":
if (typeof port === "object") {
return port.https
} else {
return 8443
}
default:
return 8000
}
}

const isHttpsActive = () => Object.keys(this.config.HTTPS || {}).length > 0;
let httpsServer;

if (isHttpsActive()) {
httpsServer = https.createServer(this.config.HTTPS || {}, httpHandler);
}
const httpServer = http.createServer(httpHandler)

if (!callback) {
callback = () => {
logger.core(colors.whiteBright(`server started on http://${host}:${port}`))
callback = (mode?: string) => {
if (mode === "https") {
isHttpsActive() && logger.core(colors.whiteBright(`server started on https://${host}:${portHandler("https")}`));
} else if (mode === "http") {
logger.core(colors.whiteBright(`server started on http://${host}:${portHandler("http")}`));
}
}
}

server.listen(port, host, callback)
// running web servers
httpsServer?.listen(portHandler("https"), host, () => callback("https"));
httpServer.listen(portHandler("http"), host, () => callback("http"));

httpsServer?.on('error', (e) => {
logger.error(e, `starting server failed`)
process.exit(-1)
});

server.on('error', (e) => {
httpServer.on('error', (e) => {
logger.error(e, `starting server failed`)
process.exit(-1)
});
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import AxonRouter from "./Router/AxonRouter";
// Types
import AxonResponse from "./core/response/AxonResponse";
import { Controller, Middleware , nextFn} from "./types/GlobalTypes";
import { AxonResponseMessage, AxonCorsConfig, AxonCoreConfig } from "./types/CoreTypes";
import { AxonResponseMessage, AxonCorsConfig, AxonCoreConfig, AxonHttpsConfig } from "./types/CoreTypes";
import { AxonPlugin } from "./types/PluginTypes";

/**
Expand Down Expand Up @@ -61,6 +61,7 @@ export {
AxonCoreConfig,
AxonResponseMessage,
AxonCorsConfig,
AxonHttpsConfig,
Request,
Response,
Headers,
Expand Down
12 changes: 11 additions & 1 deletion src/types/CoreTypes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ServerOptions } from "https";

type AxonCoreConfig = {
/**
* AxonCore debug mode.
Expand All @@ -19,8 +21,15 @@ type AxonCoreConfig = {
* Cors configuration for AxonCore.
*/
CORS?: AxonCorsConfig;

/**
* Https configuration for AxonCore.
*/
HTTPS?: AxonHttpsConfig;
}

type AxonHttpsConfig = ServerOptions

/**
* Cors configuration for AxonCore.
*/
Expand Down Expand Up @@ -127,5 +136,6 @@ type AxonResponseMessage = {
export {
AxonCoreConfig,
AxonResponseMessage,
AxonCorsConfig
AxonCorsConfig,
AxonHttpsConfig
}

0 comments on commit 9c126a2

Please sign in to comment.