使用node.js下的zookeeper客户端访问组件库,写一个 web的控制台,非常简单。比起java的ZooInspector,还有其他一些node下的zk的web控制台,有哪些优势?轻量,部署依赖少,可以单机,可以扔在服务器上多用户访问;依赖少,早起一些node下的zk的控制台,使用了node-zookeeper,这是是一个包装c实现库;这里使用了node-zookeeper-client库,这是一个纯js的zk客户端组件库,更为轻量。
环境安装,库安装略过;
app.js
const express = require('express')
const bodyParser = require('body-parser')
const api = require('./src/api')
const port = 8123
app = express()
app.use(bodyParser.json({
limit: '50mb'}))
app.use(express.static('public'))
app.use('/api', api)
app.listen(port, '127.0.0.1', () => console.log(`Server running: http://localhost:${
port}`))
const express = require('express')
const zookeeper = require('node-zookeeper-client')
const Long = require('long')
const router = express.Router()
let zkConnections = {
};
router.post('/zk', async (req, res) => {
switch(req.body.act){
case 'connect': {
let client = await zkClient(req.body.address)
zkListChildren(client, '/', res)
break
}
case 'list': {
let client = await zkClient(req.body.address)
zkListChildren(client, req.body.path, res)
break
}
case 'getData': {
let client = await zkClient(req.body.address)
zkGetData(client, req.body.path, res)
break
}
case 'addNode': {
let client = await zkClient(req.body.address)
zkAddNode(client, req.body.path, res)
break
}
case 'removeNode': {
let client = await zkClient(req.body.address)
zkRemoveNode(client, req.body.path, res)
break
}
case 'setData':
let client = await zkClient(req.body.address)
zkSetData(client, req.body.path, req.body.data, res)
break
default:
res.send('')
}
})
async function zkClient(address){
let client = zkConnections[address]
if(client){
let state = client.getState()
if(state === zookeeper.State.SYNC_CONNECTED){
return Promise.resolve(client)
}else{
client.close()
delete zkConnections[address]
return await zkClient(address)
}
}else{
client = zookeeper.createClient(address)
zkConnections[address] = client
console.log('new connetion: %s', address)
client.connect()
client.on('state', state => {
console.log(state)
})
return new Promise((resolve, reject) => {
client.once('connected', ()=>{
resolve(client)
})
})
}
}
function zkGetData(client, path, res) {
client.getData(path, (err, data, stat) => {
if(err){
console.log('%s', err)
}
let s = {
}
stat.specification.forEach(i => {
s[i.name] = i.type === 'long' ? Long.fromBytes(stat[i.name]).toString() : stat[i.name]
});
res.send({
data: (data && data.length > 0) ? data.toString('utf8') : '', stat: s})
})
}
function zkListChildren(client, path, res) {
client.getChildren(path, (err, children, stat) => {
if(err){
console.log('%s', err)
}
res.send(children)
})
}
function zkRemoveNode(client, path, res) {
client.remove(path, -1, (err)=>{
if(err){
console.log('%s', err)
res.send('fail')
}else{
res.send('success')
}
})
}
function zkAddNode(client, path, res){
client.create(path, null, null, zookeeper.CreateMode.PERSISTENT, (err) =>{
if(err){
console.log('%s', err)
res.send('fail')
}else{
res.send('success')
}
})
}
function zkSetData(client, path, data, res){
client.setData(path, Buffer.from(data), -1, (error, stat) => {
if (error) {
console.log(error.stack);
res.send('fail')
}else{
res.send('success')
}
})
}
module.exports = router
这里vue使用简单的方式,可以参考不使用Webpack的Vue传统前端使用方式(一)。
说说主要的几个点。
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js" integrity="sha256-ngFW3UnAN0Tnm76mDuu7uUtYEcG3G5H1+zioJw3t+68=" crossorigin="anonymous">script>
使用了以下前端组件:
这个方法可以实现使用js加载js到html中,而且是同步的;
async function loadjs(src) {
if(src instanceof Array){
return Promise.all(src.map(i => loadjs(i)))
}
let script = document.createElement('script')
script.setAttribute('type', 'text/javascript')
script.src = src;
document.getElementsByTagName('body')[0].appendChild(script)
return new Promise(resolve => {
script.onload = () => {
return resolve('ok')
}
})
}
用法:
await loadjs([
'js/vue_com.js',
'js/vue_zk.js'
])
Vue.component('tree', {
template: `
`,
props: ['nodes', 'show'],
data(){
return {
}
},
methods:{
loadAndToggleExpand(node){
if(node.show === null){
this.$emit('load', node)
}else{
node.show = !node.show
}
},
nodeClick(e, node){
this.$emit('nodeClick', node)
},
childNodeClick(node){
this.$emit('nodeClick', node)
},
childNodeLoad(node){
this.$emit('load', node)
}
}
});
详细代码不贴了,可以直接访问仓库: https://github.com/ccor/zk-browser
主界面主要是左侧树形目录,右侧的数据显示和操作区;
主要实现了经典的程序员的四门功课:增删改查。一般来说,基本够用了。