zyket 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +38 -0
- package/README.md +3 -0
- package/index.js +12 -0
- package/package.json +23 -0
- package/src/Middleware.js +4 -0
- package/src/kernel/index.js +52 -0
- package/src/services/Service.js +11 -0
- package/src/services/cache/index.js +38 -0
- package/src/services/database/index.js +69 -0
- package/src/services/index.js +12 -0
- package/src/services/logger/index.js +81 -0
- package/src/services/s3/index.js +83 -0
- package/src/services/socketio/Handler.js +11 -0
- package/src/services/socketio/Middleware.js +11 -0
- package/src/services/socketio/SocketIO.js +138 -0
- package/src/services/socketio/index.js +5 -0
- package/src/utils/EnvManager.js +32 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Publish Package to npmjs
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
jobs:
|
|
7
|
+
build:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
packages: write
|
|
12
|
+
attestations: write
|
|
13
|
+
id-token: write
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout code
|
|
16
|
+
uses: actions/checkout@v2
|
|
17
|
+
|
|
18
|
+
- name: Setup Node.js
|
|
19
|
+
uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: '20.x'
|
|
22
|
+
registry-url: 'https://registry.npmjs.org'
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: npm install
|
|
26
|
+
|
|
27
|
+
- name: 'Bump version'
|
|
28
|
+
id: version-bump
|
|
29
|
+
uses: 'phips28/gh-action-bump-version@master'
|
|
30
|
+
env:
|
|
31
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
with:
|
|
33
|
+
commit-message: 'CI: bumps version to {{version}} [skip ci]'
|
|
34
|
+
|
|
35
|
+
- name: Publish to npm
|
|
36
|
+
run: npm publish
|
|
37
|
+
env:
|
|
38
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const Kernel = require("./src/kernel");
|
|
2
|
+
const Service = require("./src/services/Service");
|
|
3
|
+
const { Handler, Middleware } = require("./src/services/socketio");
|
|
4
|
+
const EnvManager = require("./src/utils/EnvManager");
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
Kernel,
|
|
8
|
+
Service,
|
|
9
|
+
Handler,
|
|
10
|
+
Middleware,
|
|
11
|
+
EnvManager
|
|
12
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zyket",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [],
|
|
9
|
+
"author": "",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"description": "",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"colors": "^1.4.0",
|
|
14
|
+
"dotenv": "^16.4.7",
|
|
15
|
+
"fast-glob": "^3.3.3",
|
|
16
|
+
"mariadb": "^3.4.0",
|
|
17
|
+
"minio": "^8.0.5",
|
|
18
|
+
"node-dependency-injection": "^3.2.2",
|
|
19
|
+
"redis": "^4.7.0",
|
|
20
|
+
"sequelize": "^6.37.6",
|
|
21
|
+
"socket.io": "^4.8.1"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const {ContainerBuilder} = require("node-dependency-injection");
|
|
2
|
+
const EnvManager = require("../utils/EnvManager");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
module.exports = class Kernel {
|
|
7
|
+
container;
|
|
8
|
+
#services;
|
|
9
|
+
#onSocketConnection;
|
|
10
|
+
|
|
11
|
+
constructor({
|
|
12
|
+
services = [],
|
|
13
|
+
onConnection = () => { },
|
|
14
|
+
} = { }) {
|
|
15
|
+
this.container = new ContainerBuilder();
|
|
16
|
+
this.#services = services;
|
|
17
|
+
|
|
18
|
+
// create src folder if not exists
|
|
19
|
+
if (!fs.existsSync(path.join(process.cwd(), "src"))) {
|
|
20
|
+
fs.mkdirSync(path.join(process.cwd(), "src"));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async boot(clearConsole = true, secretsPath = `${process.cwd()}/.env`) {
|
|
25
|
+
EnvManager.load(secretsPath, false);
|
|
26
|
+
if(clearConsole) process.stdout.write("\u001b[2J\u001b[0;0H");
|
|
27
|
+
const services = require("../services");
|
|
28
|
+
|
|
29
|
+
await this.#registerServices(services);
|
|
30
|
+
await this.#registerServices(this.#services);
|
|
31
|
+
|
|
32
|
+
for (const [name] of [...services, ...this.#services]) {
|
|
33
|
+
this.container.get('logger').debug(`Booting service ${name}`);
|
|
34
|
+
await this.container.get(name).boot();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async #registerServices(servicesToRegister = []) {
|
|
39
|
+
for (const [name, serviceClass, args] of servicesToRegister) {
|
|
40
|
+
this.container.register(name, serviceClass, args.map(arg => {
|
|
41
|
+
if(arg === "@service_container") return this.container;
|
|
42
|
+
if(arg === "@onConnection") return this.#onSocketConnection;
|
|
43
|
+
return arg
|
|
44
|
+
}));
|
|
45
|
+
if(this.container.has("logger")) {
|
|
46
|
+
this.container.get("logger").debug(`Service ${name} registered`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.container.compile();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const Service = require("../Service");
|
|
2
|
+
const { createClient } = require("redis");
|
|
3
|
+
|
|
4
|
+
module.exports = class Cache extends Service {
|
|
5
|
+
#container;
|
|
6
|
+
client;
|
|
7
|
+
|
|
8
|
+
constructor(container, url) {
|
|
9
|
+
super("cache");
|
|
10
|
+
this.#container = container;
|
|
11
|
+
this.client = createClient({ url });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async boot() {
|
|
15
|
+
await this.client.connect();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async set(key, value) {
|
|
19
|
+
return await this.client.set(key, value);
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async get(key) {
|
|
24
|
+
return await this.client.get(key);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async del(key) {
|
|
28
|
+
return await this.client.del(key);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async keys(pattern) {
|
|
32
|
+
return await this.client.keys(pattern);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async expire(key, seconds) {
|
|
36
|
+
return await this.client.expire(key, seconds);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const { Sequelize } = require("sequelize");
|
|
2
|
+
const Service = require("../Service");
|
|
3
|
+
const fg = require('fast-glob');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
module.exports = class Database extends Service {
|
|
8
|
+
#container;
|
|
9
|
+
#databaseUrl;
|
|
10
|
+
sequelize
|
|
11
|
+
models = {}
|
|
12
|
+
|
|
13
|
+
constructor(container, databaseUrl) {
|
|
14
|
+
super('database');
|
|
15
|
+
this.#container = container;
|
|
16
|
+
this.#databaseUrl = databaseUrl;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async boot() {
|
|
20
|
+
this.#createModelsFolder();
|
|
21
|
+
this.sequelize = new Sequelize(process.env.DATABASE_URL, {
|
|
22
|
+
dialect: process.env.DATABASE_DIALECT || 'mariadb',
|
|
23
|
+
logging: (msg) => this.#container.get('logger').debug(msg),
|
|
24
|
+
operatorsAliases: 0,
|
|
25
|
+
pool: {
|
|
26
|
+
max: 40,
|
|
27
|
+
min: 0,
|
|
28
|
+
acquire: 30000,
|
|
29
|
+
idle: 10000
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await this.sequelize.authenticate();
|
|
34
|
+
|
|
35
|
+
await this.#loadModels();
|
|
36
|
+
|
|
37
|
+
this.#container.get('logger').debug(`Database modesl loaded: ${Object.keys(this.models).join(", ")}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async #loadModels() {
|
|
41
|
+
const models = await fg('*.js', { cwd: path.join(process.cwd(), "src", "models") });
|
|
42
|
+
for (const model of models) {
|
|
43
|
+
const modelPath = path.join(process.cwd(), "src", "models", model);
|
|
44
|
+
const modelFunc = require(modelPath);
|
|
45
|
+
if (typeof modelFunc !== 'function') {
|
|
46
|
+
this.#container.get('logger').error(`Model ${model} is not a function`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const modelInstance = modelFunc({sequelize: this.sequelize, container: this.#container, Sequelize});
|
|
50
|
+
this.models[model.replace('.js', '')] = modelInstance;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
for (const model of Object.values(this.models)) {
|
|
54
|
+
if (model.associate) {
|
|
55
|
+
model.associate(this.models);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#createModelsFolder() {
|
|
61
|
+
const path = 'src/models';
|
|
62
|
+
if (!fs.existsSync(path)) fs.mkdirSync(path);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
sync() {
|
|
66
|
+
return this.sequelize.sync();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const Database = require("./Database");
|
|
2
|
+
const Cache = require("./Cache");
|
|
3
|
+
const S3 = require("./S3");
|
|
4
|
+
const { SocketIO } = require("./socketio");
|
|
5
|
+
|
|
6
|
+
module.exports = [
|
|
7
|
+
["logger", require("./Logger"), ["@service_container", process.env.LOG_DIRECTORY || `${process.cwd()}/logs`, process.env.DEBUG === "true"]],
|
|
8
|
+
process.env.DATABASE_URL ? ["database", Database, ["@service_container", process.env.DATABASE_URL]] : null,
|
|
9
|
+
process.env.CACHE_URL ? ["cache", Cache, ["@service_container", process.env.CACHE_URL]] : null,
|
|
10
|
+
(process.env.S3_ENDPOINT && process.env.S3_ACCESS_KEY && process.env.S3_SECRET_KEY) ? ["s3", S3, ["@service_container", process.env.S3_ENDPOINT, process.env.S3_PORT, process.env.S3_USE_SSL === "true", process.env.S3_ACCESS_KEY, process.env.S3_SECRET_KEY]] : null,
|
|
11
|
+
["socketio", SocketIO, ["@service_container", process.env.PORT || 3000]],
|
|
12
|
+
].filter(Boolean);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const Service = require("../Service");
|
|
3
|
+
require("colors");
|
|
4
|
+
|
|
5
|
+
module.exports = class Logger extends Service {
|
|
6
|
+
#container
|
|
7
|
+
#logDirectory;
|
|
8
|
+
#debugEnabled;
|
|
9
|
+
messageColors = {
|
|
10
|
+
log: "white",
|
|
11
|
+
info: "green",
|
|
12
|
+
warn: "yellow",
|
|
13
|
+
error: "red",
|
|
14
|
+
debug: "blue"
|
|
15
|
+
};
|
|
16
|
+
#storeTries = 0;
|
|
17
|
+
|
|
18
|
+
constructor(container, logDirectory, debugEnabled) {
|
|
19
|
+
super("logger");
|
|
20
|
+
this.#container = container;
|
|
21
|
+
this.#logDirectory = logDirectory;
|
|
22
|
+
this.#debugEnabled = debugEnabled;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async boot() {
|
|
26
|
+
if (!fs.existsSync(this.#logDirectory)) fs.mkdirSync(this.#logDirectory);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async store(message) {
|
|
31
|
+
if (this.#storeTries > 10) throw new Error("Failed to store log message");
|
|
32
|
+
this.#storeTries++;
|
|
33
|
+
try{
|
|
34
|
+
fs.appendFileSync(`${this.#logDirectory}/${new Date().toISOString().split("T")[0]}.log`, `${message}\n`);
|
|
35
|
+
this.#storeTries = 0;
|
|
36
|
+
} catch (e) {
|
|
37
|
+
if (!fs.existsSync(this.#logDirectory)) {
|
|
38
|
+
fs.mkdirSync(this.#logDirectory);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(`${this.#logDirectory}/${new Date().toISOString().split("T")[0]}.log`)) {
|
|
42
|
+
fs.writeFileSync(`${this.#logDirectory}/${new Date().toISOString().split("T")[0]}.log`, "");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this.store(message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getDateTimestamp() {
|
|
50
|
+
return new Date().toISOString().replace("T", " ").replace("Z", "");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
buildMessage(type, message) {
|
|
54
|
+
return `${this.getDateTimestamp()} [${type.toUpperCase()}] ${message}`[this.messageColors[type]];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async log(message) {
|
|
58
|
+
console.log(this.buildMessage("log", message));
|
|
59
|
+
this.store(this.buildMessage("log", message));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async info(message) {
|
|
63
|
+
console.log(this.buildMessage("info", message));
|
|
64
|
+
this.store(this.buildMessage("info", message));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async warn(message) {
|
|
68
|
+
console.log(this.buildMessage("warn", message));
|
|
69
|
+
this.store(this.buildMessage("warn", message));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async error(message) {
|
|
73
|
+
console.log(this.buildMessage("error", message));
|
|
74
|
+
this.store(this.buildMessage("error", message));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async debug(message) {
|
|
78
|
+
this.#debugEnabled && console.log(this.buildMessage("debug", message));
|
|
79
|
+
this.store(this.buildMessage("debug", message));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const Service = require("../Service");
|
|
2
|
+
const MinioService = require('minio')
|
|
3
|
+
|
|
4
|
+
module.exports = class S3 extends Service {
|
|
5
|
+
#container
|
|
6
|
+
#endPoint
|
|
7
|
+
#port
|
|
8
|
+
#useSSL
|
|
9
|
+
#accessKey
|
|
10
|
+
#secretKey
|
|
11
|
+
|
|
12
|
+
constructor(container, endPoint, port, useSSL, accessKey, secretKey) {
|
|
13
|
+
super('s3')
|
|
14
|
+
this.#container = container
|
|
15
|
+
this.#endPoint = endPoint
|
|
16
|
+
this.#port = port
|
|
17
|
+
this.#useSSL = useSSL
|
|
18
|
+
this.#accessKey = accessKey
|
|
19
|
+
this.#secretKey = secretKey
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async boot() {
|
|
23
|
+
this.client = new MinioService.Client({
|
|
24
|
+
endPoint: this.#endPoint,
|
|
25
|
+
port: this.#port,
|
|
26
|
+
useSSL: this.#useSSL,
|
|
27
|
+
accessKey: this.#accessKey,
|
|
28
|
+
secretKey: this.#secretKey
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async saveFile(bucketName, fileName, file, contentType = 'binary/octet-stream') {
|
|
33
|
+
this.#container.get('logger').debug(`Saving file ${fileName} to bucket ${bucketName}`);
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
this.client.putObject(
|
|
36
|
+
bucketName,
|
|
37
|
+
fileName,
|
|
38
|
+
file,
|
|
39
|
+
{
|
|
40
|
+
"Content-Type": contentType
|
|
41
|
+
},
|
|
42
|
+
(err, etag) => {
|
|
43
|
+
if (err) return reject(err);
|
|
44
|
+
resolve(etag);
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getFile(bucketName, fileName) {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
let data = ''
|
|
53
|
+
this.client.getObject(bucketName, fileName, (err, stream) => {
|
|
54
|
+
if(err) return reject(err)
|
|
55
|
+
stream.on('data', (chunk) => {
|
|
56
|
+
data += chunk
|
|
57
|
+
})
|
|
58
|
+
stream.on('end', () => {
|
|
59
|
+
resolve(data)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async removeFile(bucketName, fileName) {
|
|
66
|
+
this.#container.get('logger').debug(`Removing file ${fileName} from bucket ${bucketName}`);
|
|
67
|
+
return this.client.removeObject(bucketName, fileName)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async createBucket(bucketName) {
|
|
71
|
+
this.#container.get('logger').debug(`Creating bucket ${bucketName}`);
|
|
72
|
+
return this.client.makeBucket(bucketName, 'us-east-1')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
listBuckets() {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
this.client.listBuckets((err, buckets) => {
|
|
78
|
+
if(err) return reject(err)
|
|
79
|
+
resolve(buckets)
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const Service = require("../Service");
|
|
2
|
+
const { Server } = require("socket.io");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fg = require('fast-glob');
|
|
6
|
+
const Handler = require("./Handler");
|
|
7
|
+
const Middleware = require("./Middleware");
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
module.exports = class SocketIO extends Service {
|
|
11
|
+
port;
|
|
12
|
+
#container;
|
|
13
|
+
io;
|
|
14
|
+
middlewares = {};
|
|
15
|
+
|
|
16
|
+
constructor(container, port, onConnection = () => { }) {
|
|
17
|
+
super("socketio");
|
|
18
|
+
this.port = port || 3000;
|
|
19
|
+
this.#container = container;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async boot() {
|
|
23
|
+
const middlewares = await this.#loadMiddlewaresFromFolder(path.join(process.cwd(), "src", "middlewares"));
|
|
24
|
+
for (const middleware of middlewares) {
|
|
25
|
+
this.middlewares[middleware.name] = middleware;
|
|
26
|
+
}
|
|
27
|
+
const handlers = await this.#loadHandlersFromFolder(path.join(process.cwd(), "src", "handlers"));
|
|
28
|
+
const connectionHandler = new (await this.#loadConnectionHandler())();
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
this.#container.get('logger').debug(`Middlewares: ${middlewares.map(mdl => mdl.name).join(", ")}`);
|
|
32
|
+
this.#container.get('logger').debug(`Handlers: ${handlers.map(hdl => hdl.event).join(", ")}`);
|
|
33
|
+
|
|
34
|
+
this.io = new Server({ cors: { origin: "*" }, maxHttpBufferSize: 10 * 1024 * 1024 });
|
|
35
|
+
|
|
36
|
+
this.io.on("connection", (socket) => {
|
|
37
|
+
const connectionMiddlewares = (connectionHandler?.middlewares || []).map(mdl => this.middlewares[mdl])
|
|
38
|
+
for (const middleware of connectionMiddlewares) {
|
|
39
|
+
if(!middleware) {
|
|
40
|
+
this.#container.get('logger').warn(`You are using a middleware that does not exist`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
middleware.handle({ container: this.#container, socket });
|
|
44
|
+
}
|
|
45
|
+
connectionHandler.handle({ container: this.#container, socket });
|
|
46
|
+
handlers.forEach((handler) => {
|
|
47
|
+
const handlerMiddlewares = (handler?.middlewares || []).map(mdl => this.middlewares[mdl])
|
|
48
|
+
socket.on(handler.event, async (data) => {
|
|
49
|
+
this.#container.get('logger').debug(`[${socket?.id}] Sent ${handler.event} with middlewares: ${handlerMiddlewares?.map(mdl => mdl?.name).join(", ")}`);
|
|
50
|
+
for (const middleware of handlerMiddlewares) {
|
|
51
|
+
if(!middleware) {
|
|
52
|
+
this.#container.get('logger').warn(`You are using a middleware that does not exist`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
await middleware.handle({ container: this.#container, socket });
|
|
56
|
+
}
|
|
57
|
+
return await handler.handle({ container: this.#container, socket, data });
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
this.io.listen(this.port);
|
|
63
|
+
this.#container.get('logger').info(`Socket.IO is running on port ws://localhost:${this.port}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async #loadConnectionHandler() {
|
|
67
|
+
const connectionHandlerExists = fs.existsSync(path.join(process.cwd(), "src", "handlers", "connection.js"));
|
|
68
|
+
/* if exists require, otherwise create a default one */
|
|
69
|
+
if(!connectionHandlerExists) {
|
|
70
|
+
fs.writeFileSync(path.join(process.cwd(), "src", "handlers", "connection.js"), `const { Handler } = require("zyket");
|
|
71
|
+
|
|
72
|
+
module.exports = class ConnectionHandler extends Handler {
|
|
73
|
+
async handle({ container, socket }) {
|
|
74
|
+
container.get("logger").info("New connection");
|
|
75
|
+
}
|
|
76
|
+
};`);
|
|
77
|
+
}
|
|
78
|
+
return require(path.join(process.cwd(), "src", "handlers", "connection.js"));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async #loadHandlersFromFolder(handlersFolder) {
|
|
82
|
+
this.#createHandlersFolder(handlersFolder);
|
|
83
|
+
// need to read all files and subfolders
|
|
84
|
+
const handlers = (await fg('**/*.js', { cwd: handlersFolder, ignore: 'connection.js' })).map((hdr) => {
|
|
85
|
+
// should be type handler
|
|
86
|
+
const handler = require(path.join(handlersFolder, hdr));
|
|
87
|
+
if(!(handler.prototype instanceof Handler)) throw new Error(`${hdr} is not a valid handler`);
|
|
88
|
+
return new handler(hdr.replace('.js', ''));
|
|
89
|
+
});
|
|
90
|
+
return handlers;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#createHandlersFolder(handlersFolder, overwrite = false) {
|
|
94
|
+
if (fs.existsSync(handlersFolder) && !overwrite) return;
|
|
95
|
+
this.#container.get('logger').info(`Creating handlers folder at ${handlersFolder}`);
|
|
96
|
+
fs.mkdirSync(handlersFolder);
|
|
97
|
+
// create a default handler
|
|
98
|
+
fs.writeFileSync(path.join(handlersFolder, "message.js"), `const { Handler } = require("zyket");
|
|
99
|
+
module.exports = class MessageHandler extends Handler {
|
|
100
|
+
event = "message";
|
|
101
|
+
middlewares = ["default"];
|
|
102
|
+
|
|
103
|
+
async handle({ container, socket, data }) {
|
|
104
|
+
container.get("logger").info("Message handler");
|
|
105
|
+
}
|
|
106
|
+
};`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async #loadMiddlewaresFromFolder(middlewaresFolder) {
|
|
110
|
+
this.#createMiddlewaresFolder(middlewaresFolder);
|
|
111
|
+
// need to read all files and subfolders
|
|
112
|
+
const middlewares = await fg('**/*.js', { cwd: middlewaresFolder })
|
|
113
|
+
|
|
114
|
+
return middlewares.map((mdl) => {
|
|
115
|
+
// should be type middleware
|
|
116
|
+
const middleware = require(path.join(middlewaresFolder, mdl));
|
|
117
|
+
if(!(middleware.prototype instanceof Middleware)) throw new Error(`${mdl} is not a valid middleware`);
|
|
118
|
+
return new middleware(mdl.replace('.js', ''));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#createMiddlewaresFolder(middlewaresFolder, overwrite = false) {
|
|
123
|
+
if (fs.existsSync(middlewaresFolder) && !overwrite) return;
|
|
124
|
+
this.#container.get('logger').info(`Creating middlewares folder at ${middlewaresFolder}`);
|
|
125
|
+
fs.mkdirSync(middlewaresFolder);
|
|
126
|
+
// create a default middleware
|
|
127
|
+
fs.writeFileSync(path.join(middlewaresFolder, "default.js"), `const { Middleware } = require("zyket");
|
|
128
|
+
module.exports = class DefaultMiddleware extends Middleware {
|
|
129
|
+
async handle({ container, socket }) {
|
|
130
|
+
container.get("logger").info("Default middleware");
|
|
131
|
+
}
|
|
132
|
+
};`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
stop() {
|
|
136
|
+
this.io.close();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
module.exports = class EnvManager {
|
|
4
|
+
static load(secretsPath) {
|
|
5
|
+
this.createEnvFile(secretsPath);
|
|
6
|
+
require("dotenv").config({ path: secretsPath });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static createEnvFile(secretsPath, overwrite = false) {
|
|
10
|
+
if (fs.existsSync(secretsPath) && !overwrite) return;
|
|
11
|
+
fs.writeFileSync(secretsPath, this.getDefaultSecrets());
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static getDefaultSecrets() {
|
|
15
|
+
const envsToCreate = {
|
|
16
|
+
DEBUG: true,
|
|
17
|
+
PORT: 3000,
|
|
18
|
+
DATABASE_URL: '',
|
|
19
|
+
CACHE_URL: '',
|
|
20
|
+
S3_ENDPOINT: '',
|
|
21
|
+
S3_PORT: '',
|
|
22
|
+
S3_USE_SSL: true,
|
|
23
|
+
S3_ACCESS_KEY: '',
|
|
24
|
+
S3_SECRET_KEY: '',
|
|
25
|
+
LOG_DIRECTORY: "./logs"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return Object.entries(envsToCreate).reduce((acc, [key, value]) => {
|
|
29
|
+
return `${acc}${key}=${value}\n`;
|
|
30
|
+
}, "");
|
|
31
|
+
}
|
|
32
|
+
}
|