diff --git a/src/bin/www b/src/bin/www index 837bedd..1de4006 100755 --- a/src/bin/www +++ b/src/bin/www @@ -9,6 +9,7 @@ const debug = require('debug')('ztncui:server'); const http = require('http'); const https = require('https'); const fs = require('fs'); +const storage = require('../controllers/storage'); /** * Get ports from environment and store in Express. @@ -36,33 +37,40 @@ app.set('https_host', https_host); * HTTPS_HOST HTTPS HTTPS_HOST HTTPS_PORT */ -const http_all_interfaces = process.env.HTTP_ALL_INTERFACES || null; -if (http_all_interfaces) { - console.log('Listening for HTTP requests on port ' + http_port + ' on all interfaces'); - app.listen(http_port); -} else { - console.log('Listening for HTTP requests on port ' + http_port + ' on localhost'); - app.listen(http_port, 'localhost'); -} - const options = !https_port ? {} : { cert: fs.readFileSync('etc/tls/fullchain.pem'), key: fs.readFileSync('etc/tls/privkey.pem') }; -const server = https.createServer(options, app); +const https_server = https.createServer(options, app); -if (https_port) { - if (https_host) { - console.log('Listening for HTTPS requests on port ' + https_port + ' on address ' + https_host); +async function start() { + await storage.init(); + + const http_all_interfaces = process.env.HTTP_ALL_INTERFACES || null; + if (http_all_interfaces) { + console.log('Listening for HTTP requests on port ' + http_port + ' on all interfaces'); + app.listen(http_port); } else { - console.log('Listening for HTTPS requests on port ' + https_port + ' on all interfaces'); + console.log('Listening for HTTP requests on port ' + http_port + ' on localhost'); + app.listen(http_port, 'localhost'); } - server.listen(https_port, https_host); + + if (https_port) { + if (https_host) { + console.log('Listening for HTTPS requests on port ' + https_port + ' on address ' + https_host); + } else { + console.log('Listening for HTTPS requests on port ' + https_port + ' on all interfaces'); + } + https_server.listen(https_port, https_host); + } + + https_server.on('error', onError); + https_server.on('listening', onListening); } -server.on('error', onError); -server.on('listening', onListening); +start(); + /** * Normalize a port into a number, string, or false. @@ -121,7 +129,7 @@ function onError(error) { */ function onListening() { - const addr = server.address(); + const addr = https_server.address(); const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; diff --git a/src/controllers/networkController.js b/src/controllers/networkController.js index c42abba..c5a25dd 100644 --- a/src/controllers/networkController.js +++ b/src/controllers/networkController.js @@ -6,11 +6,10 @@ const fs = require('fs'); const ipaddr = require('ip-address'); -const storage = require('node-persist'); +const storage = require('./storage'); const zt = require('./zt'); const util = require('util'); -storage.initSync({dir: 'etc/storage'}); async function get_network_with_members(nwid) { const [network, peers, members] = await Promise.all([ @@ -22,11 +21,11 @@ async function get_network_with_members(nwid) { Object.keys(member_ids) .map(id => Promise.all([ zt.member_detail(nwid, id), - storage.getItem(id) + storage.get_member(id) ])) ) - ).then(results => results.map(([member, name]) => { - member.name = name || ''; + ).then(results => results.map(([member, {name}]) => { + member.name = name; return member; })) ]); @@ -37,13 +36,13 @@ async function get_network_with_members(nwid) { } async function get_network_member(nwid, memberid) { - const [network, member, peer, name] = await Promise.all([ + const [network, member, peer, {name}] = await Promise.all([ zt.network_detail(nwid), zt.member_detail(nwid, memberid), zt.peer(memberid), - storage.getItem(memberid) + storage.get_member(memberid) ]); - member.name = name || ''; + member.name = name; member.peer = peer; return {network, member}; } @@ -677,7 +676,9 @@ exports.members = async function(req, res) { if (!errors) { try { - const ret = await storage.setItem(req.body.id, req.body.name); + const member = await storage.get_member(req.body.id); + member.name = req.body.name; + await storage.set_member(req.body.id, member); } catch (err) { throw err; } @@ -697,17 +698,16 @@ exports.member_delete = async function(req, res) { try { const network = await zt.network_detail(req.params.nwid); let member = null; - let name = null; + let { name } = await storage.get_member(req.params.id); if (req.method === 'POST') { member = await zt.member_delete(req.params.nwid, req.params.id); if (member.deleted) { - name = await storage.removeItem(member.id); + await storage.delete_member(member.id); } } else { member = await zt.member_detail(req.params.nwid, req.params.id); - name = await storage.getItem(member.id); } - member.name = name || ''; + member.name = name; navigate.whence = '/controller/network/' + network.nwid; res.render('member_delete', {title: 'Delete member from ' + network.name, @@ -731,7 +731,7 @@ exports.delete_ip = async function(req, res) { const network = await zt.network_detail(req.params.nwid); let member = await zt.member_detail(req.params.nwid, req.params.id); navigate.whence = '/controller/network/' + network.nwid; - member.name = await storage.getItem(member.id) | ''; + member.name = (await storage.get_member(member.id)).name; if (req.params.index) { member = await zt.ipAssignmentDelete(network.nwid, member.id, req.params.index); @@ -795,7 +795,7 @@ exports.assign_ip = async function(req, res) { member = await zt.ipAssignmentAdd(network.nwid, member.id, ipAssignment); } - member.name = await storage.getItem(member.id) | ''; + member.name = (await storage.get_member(member.id)).name; res.render('ipAssignments', {title: 'ipAssignments', navigate: navigate, ipAssignment: ipAssignment, network: network, member: member, diff --git a/src/controllers/storage.js b/src/controllers/storage.js new file mode 100644 index 0000000..1e07d55 --- /dev/null +++ b/src/controllers/storage.js @@ -0,0 +1,89 @@ +const storage = require('node-persist').create(); + +/** + * @typedef {{ name: string, description: string }} MemberInfo + * @typedef {{ rulesSource: string, description: string }} NetworkInfo + */ + +async function init() { + const v1 = require('node-persist').create(); + await v1.init({ dir: 'etc/storage' }); + await storage.init({ dir: 'etc/storage-v2' }); + const version = await v1.getItem('version'); + let newVersion = version; + + if (newVersion === undefined) { + const data = []; + await v1.forEach((key, value) => { + data.push({ key, value }); + }); + for (const { key, value } of data) { + await storage.setItem('member-' + key, { name: value }); + } + newVersion = 2; + await v1.setItem('version', newVersion); + } + + if (newVersion != version) { + console.info(`Storage version changed: ${version} -> ${newVersion}`); + } +} +exports.init = init; + + +exports.set_member = set_member; +/** + * @param {string} id + * @param {MemberInfo} member + */ +async function set_member(id, member) { + await storage.setItem('member-' + id, member); +} + + +exports.get_member = get_member; +/** + * @param {string} id + * @returns {Promise} + */ +async function get_member(id) { + /** @type {MemberInfo} */ + const member = await storage.getItem('member-' + id) || {}; + if (!member.name) member.name = ''; + if (!member.description) member.description = ''; +} + + +exports.delete_member = delete_member; +async function delete_member(id) { + await storage.removeItem('member-' + id); +} + + +exports.set_network = set_network; +/** + * @param {string} id + * @param {NetworkInfo} network + */ +async function set_network(id, network) { + await storage.setItem('network-' + id, network); +} + + +exports.get_network = get_network; +/** + * @param {string} id + * @returns {Promise} + */ +async function get_network(id) { + /** @type {NetworkInfo} */ + const network = await storage.getItem('network-' + id) || {}; + if (!network.rulesSource) network.rulesSource = ''; + if (!network.description) network.description = ''; +} + + +exports.delete_network = delete_network; +async function delete_network(id) { + await storage.removeItem('network-' + id); +}