refactor: 重构配置加载功能。
This commit is contained in:
parent
a02bc282bb
commit
3ad35f3358
@ -1,9 +1,9 @@
|
|||||||
import { ConfigLoader } from "../src/config-loader.js";
|
import { ConfigLoader } from "../src/config-loader";
|
||||||
|
|
||||||
const loader = new ConfigLoader();
|
const loader = new ConfigLoader();
|
||||||
|
|
||||||
loader
|
loader
|
||||||
.loadConfig()
|
.load()
|
||||||
.then((config) => {
|
.then((config) => {
|
||||||
console.log("config", config);
|
console.log("config", config);
|
||||||
})
|
})
|
||||||
|
140
package-lock.json
generated
140
package-lock.json
generated
@ -11,7 +11,6 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"etcd3": "^1.1.0",
|
"etcd3": "^1.1.0",
|
||||||
"find-up": "^6.1.0",
|
|
||||||
"js-yaml": "^4.1.0"
|
"js-yaml": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -21,7 +20,7 @@
|
|||||||
"@types/node": "^14.17.17",
|
"@types/node": "^14.17.17",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"ts-node": "^10.2.1",
|
"ts-node": "^10.2.1",
|
||||||
"typescript": "^4.5.0-beta"
|
"typescript": "^4.4.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cspotcode/source-map-consumer": {
|
"node_modules/@cspotcode/source-map-consumer": {
|
||||||
@ -325,22 +324,6 @@
|
|||||||
"cockatiel": "^1.1.1"
|
"cockatiel": "^1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/find-up": {
|
|
||||||
"version": "6.1.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/find-up/-/find-up-6.1.0.tgz",
|
|
||||||
"integrity": "sha512-aBlseiBgQ1RSiF/brMW+toDud3NHJ2Hn3pgNJLmBf2+gBwwNbfhE/Lbg2wwwoHfD3qXReOvDH4hlywQCXp4/Lw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"locate-path": "^7.0.0",
|
|
||||||
"path-exists": "^5.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://npm.ivanli.cc/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://npm.ivanli.cc/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@ -399,21 +382,6 @@
|
|||||||
"js-yaml": "bin/js-yaml.js"
|
"js-yaml": "bin/js-yaml.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/locate-path": {
|
|
||||||
"version": "7.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/locate-path/-/locate-path-7.0.0.tgz",
|
|
||||||
"integrity": "sha512-+cg2yXqDUKfo4hsFxwa3G1cBJeA+gs1vD8FyV9/odWoUlQe/4syxHQ5DPtKjtfm6gnKbZzjCqzX03kXosvZB1w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"p-locate": "^6.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lodash.camelcase": {
|
"node_modules/lodash.camelcase": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://npm.ivanli.cc/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
"resolved": "https://npm.ivanli.cc/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||||
@ -462,45 +430,6 @@
|
|||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/p-limit": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/p-limit/-/p-limit-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"yocto-queue": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/p-locate": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/p-locate/-/p-locate-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"p-limit": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-exists": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/path-exists/-/path-exists-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-is-absolute": {
|
"node_modules/path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://npm.ivanli.cc/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://npm.ivanli.cc/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
@ -599,9 +528,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.5.0-beta",
|
"version": "4.4.4",
|
||||||
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.5.0-beta.tgz",
|
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.4.4.tgz",
|
||||||
"integrity": "sha512-7PvWhki2lwukaR9osVhFnNzxaE4LM+gC94dlwcvS+Tqz8+U65va7FbKo02bT+/MFlnMPM8bsPUXvHiMD/Mg3Jg==",
|
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -628,18 +557,6 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"node_modules/yocto-queue": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/yocto-queue/-/yocto-queue-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.20"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -870,15 +787,6 @@
|
|||||||
"cockatiel": "^1.1.1"
|
"cockatiel": "^1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"find-up": {
|
|
||||||
"version": "6.1.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/find-up/-/find-up-6.1.0.tgz",
|
|
||||||
"integrity": "sha512-aBlseiBgQ1RSiF/brMW+toDud3NHJ2Hn3pgNJLmBf2+gBwwNbfhE/Lbg2wwwoHfD3qXReOvDH4hlywQCXp4/Lw==",
|
|
||||||
"requires": {
|
|
||||||
"locate-path": "^7.0.0",
|
|
||||||
"path-exists": "^5.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://npm.ivanli.cc/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://npm.ivanli.cc/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@ -923,14 +831,6 @@
|
|||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"locate-path": {
|
|
||||||
"version": "7.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/locate-path/-/locate-path-7.0.0.tgz",
|
|
||||||
"integrity": "sha512-+cg2yXqDUKfo4hsFxwa3G1cBJeA+gs1vD8FyV9/odWoUlQe/4syxHQ5DPtKjtfm6gnKbZzjCqzX03kXosvZB1w==",
|
|
||||||
"requires": {
|
|
||||||
"p-locate": "^6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lodash.camelcase": {
|
"lodash.camelcase": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://npm.ivanli.cc/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
"resolved": "https://npm.ivanli.cc/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||||
@ -970,27 +870,6 @@
|
|||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"p-limit": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/p-limit/-/p-limit-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
|
|
||||||
"requires": {
|
|
||||||
"yocto-queue": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"p-locate": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/p-locate/-/p-locate-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
|
|
||||||
"requires": {
|
|
||||||
"p-limit": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"path-exists": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/path-exists/-/path-exists-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="
|
|
||||||
},
|
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://npm.ivanli.cc/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://npm.ivanli.cc/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
@ -1047,9 +926,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.5.0-beta",
|
"version": "4.4.4",
|
||||||
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.5.0-beta.tgz",
|
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.4.4.tgz",
|
||||||
"integrity": "sha512-7PvWhki2lwukaR9osVhFnNzxaE4LM+gC94dlwcvS+Tqz8+U65va7FbKo02bT+/MFlnMPM8bsPUXvHiMD/Mg3Jg==",
|
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
@ -1063,11 +942,6 @@
|
|||||||
"resolved": "https://npm.ivanli.cc/yn/-/yn-3.1.1.tgz",
|
"resolved": "https://npm.ivanli.cc/yn/-/yn-3.1.1.tgz",
|
||||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
|
||||||
"yocto-queue": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://npm.ivanli.cc/yocto-queue/-/yocto-queue-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g=="
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
package.json
19
package.json
@ -1,16 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "configuration",
|
"name": "@fennec/configuration",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Fennec configuration loader and share info.",
|
"description": "Fennec configuration loader and share info.",
|
||||||
"main": "./lib/index.js",
|
"main": "lib",
|
||||||
"types": "./lib/types/index.d.ts",
|
"types": "lib/types/index.d.ts",
|
||||||
"type": "module",
|
"files": [
|
||||||
|
"lib/**/*",
|
||||||
|
"*.md"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "rimraf lib",
|
"prebuild": "rimraf lib",
|
||||||
"build": "tsc -p \"tsconfig.build.json\"",
|
"build": "tsc -p \"tsconfig.build.json\"",
|
||||||
|
"prepublishOnly": "npm run build",
|
||||||
"start:example-register": "DEBUG=* ts-node ./examples/register.ts",
|
"start:example-register": "DEBUG=* ts-node ./examples/register.ts",
|
||||||
"start:example-config-loader": "DEBUG=* node --loader ts-node/esm ./examples/config-loader.ts",
|
"start:example-config-loader": "DEBUG=* ts-node ./examples/config-loader.ts"
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -25,9 +28,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"esm": "^3.2.25",
|
|
||||||
"etcd3": "^1.1.0",
|
"etcd3": "^1.1.0",
|
||||||
"find-up": "^6.1.0",
|
|
||||||
"js-yaml": "^4.1.0"
|
"js-yaml": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -37,6 +38,6 @@
|
|||||||
"@types/node": "^14.17.17",
|
"@types/node": "^14.17.17",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"ts-node": "^10.2.1",
|
"ts-node": "^10.2.1",
|
||||||
"typescript": "^4.5.0-beta"
|
"typescript": "^4.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { AppConfig } from "./app-config.model.js";
|
import { AppConfig } from "./app-config.model";
|
||||||
import { Etcd3 } from "etcd3";
|
import { Etcd3 } from "etcd3";
|
||||||
import { load } from "js-yaml";
|
import { load } from "js-yaml";
|
||||||
import { hostname } from "os";
|
import { hostname } from "os";
|
||||||
import { getEtcdInstance } from "./etcd-connection.js";
|
import { getEtcdInstance } from "./etcd-connection";
|
||||||
import { readFile } from "fs/promises";
|
import { readFile } from "fs/promises";
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
|
import { findUp } from "./utils/find-up";
|
||||||
|
|
||||||
export class ConfigLoader {
|
export class ConfigLoader {
|
||||||
private etcd: Etcd3;
|
private etcd: Etcd3;
|
||||||
@ -17,10 +18,11 @@ export class ConfigLoader {
|
|||||||
this.etcd = getEtcdInstance(config);
|
this.etcd = getEtcdInstance(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadConfig<T extends Object>(configKey?: string): Promise<any> {
|
async load<T extends Object>(configKey?: string): Promise<any> {
|
||||||
const config = await (await import("find-up"))
|
const config = await findUp(
|
||||||
.findUp(["config,yml", "config.yaml"])
|
["config.yml", "config.yaml"],
|
||||||
.then((path) => {
|
process.cwd()
|
||||||
|
).then((path) => {
|
||||||
if (path) {
|
if (path) {
|
||||||
return readFile(path, "utf8").then((str) => load(str));
|
return readFile(path, "utf8").then((str) => load(str));
|
||||||
} else {
|
} else {
|
||||||
@ -34,16 +36,13 @@ export class ConfigLoader {
|
|||||||
} else if (process.env.config_key) {
|
} else if (process.env.config_key) {
|
||||||
configKey = process.env.config_key;
|
configKey = process.env.config_key;
|
||||||
} else {
|
} else {
|
||||||
configKey = await (
|
configKey = await findUp("package.json", process.cwd())
|
||||||
await import("find-up")
|
|
||||||
)
|
|
||||||
.findUp("package.json")
|
|
||||||
.then((path) => {
|
.then((path) => {
|
||||||
if (path) {
|
if (path) {
|
||||||
return readFile(path, "utf8");
|
return readFile(path, "utf8");
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Fallback to using package name as configuration name"
|
"Can't find package.json. Fallback to using package name as configuration name when CONFIG_KEY not defined."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
1
src/config/base-configuration.interface.ts
Normal file
1
src/config/base-configuration.interface.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export interface BaseConfiguration extends Record<string, any> {}
|
43
src/config/etcd-config-reader.ts
Normal file
43
src/config/etcd-config-reader.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import debug from "debug";
|
||||||
|
import { Etcd3, IOptions } from "etcd3";
|
||||||
|
import { load } from "js-yaml";
|
||||||
|
import { hostname } from "os";
|
||||||
|
import { Options } from "../interfaces/options.interface";
|
||||||
|
import { getAppPkg } from "../utils/app-pkg";
|
||||||
|
import { BaseConfiguration } from "./base-configuration.interface";
|
||||||
|
|
||||||
|
const configKeyPrefix = "share/config";
|
||||||
|
const logger = debug("fennec:config:loader:etcd");
|
||||||
|
|
||||||
|
export async function readEtcdConfig<T = BaseConfiguration>({
|
||||||
|
etcd,
|
||||||
|
appName,
|
||||||
|
environment,
|
||||||
|
}: Options): Promise<T> {
|
||||||
|
if (!(etcd instanceof Etcd3)) {
|
||||||
|
etcd = new Etcd3(etcd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appName == undefined) {
|
||||||
|
appName = await getAppPkg().then((pkg) => pkg.name);
|
||||||
|
debug.log("found appName from package.json. [%s]", appName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `${configKeyPrefix}/${environment ?? hostname()}/${appName}`;
|
||||||
|
debug.log('etcd key: "%s"', key);
|
||||||
|
|
||||||
|
const plainText = await etcd.get(key);
|
||||||
|
|
||||||
|
if (plainText === null) {
|
||||||
|
debug.log('No configuration found at "%s"', key);
|
||||||
|
throw new Error(`No configuration found at ${key}`);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (await load(plainText)) as T;
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("Can not parse value as yaml");
|
||||||
|
logger.log("plainText: %s", plainText);
|
||||||
|
logger.log("%O", error);
|
||||||
|
throw new Error(`Failed to parse configuration at ${key}`);
|
||||||
|
}
|
||||||
|
}
|
27
src/config/file-config-reader.ts
Normal file
27
src/config/file-config-reader.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import debug from "debug";
|
||||||
|
import { readFile } from "fs/promises";
|
||||||
|
import { load } from "js-yaml";
|
||||||
|
import { Options } from "../interfaces/options.interface";
|
||||||
|
import { findUp } from "../utils/find-up";
|
||||||
|
import { BaseConfiguration } from "./base-configuration.interface";
|
||||||
|
|
||||||
|
const configKeyPrefix = "share/config";
|
||||||
|
const logger = debug("fennec:config:loader:etcd");
|
||||||
|
|
||||||
|
export async function readFileConfig<
|
||||||
|
T = BaseConfiguration
|
||||||
|
>({}: Options = {}): Promise<T> {
|
||||||
|
const path = await findUp(["config.yml", "config.yaml"], process.cwd());
|
||||||
|
try {
|
||||||
|
if (path) {
|
||||||
|
return readFile(path, "utf8").then((str) => load(str) as T);
|
||||||
|
} else {
|
||||||
|
throw new Error("No config file found");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("Can not parse file as yaml");
|
||||||
|
logger.log("File path: %s", path);
|
||||||
|
logger.log("%O", error);
|
||||||
|
throw new Error(`Failed to parse configuration at ${path}`);
|
||||||
|
}
|
||||||
|
}
|
15
src/config/index.ts
Normal file
15
src/config/index.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Options } from "../interfaces/options.interface";
|
||||||
|
import { readEtcdConfig } from "./etcd-config-reader";
|
||||||
|
import { readFileConfig } from "./file-config-reader";
|
||||||
|
|
||||||
|
export * from "./base-configuration.interface";
|
||||||
|
export * from "./etcd-config-reader";
|
||||||
|
export * from "./file-config-reader";
|
||||||
|
|
||||||
|
export function readConfiguration(option: Options) {
|
||||||
|
try {
|
||||||
|
return readEtcdConfig(option);
|
||||||
|
} catch (e) {
|
||||||
|
return readFileConfig(option);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { Etcd3 } from "etcd3";
|
import { Etcd3 } from "etcd3";
|
||||||
import { AppConfig } from "./app-config.model.js";
|
import { AppConfig } from "./app-config.model";
|
||||||
function connectEtcd(config?: AppConfig) {
|
function connectEtcd(config?: AppConfig) {
|
||||||
return new Etcd3({
|
return new Etcd3({
|
||||||
...(config?.etcd ?? { hosts: ["http://rpi:2379"] }),
|
...(config?.etcd ?? { hosts: ["http://rpi:2379"] }),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export * from "./app-config.model.js";
|
export * from "./app-config.model";
|
||||||
export * from "./config-loader.js";
|
export * from "./config-loader";
|
||||||
export * from "./etcd-connection.js";
|
export * from "./etcd-connection";
|
||||||
export * from "./service-register.js";
|
export * from "./service-register";
|
||||||
|
export * from "./config";
|
||||||
|
6
src/interfaces/options.interface.ts
Normal file
6
src/interfaces/options.interface.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { Etcd3, IOptions } from "etcd3";
|
||||||
|
export interface Options {
|
||||||
|
etcd: Etcd3 | IOptions;
|
||||||
|
appName?: string;
|
||||||
|
environment?: string;
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { AppConfig } from "./app-config.model.js";
|
import { AppConfig } from "./app-config.model";
|
||||||
import { Etcd3 } from "etcd3";
|
import { Etcd3 } from "etcd3";
|
||||||
import { hostname } from "os";
|
import { hostname } from "os";
|
||||||
import { getEtcdInstance } from "./etcd-connection.js";
|
import { getEtcdInstance } from "./etcd-connection";
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
|
|
||||||
export class ServiceRegister {
|
export class ServiceRegister {
|
||||||
|
18
src/utils/app-pkg.ts
Normal file
18
src/utils/app-pkg.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { readFile } from "fs/promises";
|
||||||
|
import { findUp } from "./find-up";
|
||||||
|
|
||||||
|
interface Pkg {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAppPkg<T = Pkg>(): Promise<T> {
|
||||||
|
return await findUp("package.json", process.cwd())
|
||||||
|
.then((path) => {
|
||||||
|
if (path) {
|
||||||
|
return readFile(path, "utf8");
|
||||||
|
} else {
|
||||||
|
throw new Error("Can't find package.json.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((str) => JSON.parse(str));
|
||||||
|
}
|
33
src/utils/find-up.ts
Normal file
33
src/utils/find-up.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import path from "path";
|
||||||
|
import fs from "fs/promises";
|
||||||
|
|
||||||
|
export const findUp = async (
|
||||||
|
filenameList: string[] | string,
|
||||||
|
from: string
|
||||||
|
): Promise<string | null> => {
|
||||||
|
if (!Array.isArray(filenameList)) {
|
||||||
|
filenameList = [filenameList];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const isDir = await fs.stat(from).then((stat) => stat.isDirectory());
|
||||||
|
if (!isDir) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const filename of filenameList) {
|
||||||
|
const filepath = path.resolve(from, filename);
|
||||||
|
if (
|
||||||
|
await fs
|
||||||
|
.stat(filepath)
|
||||||
|
.then((stat) => stat.isFile() || stat.isDirectory())
|
||||||
|
) {
|
||||||
|
return filepath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err.code === "ENOENT") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return findUp(filenameList, path.resolve(from, ".."));
|
||||||
|
};
|
@ -5,6 +5,5 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationDir": "./lib/types",
|
"declarationDir": "./lib/types",
|
||||||
"module": "node12",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user