traefik-key-mgr/index.js

155 lines
3.2 KiB
JavaScript

const Redis = require('ioredis')
const commander = require('commander')
const fs = require('fs')
const yaml = require('yaml')
function isNumeric (v) {
return isFinite(v) && v !== null && v !== false && v !== true
}
/**
* @param {any} obj
* @param {string[]} keys
* @param {any} value
*/
function setKey (obj, keys, value) {
const key = isNumeric(keys[0]) ? parseInt(keys[0], 10) : keys[0]
if (keys.length === 1) {
obj[key] = value
return
}
if (!(key in obj)) {
if (isNumeric(keys[1])) {
obj[key] = []
} else {
obj[key] = {}
}
}
setKey(obj[key], keys.slice(1), value)
}
/**
* @param {string} file
* @return {boolean}
*/
async function checkFileExists (file) {
if (!file) return false
try {
await fs.promises.access(file, fs.constants.W_OK || fs.constants.R_OK)
} catch (err) {
console.log(err)
return false
}
return true
}
function getRedis () {
const { port, host } = commander
const redis = new Redis(port || 6379, host || 'localhost')
return redis
}
function generateFromStruct (obj, prefix = '') {
const kvs = []
if (Object.keys(obj).length === 0) return kvs
for (const k in obj) {
const key = !prefix ? k : [prefix, k].join('/')
if (typeof obj[k] === 'object') {
kvs.push(...generateFromStruct(obj[k], key))
} else {
kvs.push({ key, value: `${obj[k]}` })
}
}
return kvs
}
async function importData () {
const { file } = commander
if (!await checkFileExists(file)) throw new Error(`check file (${file}) fail`)
const redis = getRedis()
const str = await fs.promises.readFile(file, 'utf8')
const obj = yaml.parse(str)
const kvs = generateFromStruct(obj)
try {
// clean redis
await redis.flushdb()
for (const o of kvs) {
console.log(`set: ${o.key} => ${o.value}`)
await redis.set(o.key, o.value)
}
} finally {
await redis.disconnect()
}
}
async function exportData () {
const { file } = commander
const redis = getRedis()
const obj = {}
try {
let cursor = ''
while (cursor !== '0') {
const result = await redis.scan(cursor || '0')
console.log(result)
cursor = result[0]
for (const k of result[1]) {
const str = await redis.get(k)
if (!str) continue
setKey(obj, k.split('/'), str)
}
}
await fs.promises.writeFile(file, yaml.stringify(obj))
} finally {
await redis.disconnect()
}
}
commander.option('-r, --run <module>', 'run tool module [import, export]')
.option('-p, --port [port]', 'redis server port default: 6379')
.option('-h, --host [host]', 'redis host addr default: localhost')
.option('-f, --file <file path>', 'yaml config path')
.parse(process.argv)
; (async () => {
const { run, port, host, file } = commander
console.log(run, port, host, file)
switch (run) {
case 'import':
await importData()
break
case 'export':
await exportData()
break
default:
throw new Error('run module not support')
}
// for (const key in json) {
// const strs = key.split('/')
// setKey(obj, strs, json[key])
// }
// // console.log(yaml.stringify(obj))
// await fs.promises.writeFile('store.yml', yaml.stringify(obj))
})().then(console.log).catch(console.log)