feat: configuration loader.
This commit is contained in:
parent
e4c6718e43
commit
a02bc282bb
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"nodenext"
|
||||
]
|
||||
}
|
12
examples/config-loader.ts
Normal file
12
examples/config-loader.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { ConfigLoader } from "../src/config-loader.js";
|
||||
|
||||
const loader = new ConfigLoader();
|
||||
|
||||
loader
|
||||
.loadConfig()
|
||||
.then((config) => {
|
||||
console.log("config", config);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import { AppConfig, ServiceRegister } from "../src";
|
||||
import { AppConfig, ServiceRegister } from "../src/index.js.js";
|
||||
|
||||
const config: AppConfig = {
|
||||
etcd: {
|
||||
|
144
package-lock.json
generated
144
package-lock.json
generated
@ -1,16 +1,17 @@
|
||||
{
|
||||
"name": "configuration",
|
||||
"version": "1.0.0",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "configuration",
|
||||
"version": "1.0.0",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.2",
|
||||
"etcd3": "^1.1.0",
|
||||
"find-up": "^6.1.0",
|
||||
"js-yaml": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -20,7 +21,7 @@
|
||||
"@types/node": "^14.17.17",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.4.3"
|
||||
"typescript": "^4.5.0-beta"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-consumer": {
|
||||
@ -324,6 +325,22 @@
|
||||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://npm.ivanli.cc/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@ -382,6 +399,21 @@
|
||||
"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": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://npm.ivanli.cc/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
@ -430,6 +462,45 @@
|
||||
"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": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://npm.ivanli.cc/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
@ -528,9 +599,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.4.3.tgz",
|
||||
"integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
|
||||
"version": "4.5.0-beta",
|
||||
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.5.0-beta.tgz",
|
||||
"integrity": "sha512-7PvWhki2lwukaR9osVhFnNzxaE4LM+gC94dlwcvS+Tqz8+U65va7FbKo02bT+/MFlnMPM8bsPUXvHiMD/Mg3Jg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@ -557,6 +628,18 @@
|
||||
"engines": {
|
||||
"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": {
|
||||
@ -787,6 +870,15 @@
|
||||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://npm.ivanli.cc/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@ -831,6 +923,14 @@
|
||||
"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": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://npm.ivanli.cc/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
@ -870,6 +970,27 @@
|
||||
"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": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://npm.ivanli.cc/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
@ -926,9 +1047,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.4.3.tgz",
|
||||
"integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
|
||||
"version": "4.5.0-beta",
|
||||
"resolved": "https://npm.ivanli.cc/typescript/-/typescript-4.5.0-beta.tgz",
|
||||
"integrity": "sha512-7PvWhki2lwukaR9osVhFnNzxaE4LM+gC94dlwcvS+Tqz8+U65va7FbKo02bT+/MFlnMPM8bsPUXvHiMD/Mg3Jg==",
|
||||
"dev": true
|
||||
},
|
||||
"wrappy": {
|
||||
@ -942,6 +1063,11 @@
|
||||
"resolved": "https://npm.ivanli.cc/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,12 @@
|
||||
"description": "Fennec configuration loader and share info.",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf lib",
|
||||
"build": "tsc -p \"tsconfig.build.json\"",
|
||||
"start:example-register": "DEBUG=* ts-node ./examples/register.ts",
|
||||
"start:example-config-loader": "DEBUG=* node --loader ts-node/esm ./examples/config-loader.ts",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
@ -23,7 +25,9 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.2",
|
||||
"esm": "^3.2.25",
|
||||
"etcd3": "^1.1.0",
|
||||
"find-up": "^6.1.0",
|
||||
"js-yaml": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -33,6 +37,6 @@
|
||||
"@types/node": "^14.17.17",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.4.3"
|
||||
"typescript": "^4.5.0-beta"
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,68 @@
|
||||
import { AppConfig } from "./app-config.model";
|
||||
import { debug } from "console";
|
||||
import { AppConfig } from "./app-config.model.js";
|
||||
import { Etcd3 } from "etcd3";
|
||||
import { load } from "js-yaml";
|
||||
import { hostname } from "os";
|
||||
import { getEtcdInstance } from "./etcd-connection";
|
||||
import { getEtcdInstance } from "./etcd-connection.js";
|
||||
import { readFile } from "fs/promises";
|
||||
import debug from "debug";
|
||||
|
||||
class ConfigLoader {
|
||||
export class ConfigLoader {
|
||||
private etcd: Etcd3;
|
||||
|
||||
private readonly currHost = hostname();
|
||||
private readonly configKeyPrefix = "share/config";
|
||||
private readonly logger = debug("fennec:config:loader");
|
||||
|
||||
constructor(config: AppConfig) {
|
||||
constructor(config?: AppConfig) {
|
||||
this.etcd = getEtcdInstance(config);
|
||||
}
|
||||
|
||||
async loadConfig(configKey: string): Promise<any> {
|
||||
const str = await this.etcd
|
||||
.get(`${this.configKeyPrefix}/${this.currHost}/${configKey}`)
|
||||
.string();
|
||||
async loadConfig<T extends Object>(configKey?: string): Promise<any> {
|
||||
const config = await (await import("find-up"))
|
||||
.findUp(["config,yml", "config.yaml"])
|
||||
.then((path) => {
|
||||
if (path) {
|
||||
return readFile(path, "utf8").then((str) => load(str));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
if (!str) {
|
||||
debug("config-loader", `No config found for ${configKey}`);
|
||||
return null;
|
||||
if (configKey === undefined) {
|
||||
if (process.env.CONFIG_KEY) {
|
||||
configKey = process.env.CONFIG_KEY;
|
||||
} else if (process.env.config_key) {
|
||||
configKey = process.env.config_key;
|
||||
} else {
|
||||
configKey = await (
|
||||
await import("find-up")
|
||||
)
|
||||
.findUp("package.json")
|
||||
.then((path) => {
|
||||
if (path) {
|
||||
return readFile(path, "utf8");
|
||||
} else {
|
||||
throw new Error(
|
||||
"Fallback to using package name as configuration name"
|
||||
);
|
||||
}
|
||||
return load(str);
|
||||
})
|
||||
.then((json) => JSON.parse(json)?.name as string);
|
||||
}
|
||||
}
|
||||
const etcdConfigKey = `${this.configKeyPrefix}/${this.currHost}/${configKey}`;
|
||||
const str = await this.etcd.get(etcdConfigKey).string();
|
||||
|
||||
if (!str || !config) {
|
||||
this.logger(
|
||||
`Not define configuration.
|
||||
- Put configuration in %s
|
||||
- Provide configuration key in CONFIG_KEY environment variable
|
||||
- Create "config.yml" file in current working directory (CWD)`,
|
||||
etcdConfigKey
|
||||
);
|
||||
throw new Error(`Not define configuration.`);
|
||||
}
|
||||
return Object.assign(config, load(str)) as T;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { Etcd3 } from "etcd3";
|
||||
import { AppConfig } from "./app-config.model";
|
||||
function connectEtcd(config: AppConfig) {
|
||||
import { AppConfig } from "./app-config.model.js";
|
||||
function connectEtcd(config?: AppConfig) {
|
||||
return new Etcd3({
|
||||
...config.etcd,
|
||||
...(config?.etcd ?? { hosts: ["http://rpi:2379"] }),
|
||||
});
|
||||
}
|
||||
|
||||
let instance: Etcd3;
|
||||
|
||||
export function getEtcdInstance(config: AppConfig) {
|
||||
export function getEtcdInstance(config?: AppConfig) {
|
||||
if (!instance) {
|
||||
instance = connectEtcd(config);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from "./app-config.model";
|
||||
export * from "./config-loader";
|
||||
export * from "./etcd-connection";
|
||||
export * from "./service-register";
|
||||
export * from "./app-config.model.js";
|
||||
export * from "./config-loader.js";
|
||||
export * from "./etcd-connection.js";
|
||||
export * from "./service-register.js";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { AppConfig } from "./app-config.model";
|
||||
import { AppConfig } from "./app-config.model.js";
|
||||
import { Etcd3 } from "etcd3";
|
||||
import { hostname } from "os";
|
||||
import { getEtcdInstance } from "./etcd-connection";
|
||||
import { getEtcdInstance } from "./etcd-connection.js";
|
||||
import debug from "debug";
|
||||
|
||||
export class ServiceRegister {
|
||||
@ -12,7 +12,7 @@ export class ServiceRegister {
|
||||
|
||||
private readonly logger = debug("fennec:config:register");
|
||||
|
||||
constructor(config: AppConfig) {
|
||||
constructor(config?: AppConfig) {
|
||||
this.etcd = getEtcdInstance(config);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
"outDir": "./lib",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"declarationDir": "./lib/types"
|
||||
}
|
||||
"declarationDir": "./lib/types",
|
||||
"module": "node12",
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user