commit 37047cee22779b13ceb7b0c98704c3e6e574f65a Author: jusax23 Date: Sat Feb 25 18:35:59 2023 +0100 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b9dde30 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +dist +node_modules +config.juml \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..4ca1343 --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +config.juml \ No newline at end of file diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..f68f931 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,23 @@ +# .woodpecker.yml +platform: linux/arm64 + +pipeline: + build: + image: node:18-alpine + commands: + - apk add git zip tar + - npm install + - npm install git+https://jusax.de/git/jusax23/gitea-release.git + - mkdir build + - mkdir juml + - mkdir juml/dist + - mkdir upload + - npm run prepublish + - cp dist/* juml/dist + - cp package.json juml + - cp package-lock.json juml + - cp readme.md juml + - zip -r upload/juml.zip juml/* + - tar -czvf upload/juml.tar.gz juml/* + - npx gitea-release "https://jusax.de/git/api/v1/" "$${GITEA_TOKEN}" "$${CI_REPO}" "$${CI_COMMIT_BRANCH}" "$${CI_COMMIT_TAG}" "upload" "$${CI_COMMIT_MESSAGE}" + secrets: [ gitea_token ] \ No newline at end of file diff --git a/example.js b/example.js new file mode 100644 index 0000000..f0e53c4 --- /dev/null +++ b/example.js @@ -0,0 +1,33 @@ +import juml from "./dist/juml.js"; + +const conf_struct = { + System:{ + PORT:{type:"number",default:80}, + URL:{type:"string",default:"https://google.de/",comment:"The exposed URL:"} + }, + ssl:{ + enable:{type:"boolean",default:true,env:"FMI_SSL_ENABELED"}, + privkey:{type:"string",default:"privkey.pem"}, + cert:{type:"string",default:"cert.pem"}, + chain:{type:"string",default:"chain.pem"} + } +}; + +console.log() + +const mc = new juml(conf_struct); + +mc.connect("./config.juml"); + +if(mc.get("ssl","enable")){ + console.log("SSL Enabled"); + mc.readPathes(mc.get("ssl","privkey"),mc.get("ssl","cert"),mc.get("ssl","chain")) + .then(([privkey,cert,chain])=>{ + console.log("privkey: ",privkey,"\ncert: ",cert,"\nchain: ",chain); + }).catch(err=>{ + console.error(err); + process.exit(); + }); +}else{ + console.log("SSL Disabled"); +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2b3f3bd --- /dev/null +++ b/package-lock.json @@ -0,0 +1,126 @@ +{ + "name": "juml", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "juml", + "version": "1.0.0", + "license": "UNLICENSED", + "dependencies": { + "node-fetch": "^3.3.0" + }, + "devDependencies": { + "@types/node": "^18.11.18", + "typescript": "^4.9.4" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/@types/node": { + "version": "18.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.1.tgz", + "integrity": "sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ==", + "dev": true + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", + "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9961965 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "juml", + "version": "1.0.0", + "description": "", + "main": "dist/juml.js", + "types": "dist/juml.d.ts", + "type": "module", + "directories": { + "dist": "dist" + }, + "files": [ + "dist/*" + ], + "private": false, + "scripts": { + "prepublish": "tsc" + }, + "author": "jusax23", + "license": "UNLICENSED", + "dependencies": { + "node-fetch": "^3.3.0" + }, + "engines": { + "node": ">= 16" + }, + "devDependencies": { + "@types/node": "^18.11.18", + "typescript": "^4.9.4" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..5292eaa --- /dev/null +++ b/readme.md @@ -0,0 +1,6 @@ +# nMan + +A simple way of shutting down a Server. + +## Example +See example.mjs \ No newline at end of file diff --git a/src/juml.ts b/src/juml.ts new file mode 100644 index 0000000..36a6e49 --- /dev/null +++ b/src/juml.ts @@ -0,0 +1,247 @@ +import fs from "fs"; +import fetch from 'node-fetch'; +import path from "path"; + +export default class juml { + #groups: { [key: string]: Group } = {}; + #pathfile: string | null = null; + + constructor(struct: { [x: string]: { [x: string]: any; }; }) { + for (let g in struct) { + this.#groups[g] = new Group(struct[g]); + } + } + connect(file: string, dir = process.cwd()) { + var exists = true; + this.#pathfile = jpath(dir, file); + if (!fs.existsSync(this.#pathfile) || !fs.lstatSync(this.#pathfile).isFile()) { + console.warn("Config does't exists. It will be created: " + this.#pathfile); + exists = false; + } else { + this.fromJUML(fs.readFileSync(this.#pathfile).toString()); + } + this.save(); + return exists; + } + + get(group: string, name: string, empty: any = null) { + if ((this.#groups[group] ?? {})[name] == null) { + return empty; + } + return this.#groups[group][name].valueOf(); + } + set(group: string, name: string, value: any) { + if ((this.#groups[group] ?? {})[name] == null) { + return false; + } + this.#groups[group][name].set(value); + return true; + } + + save() { + if (this.#pathfile != null) fs.writeFileSync(this.#pathfile, this.toJUML()); + } + + fromJUML(juml: string) { + var comment: string[] = []; + let nowGroup: Group | null = null; + + juml.split("\n").map(s => s.trim()).forEach(now => { + if (now.startsWith("#")) { + comment.push(now.slice(1)); + } else if (now.startsWith("[") && now.endsWith("]")) { + let groupName = now.slice(1, -1); + nowGroup = this.#groups[groupName] || null; + nowGroup.setComment(comment.join("\n")); + comment = []; + } else if (now.includes("=") && nowGroup != null) { + let nows = now.split("="); + let name = nows.splice(0, 1)[0].trim(); + let data = nows.join("=").trim(); + if (nowGroup[name] != null) { + nowGroup[name].set = data; + nowGroup[name].comment = comment.join("\n"); + comment = []; + } + } + }); + } + toJUML() { + let json = this.#groups; + var out = ""; + for (let group in json) { + if (json[group].comment() != "") { + out += "\n"; + out += json[group].comment().split("\n").map(d => "#" + d).join("\n"); + } + out += `\n[${group}]\n`; + for (let name in json[group]) { + if (json[group][name].comment != "") { + out += json[group][name].comment.split("\n").map((d: string) => "#" + d).join("\n"); + out += "\n"; + } + out += name + "=" + json[group][name] + "\n"; + } + } + return out; + } + + readPath(path: string, dir = process.cwd()) { + return new Promise((res, rej) => { + if (path.startsWith("http")) { + fetch(path) + .then(d => d.text()) + .then(d => res(d)) + .catch(() => { + rej("Error occurred while fetching: " + path) + }) + } else { + const pathf = jpath(dir, path); + if (!fs.existsSync(pathf) || !fs.statSync(pathf).isFile()) { + rej("Coud not find File: " + pathf); + } else { + try { + var content = fs.readFileSync(pathf).toString(); + res(content); + } catch (e) { + rej("Error occurred while reading: " + pathf); + } + } + } + }); + } + readPathes(...pathes: string[]) { + return new Promise(async (res, rej) => { + var out = []; + for (var i = 0; i < pathes.length; i++) { + try { + out[i] = await this.readPath(pathes[i]); + } catch (e) { + rej(e); + } + } + res(out); + }); + }; +} + +class Group extends Object { + #comment = ""; + [key: string]: Field | any; + constructor(struct: { [x: string]: any; }) { + super({}); + for (let e in struct) { + let elem = struct[e]; + switch (elem.type || "string") { + case "number": { + this[e] = new NField(elem.default ?? 0, elem.comment ?? "", elem.env ?? ""); + } break; + case "boolean": { + this[e] = new BField(elem.default ?? false, elem.comment ?? "", elem.env ?? ""); + } break; + case "string": { + this[e] = new SField(elem.default ?? "", elem.comment ?? "", elem.env ?? ""); + } break; + } + } + } + comment() { + return this.#comment + } + setComment(c: string) { + this.#comment = c; + } +} + +abstract class Field { + command = ""; + valueOf() { } + set set(v: any) { } +} + +class NField extends Field { + comment = ""; + #value = 0; + + constructor(v: any, comment: string, env: string) { + super(); + if (env != "" && process.env[env]) { + this.#value = Number(createType(process.env[env])); + } else { + this.#value = Number(createType(v)); + } + this.comment = comment; + } + set set(v: number) { + this.#value = Number(createType(v)); + } + valueOf() { + return this.#value; + } +} +class BField extends Field { + comment = ""; + #value = false; + + constructor(v: any, comment: string, env: string) { + super(); + if (env != "" && process.env[env]) { + this.#value = Boolean(createType(process.env[env])); + } else { + this.#value = Boolean(createType(v)); + } + this.comment = comment; + } + set set(v: boolean) { + this.#value = Boolean(createType(v)); + } + valueOf() { + return this.#value; + } +} +class SField extends Field { + comment = ""; + #value = ""; + + constructor(v: any, comment: string, env: string) { + super(); + if (env != "" && process.env[env]) { + this.#value = String(createType(process.env[env])); + } else { + this.#value = String(createType(v)); + } + this.comment = comment; + } + set set(v: string) { + this.#value = String(createType(v)); + } + valueOf() { + return this.#value; + } +} + +function createType(data: any) { + if (data == "true") { + return true; + } + if (data == "false") { + return false; + } + if (String(data).toLowerCase() == "infinity") { + return Infinity; + } + if (String(data).toLowerCase() == "-infinity") { + return -Infinity; + } + if (!isNaN(data)) { + return Number(data); + } + return data; +} + +function jpath(a: string, b: string) { + if (b.startsWith("/")) { + return b; + } + return path.join(a, b); +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c0f6647 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "declaration": true, + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + }, + "files": [ + "src/juml.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file