diff --git a/app.js b/app.js index d8ce3a0d..1bb461a1 100644 --- a/app.js +++ b/app.js @@ -28,6 +28,8 @@ const switchRoutes = require("./routes/lnd/switch"); const infoCLRoutes = require("./routes/c-lightning/getInfo"); const feesCLRoutes = require("./routes/c-lightning/fees"); +const balanceCLRoutes = require("./routes/c-lightning/balance"); +const channelsCLRoutes = require("./routes/c-lightning/channels"); app.use(cookieParser(common.secret_key)); app.use(bodyParser.json()); @@ -68,6 +70,8 @@ app.use(apiLNDRoot + "switch", switchRoutes); app.use(apiCLRoot + "getinfo", infoCLRoutes); app.use(apiCLRoot + "fees", feesCLRoutes); +app.use(apiCLRoot + "balance", balanceCLRoutes); +app.use(apiCLRoot + "channels", channelsCLRoutes); app.use((req, res, next) => { res.sendFile(path.join(__dirname, "angular", "index.html")); diff --git a/common.js b/common.js index 711d966a..b9c6dd48 100644 --- a/common.js +++ b/common.js @@ -15,8 +15,8 @@ common.secret_key = crypto.randomBytes(64).toString('hex'); common.nodes = []; common.selectedNode = {}; -common.getSelLNDServerUrl = () => { - return common.selectedNode.lnd_server_url; +common.getSelLNServerUrl = () => { + return common.selectedNode.ln_server_url; }; common.getOptions = () => { diff --git a/connect.js b/connect.js index d56373d1..d36ba25f 100644 --- a/connect.js +++ b/connect.js @@ -17,30 +17,30 @@ common.path_separator = (platform === 'win32') ? '\\' : '/'; connect.setDefaultConfig = () => { var homeDir = os.userInfo().homedir; var macaroonPath = ''; - var lndConfigPath = ''; + var configPath = ''; switch (platform) { case 'win32': macaroonPath = homeDir + '\\AppData\\Local\\Lnd\\data\\chain\\bitcoin\\mainnet'; - lndConfigPath = homeDir + '\\AppData\\Local\\Lnd\\lnd.conf'; + configPath = homeDir + '\\AppData\\Local\\Lnd\\lnd.conf'; break; case 'darwin': macaroonPath = homeDir + '/Library/Application Support/Lnd/data/chain/bitcoin/mainnet'; - lndConfigPath = homeDir + '/Library/Application Support/Lnd/lnd.conf'; + configPath = homeDir + '/Library/Application Support/Lnd/lnd.conf'; break; case 'linux': macaroonPath = homeDir + '/.lnd/data/chain/bitcoin/mainnet'; - lndConfigPath = homeDir + '/.lnd/lnd.conf'; + configPath = homeDir + '/.lnd/lnd.conf'; break; default: macaroonPath = ''; - lndConfigPath = ''; + configPath = ''; break; } return { Authentication: { macaroonPath: macaroonPath, nodeAuthType: 'DEFAULT', - lndConfigPath: lndConfigPath, + configPath: configPath, rtlPass: '' }, Settings: { @@ -51,7 +51,7 @@ connect.setDefaultConfig = () => { theme: 'dark-blue', satsToBTC: false, channelBackupPath: homeDir + common.path_separator + 'backup' + common.path_separator + 'node-0', - lndServerUrl: 'https://localhost:8080/v1', + lnServerUrl: 'https://localhost:8080/v1', enableLogging: false, port: 3000 }, @@ -129,15 +129,23 @@ connect.validateSingleNodeConfig = (config) => { } if(undefined !== process.env.LND_SERVER_URL) { - common.nodes[0].lnd_server_url = process.env.LND_SERVER_URL; + common.nodes[0].ln_server_url = process.env.LND_SERVER_URL; + } else if(undefined !== process.env.LN_SERVER_URL) { + common.nodes[0].ln_server_url = process.env.LN_SERVER_URL; } else { - if((config.Authentication.lndServerUrl === '' || undefined === config.Authentication.lndServerUrl) && (config.Settings.lndServerUrl === '' || undefined === config.Settings.lndServerUrl)) { - errMsg = errMsg + '\nPlease set LND Server URL through environment or RTL.conf!'; + if( + (config.Authentication.lndServerUrl === '' || undefined === config.Authentication.lndServerUrl) + && (config.Settings.lndServerUrl === '' || undefined === config.Settings.lndServerUrl) + && (config.Settings.lnServerUrl === '' || undefined === config.Settings.lnServerUrl) + ) { + errMsg = errMsg + '\nPlease set Server URL through environment or RTL.conf!'; } else { if (config.Settings.lndServerUrl !== '' && undefined !== config.Settings.lndServerUrl) { - common.nodes[0].lnd_server_url = config.Settings.lndServerUrl; + common.nodes[0].ln_server_url = config.Settings.lndServerUrl; } else if (config.Authentication.lndServerUrl !== '' && undefined !== config.Authentication.lndServerUrl) { - common.nodes[0].lnd_server_url = config.Authentication.lndServerUrl; + common.nodes[0].ln_server_url = config.Authentication.lndServerUrl; + } else if (config.Settings.lnServerUrl !== '' && undefined !== config.Settings.lnServerUrl) { + common.nodes[0].ln_server_url = config.Settings.lnServerUrl; } } } @@ -153,10 +161,14 @@ connect.validateSingleNodeConfig = (config) => { } if(undefined !== process.env.LND_CONFIG_PATH) { - common.nodes[0].lnd_config_path = process.env.LND_CONFIG_PATH; + common.nodes[0].config_path = process.env.LND_CONFIG_PATH; + } else if (undefined !== process.env.CONFIG_PATH) { + common.nodes[0].config_path = process.env.CONFIG_PATH; } else { if(config.Authentication.lndConfigPath !== '' && undefined !== config.Authentication.lndConfigPath) { - common.nodes[0].lnd_config_path = config.Authentication.lndConfigPath; + common.nodes[0].config_path = config.Authentication.lndConfigPath; + } else if(config.Authentication.ConfigPath !== '' && undefined !== config.Authentication.ConfigPath) { + common.nodes[0].config_path = config.Authentication.ConfigPath; } else { if(upperCase(common.node_auth_type) === 'DEFAULT') { errMsg = errMsg + '\nDefault Node Authentication can be set with LND Config Path only. Please set LND Config Path through environment or RTL.conf!'; @@ -268,16 +280,25 @@ connect.validateMultiNodeConfig = (config) => { common.nodes[idx].macaroon_path = node.Authentication.macaroonPath; } - if((node.Settings.lndServerUrl === '' || undefined === node.Settings.lndServerUrl)) { - errMsg = errMsg + '\nPlease set LND server URL for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!'; + if( + (node.Settings.lndServerUrl === '' || undefined === node.Settings.lndServerUrl) + && (node.Settings.lnServerUrl === '' || undefined === node.Settings.lnServerUrl) + ) { + errMsg = errMsg + '\nPlease set server URL for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!'; } else { - common.nodes[idx].lnd_server_url = node.Settings.lndServerUrl; + common.nodes[idx].ln_server_url = node.Settings.lndServerUrl ? node.Settings.lndServerUrl : node.Settings.lnServerUrl; } common.nodes[idx].index = node.index; common.nodes[idx].ln_node = node.lnNode; common.nodes[idx].ln_implementation = node.lnImplementation; - common.nodes[idx].lnd_config_path = (undefined !== node.Authentication && undefined !== node.Authentication.lndConfigPath) ? node.Authentication.lndConfigPath : ''; + if (undefined !== node.Authentication && undefined !== node.Authentication.lndConfigPath) { + common.nodes[idx].config_path = node.Authentication.lndConfigPath; + } else if (undefined !== node.Authentication && undefined !== node.Authentication.configPath) { + common.nodes[idx].config_path = node.Authentication.configPath; + } else { + common.nodes[idx].config_path = ''; + } common.nodes[idx].bitcoind_config_path = (undefined !== node.Settings.bitcoindConfigPath) ? node.Settings.bitcoindConfigPath : ''; common.nodes[idx].enable_logging = (undefined !== node.Settings.enableLogging) ? node.Settings.enableLogging : false; common.nodes[idx].channel_backup_path = (undefined !== node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : common.rtl_conf_file_path + common.path_separator + 'backup' + common.path_separator + 'node-' + node.index; @@ -408,9 +429,9 @@ connect.logEnvVariables = () => { logger.info({fileName: 'Config Setup Variable', msg: 'LN IMPLEMENTATION: ' + node.ln_implementation, node}); logger.info({fileName: 'Config Setup Variable', msg: 'PORT: ' + common.port, node}); logger.info({fileName: 'Config Setup Variable', msg: 'MACAROON_PATH: ' + node.macaroon_path, node}); - logger.info({fileName: 'Config Setup Variable', msg: 'LND_SERVER_URL: ' + node.lnd_server_url, node}); + logger.info({fileName: 'Config Setup Variable', msg: 'LND_SERVER_URL: ' + node.ln_server_url, node}); logger.info({fileName: 'Config Setup Variable', msg: 'RTL_CONFIG_PATH: ' + node.rtl_conf_file_path, node}); - logger.info({fileName: 'Config Setup Variable', msg: 'LND_CONFIG_PATH: ' + node.lnd_config_path, node}); + logger.info({fileName: 'Config Setup Variable', msg: 'CONFIG_PATH: ' + node.config_path, node}); logger.info({fileName: 'Config Setup Variable', msg: 'BITCOIND_CONFIG_PATH: ' + node.bitcoind_config_path, node}); logger.info({fileName: 'Config Setup Variable', msg: 'CHANNEL_BACKUP_PATH: ' + node.channel_backup_path, node}); }); @@ -418,10 +439,10 @@ connect.logEnvVariables = () => { if (!common.nodes[0].enable_logging) { return; } logger.info({fileName: 'Config Setup Variable', msg: 'NODE_SETUP: SINGLE'}); logger.info({fileName: 'Config Setup Variable', msg: 'PORT: ' + common.port}); - logger.info({fileName: 'Config Setup Variable', msg: 'LND_SERVER_URL: ' + common.nodes[0].lnd_server_url}); + logger.info({fileName: 'Config Setup Variable', msg: 'LND_SERVER_URL: ' + common.nodes[0].ln_server_url}); logger.info({fileName: 'Config Setup Variable', msg: 'MACAROON_PATH: ' + common.nodes[0].macaroon_path}); logger.info({fileName: 'Config Setup Variable', msg: 'NODE_AUTH_TYPE: ' + common.node_auth_type}); - logger.info({fileName: 'Config Setup Variable', msg: 'LND_CONFIG_PATH: ' + common.nodes[0].lnd_config_path}); + logger.info({fileName: 'Config Setup Variable', msg: 'CONFIG_PATH: ' + common.nodes[0].config_path}); logger.info({fileName: 'Config Setup Variable', msg: 'RTL_CONFIG_PATH: ' + common.rtl_conf_file_path}); logger.info({fileName: 'Config Setup Variable', msg: 'BITCOIND_CONFIG_PATH: ' + common.nodes[0].bitcoind_config_path}); logger.info({fileName: 'Config Setup Variable', msg: 'CHANNEL_BACKUP_PATH: ' + common.nodes[0].channel_backup_path}); @@ -434,7 +455,7 @@ connect.logEnvVariables = () => { connect.getAllNodeAllChannelBackup = (node) => { let channel_backup_file = node.channel_backup_path + common.path_separator + 'channel-all.bak'; let options = { - url: node.lnd_server_url + '/channels/backup', + url: node.ln_server_url + '/channels/backup', rejectUnauthorized: false, json: true, headers: {'Grpc-Metadata-macaroon': fs.readFileSync(node.macaroon_path + '/admin.macaroon').toString('hex')} diff --git a/controllers/RTLConf.js b/controllers/RTLConf.js index 25b45a60..dc32ad58 100644 --- a/controllers/RTLConf.js +++ b/controllers/RTLConf.js @@ -26,7 +26,7 @@ exports.getRTLConfig = (req, res, next) => { const sso = { rtlSSO: common.rtl_sso, logoutRedirectLink: common.logout_redirect_link }; const authentication = { nodeAuthType: common.node_auth_type, - lndConfigPath: common.nodes[0].lnd_config_path, + configPath: common.nodes[0].config_path, bitcoindConfigPath: common.nodes[0].bitcoind_config_path }; jsonConfig.Settings.channelBackupPath = (undefined !== jsonConfig.Settings.channelBackupPath) ? jsonConfig.Settings.channelBackupPath : common.nodes[0].channel_backup_path; @@ -61,8 +61,13 @@ exports.getRTLConfig = (req, res, next) => { const authentication = {}; authentication.nodeAuthType = 'CUSTOM'; if(node.Authentication && node.Authentication.lndConfigPath) { - authentication.lndConfigPath = node.Authentication.lndConfigPath; + authentication.configPath = node.Authentication.lndConfigPath; + } else if(node.Authentication && node.Authentication.configPath) { + authentication.configPath = node.Authentication.configPath; + } else { + authentication.configPath = ''; } + if(node.Settings.bitcoindConfigPath) { authentication.bitcoindConfigPath = node.Settings.bitcoindConfigPath; } @@ -138,9 +143,9 @@ exports.getConfig = (req, res, next) => { let confFile = ''; let JSONFormat = false; switch (req.params.nodeType) { - case 'lnd': + case 'ln': JSONFormat = false; - confFile = common.selectedNode.lnd_config_path; + confFile = common.selectedNode.config_path; break; case 'bitcoind': JSONFormat = false; diff --git a/controllers/authenticate.js b/controllers/authenticate.js index ba2e2fbb..86fbc195 100644 --- a/controllers/authenticate.js +++ b/controllers/authenticate.js @@ -13,7 +13,7 @@ exports.authenticateUser = (req, res, next) => { if (crypto.createHash('sha256').update(common.cookie).digest('hex') === req.body.password) { connect.refreshCookie(common.rtl_cookie_path); const token = jwt.sign( - { user: 'Custom_User', lndConfigPath: common.nodes[0].lnd_config_path, macaroonPath: common.nodes[0].macaroon_path }, + { user: 'Custom_User', configPath: common.nodes[0].config_path, macaroonPath: common.nodes[0].macaroon_path }, common.secret_key ); res.status(200).json({ token: token }); @@ -30,7 +30,7 @@ exports.authenticateUser = (req, res, next) => { if (common.rtl_pass === password) { var rpcUser = 'Multi_Node_User'; const token = jwt.sign( - { user: rpcUser, lndConfigPath: common.nodes[0].lnd_config_path, macaroonPath: common.nodes[0].macaroon_path }, + { user: rpcUser, configPath: common.nodes[0].config_path, macaroonPath: common.nodes[0].macaroon_path }, common.secret_key ); res.status(200).json({ token: token }); @@ -46,7 +46,7 @@ exports.authenticateUser = (req, res, next) => { if (common.rtl_pass === password) { var rpcUser = 'Single_Node_User'; const token = jwt.sign( - { user: rpcUser, lndConfigPath: common.nodes[0].lnd_config_path, macaroonPath: common.nodes[0].macaroon_path }, + { user: rpcUser, configPath: common.nodes[0].config_path, macaroonPath: common.nodes[0].macaroon_path }, common.secret_key ); res.status(200).json({ token: token }); @@ -58,7 +58,7 @@ exports.authenticateUser = (req, res, next) => { }); } } else { - fs.readFile(common.nodes[0].lnd_config_path, 'utf8', function (err, data) { + fs.readFile(common.nodes[0].config_path, 'utf8', function (err, data) { if (err) { logger.error({fileName: 'Authenticate', lineNum: 60, msg: 'LND Config Reading Failed!'}); err.description = 'You might be connecting RTL remotely to your LND node OR You might be missing rpcpass in your lnd.conf.'; @@ -81,7 +81,7 @@ exports.authenticateUser = (req, res, next) => { var rpcUser = (undefined !== jsonLNDConfig.Bitcoind && undefined !== jsonLNDConfig.Bitcoind['bitcoind.rpcuser']) ? jsonLNDConfig.Bitcoind['bitcoind.rpcuser'] : ''; rpcUser = (rpcUser === '' && undefined !== jsonLNDConfig['bitcoind.rpcuser']) ? jsonLNDConfig['bitcoind.rpcuser'] : ''; const token = jwt.sign( - { user: rpcUser, lndConfigPath: common.nodes[0].lnd_config_path, macaroonPath: common.nodes[0].macaroon_path }, + { user: rpcUser, configPath: common.nodes[0].config_path, macaroonPath: common.nodes[0].macaroon_path }, common.secret_key ); res.status(200).json({ token: token }); diff --git a/controllers/c-lightning/balance.js b/controllers/c-lightning/balance.js new file mode 100644 index 00000000..00008f45 --- /dev/null +++ b/controllers/c-lightning/balance.js @@ -0,0 +1,38 @@ +var request = require('request-promise'); +var common = require('../../common'); +var logger = require('../logger'); +var options = {}; + +exports.getBalance = (req, res, next) => { + options = common.getOptions(); + options.url = common.getSelLNServerUrl() + '/getBalance'; + request(options).then((body) => { + logger.info({fileName: 'Balance', msg: ' Balance Received: ' + JSON.stringify(body)}); + if(undefined === body.totalBalance) { + body.totalBalance = 0; + body.btc_totalBalance = 0; + } else { + body.btc_totalBalance = common.convertToBTC(body.totalBalance); + } + if(undefined === body.confBalance) { + body.confBalance = 0; + body.btc_confBalance = 0; + } else { + body.btc_confBalance = common.convertToBTC(body.confBalance); + } + if(undefined === body.unconfBalance) { + body.unconfBalance = 0; + body.btc_unconfBalance = 0; + } else { + body.btc_unconfBalance = common.convertToBTC(body.unconfBalance); + } + + res.status(200).json(body); + }) + .catch(function (err) { + return res.status(500).json({ + message: "Fetching balance failed!", + error: err.error + }); + }); +}; diff --git a/controllers/c-lightning/channels.js b/controllers/c-lightning/channels.js new file mode 100644 index 00000000..cc615441 --- /dev/null +++ b/controllers/c-lightning/channels.js @@ -0,0 +1,33 @@ +var request = require('request-promise'); +var common = require('../../common'); +var logger = require('../logger'); +var options = {}; + +exports.getLocalRemoteBalance = (req, res, next) => { + options = common.getOptions(); + options.url = common.getSelLNServerUrl() + '/channel/localremotebal'; + request(options).then(function (body) { + logger.info({fileName: 'Channels', msg: 'Local Remote Balance: ' + JSON.stringify(body)}); + if(undefined === body.localBalance) { + body.localBalance = 0; + body.btc_localBalance = 0; + } else { + body.btc_localBalance = common.convertToBTC(body.localBalance); + } + if(undefined === body.remoteBalance) { + body.remoteBalance = 0; + body.btc_remoteBalance = 0; + } else { + body.btc_remoteBalance = common.convertToBTC(body.remoteBalance); + } + + res.status(200).json(body); + }) + .catch(function (err) { + logger.error({fileName: 'Channels', lineNum: 14, msg: 'Local Remote Balance: ' + JSON.stringify(err)}); + return res.status(500).json({ + message: 'Fetching Local Remote Balance Failed!', + error: err.error + }); + }); +}; diff --git a/controllers/c-lightning/fees.js b/controllers/c-lightning/fees.js index 067293e5..6f2c2258 100644 --- a/controllers/c-lightning/fees.js +++ b/controllers/c-lightning/fees.js @@ -5,7 +5,7 @@ var options = {}; exports.getFees = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/getFees'; + options.url = common.getSelLNServerUrl() + '/getFees'; request(options).then((body) => { logger.info({fileName: 'Fees', msg: 'Fee Received: ' + JSON.stringify(body)}); if(undefined === body || body.error) { @@ -14,24 +14,6 @@ exports.getFees = (req, res, next) => { error: (undefined === body) ? 'Error From Server!' : body.error }); } else { - if (undefined === body.day_fee_sum) { - body.day_fee_sum = 0; - body.btc_day_fee_sum = 0; - } else { - body.btc_day_fee_sum = common.convertToBTC(body.day_fee_sum); - } - if (undefined === body.week_fee_sum) { - body.week_fee_sum = 0; - body.btc_week_fee_sum = 0; - } else { - body.btc_week_fee_sum = common.convertToBTC(body.week_fee_sum); - } - if (undefined === body.month_fee_sum) { - body.month_fee_sum = 0; - body.btc_month_fee_sum = 0; - } else { - body.btc_month_fee_sum = common.convertToBTC(body.month_fee_sum); - } if(undefined === body.feeCollected) { body.feeCollected = 0; body.btc_feeCollected = 0; diff --git a/controllers/c-lightning/getInfo.js b/controllers/c-lightning/getInfo.js index 0dfe88e4..04817a43 100644 --- a/controllers/c-lightning/getInfo.js +++ b/controllers/c-lightning/getInfo.js @@ -7,7 +7,7 @@ var options = {}; exports.getInfo = (req, res, next) => { common.setOptions(); options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/getinfo'; + options.url = common.getSelLNServerUrl() + '/getinfo'; if(common.multi_node_setup) { logger.info({fileName:'GetInfo', msg: 'Selected Node: ' + JSON.stringify(common.selectedNode.ln_node)}); } else { @@ -25,6 +25,8 @@ exports.getInfo = (req, res, next) => { error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error }); } else { + body.currency_unit = 'BTC'; + body.smaller_currency_unit = 'Sats'; res.status(200).json(body); } }) diff --git a/controllers/lnd/balance.js b/controllers/lnd/balance.js index b1fb378d..76aaae5c 100644 --- a/controllers/lnd/balance.js +++ b/controllers/lnd/balance.js @@ -5,7 +5,7 @@ var options = {}; exports.getBalance = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/balance/' + req.params.source; + options.url = common.getSelLNServerUrl() + '/balance/' + req.params.source; options.qs = req.query; request(options).then((body) => { logger.info({fileName: 'Balance', msg: 'Request params: ' + JSON.stringify(req.params) + 'Request Query: ' + JSON.stringify(req.query) + ' Balance Received: ' + JSON.stringify(body)}); diff --git a/controllers/lnd/channels.js b/controllers/lnd/channels.js index 9b9c56d2..a1cb0947 100644 --- a/controllers/lnd/channels.js +++ b/controllers/lnd/channels.js @@ -6,9 +6,9 @@ var options = {}; getAliasForChannel = (channel, channelType) => { return new Promise(function(resolve, reject) { if (undefined === channelType || channelType === 'all') { - options.url = common.getSelLNDServerUrl() + '/graph/node/' + channel.remote_pubkey; + options.url = common.getSelLNServerUrl() + '/graph/node/' + channel.remote_pubkey; } else { - options.url = common.getSelLNDServerUrl() + '/graph/node/' + channel.channel.remote_node_pub; + options.url = common.getSelLNServerUrl() + '/graph/node/' + channel.channel.remote_node_pub; } request(options).then(function(aliasBody) { logger.info({fileName: 'Channels', msg: 'Alias: ' + JSON.stringify(aliasBody.node.alias)}); @@ -27,9 +27,9 @@ getAliasForChannel = (channel, channelType) => { exports.getChannels = (req, res, next) => { options = common.getOptions(); if (undefined === req.params.channelType || req.params.channelType === 'all') { - options.url = common.getSelLNDServerUrl() + '/channels'; + options.url = common.getSelLNServerUrl() + '/channels'; } else { - options.url = common.getSelLNDServerUrl() + '/channels/' + req.params.channelType; // active_only, inactive_only, public_only, private_only, Not Implemented in Frontend yet + options.url = common.getSelLNServerUrl() + '/channels/' + req.params.channelType; // active_only, inactive_only, public_only, private_only, Not Implemented in Frontend yet } options.qs = req.query; request(options).then(function (body) { @@ -75,7 +75,7 @@ exports.getChannels = (req, res, next) => { exports.postChannel = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/channels'; + options.url = common.getSelLNServerUrl() + '/channels'; options.form = { node_pubkey_string: req.body.node_pubkey, local_funding_amount: req.body.local_funding_amount, @@ -110,7 +110,7 @@ exports.postChannel = (req, res, next) => { exports.postTransactions = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/channels/transactions'; + options.url = common.getSelLNServerUrl() + '/channels/transactions'; if(req.body.paymentReq) { options.form = JSON.stringify({ payment_request: req.body.paymentReq @@ -152,7 +152,7 @@ exports.closeChannel = (req, res, next) => { req.setTimeout(60000 * 10); // timeout 10 mins options = common.getOptions(); let channelpoint = req.params.channelPoint.replace(':', '/'); - options.url = common.getSelLNDServerUrl() + '/channels/' + channelpoint + '?force=' + req.query.force; + options.url = common.getSelLNServerUrl() + '/channels/' + channelpoint + '?force=' + req.query.force; logger.info({fileName: 'Channels', msg: 'Closing Channel: ' + options.url}); request.delete(options).then((body) => { logger.info({fileName: 'Channels', msg: 'Close Channel Response: ' + JSON.stringify(body)}); @@ -176,7 +176,7 @@ exports.closeChannel = (req, res, next) => { exports.postChanPolicy = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/chanpolicy'; + options.url = common.getSelLNServerUrl() + '/chanpolicy'; if(req.body.chanPoint === 'all') { options.form = JSON.stringify({ global: true, diff --git a/controllers/lnd/channelsBackup.js b/controllers/lnd/channelsBackup.js index 2fe6af2c..748a0bca 100644 --- a/controllers/lnd/channelsBackup.js +++ b/controllers/lnd/channelsBackup.js @@ -11,12 +11,12 @@ exports.getBackup = (req, res, next) => { if (req.params.channelPoint === 'ALL') { channel_backup_file = common.selectedNode.channel_backup_path + common.path_separator + 'channel-all.bak'; message = 'All Channels Backup Successful at: ' + channel_backup_file + ' !'; - options.url = common.getSelLNDServerUrl() + '/channels/backup'; + options.url = common.getSelLNServerUrl() + '/channels/backup'; } else { channel_backup_file = common.selectedNode.channel_backup_path + common.path_separator + 'channel-' + req.params.channelPoint.replace(':', '-') + '.bak'; message = 'Channel Backup Successful at: ' + channel_backup_file + ' !'; let channelpoint = req.params.channelPoint.replace(':', '/'); - options.url = common.getSelLNDServerUrl() + '/channels/backup/' + channelpoint; + options.url = common.getSelLNServerUrl() + '/channels/backup/' + channelpoint; let exists = fs.existsSync(channel_backup_file); if (exists) { fs.writeFile(channel_backup_file, '', () => { }); @@ -51,7 +51,7 @@ exports.getBackup = (req, res, next) => { exports.postBackupVerify = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/channels/backup/verify'; + options.url = common.getSelLNServerUrl() + '/channels/backup/verify'; let channel_verify_file = ''; let message = ''; let verify_backup = ''; diff --git a/controllers/lnd/fees.js b/controllers/lnd/fees.js index e902edf6..058fac0a 100644 --- a/controllers/lnd/fees.js +++ b/controllers/lnd/fees.js @@ -5,7 +5,7 @@ var options = {}; exports.getFees = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/fees'; + options.url = common.getSelLNServerUrl() + '/fees'; request(options).then((body) => { logger.info({fileName: 'Fees', msg: 'Fee Received: ' + JSON.stringify(body)}); if(undefined === body || body.error) { diff --git a/controllers/lnd/getInfo.js b/controllers/lnd/getInfo.js index 8468142c..60895781 100644 --- a/controllers/lnd/getInfo.js +++ b/controllers/lnd/getInfo.js @@ -7,7 +7,7 @@ var options = {}; exports.getInfo = (req, res, next) => { common.setOptions(); options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/getinfo'; + options.url = common.getSelLNServerUrl() + '/getinfo'; if(common.multi_node_setup) { logger.info({fileName:'GetInfo', msg: 'Selected Node: ' + JSON.stringify(common.selectedNode.ln_node)}); } else { diff --git a/controllers/lnd/graph.js b/controllers/lnd/graph.js index 41e443dd..1028f3e8 100644 --- a/controllers/lnd/graph.js +++ b/controllers/lnd/graph.js @@ -5,7 +5,7 @@ var options = {}; getAliasFromPubkey = (hop) => { return new Promise(function(resolve, reject) { - options.url = common.getSelLNDServerUrl() + '/graph/node/' + hop.pub_key; + options.url = common.getSelLNServerUrl() + '/graph/node/' + hop.pub_key; request(options) .then(function(aliasBody) { logger.info({fileName: 'Graph', msg: 'Alias: ' + JSON.stringify(aliasBody.node.alias)}); @@ -18,7 +18,7 @@ getAliasFromPubkey = (hop) => { exports.getDescribeGraph = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/graph'; + options.url = common.getSelLNServerUrl() + '/graph'; request.get(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); @@ -42,7 +42,7 @@ exports.getDescribeGraph = (req, res, next) => { exports.getGraphInfo = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/graph/info'; + options.url = common.getSelLNServerUrl() + '/graph/info'; request.get(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); @@ -71,7 +71,7 @@ exports.getGraphInfo = (req, res, next) => { exports.getGraphNode = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/graph/node/' + req.params.pubKey; + options.url = common.getSelLNServerUrl() + '/graph/node/' + req.params.pubKey; request(options).then((body) => { logger.info({fileName: 'Graph', msg: 'Node Info Received: ' + JSON.stringify(body)}); if(undefined === body || body.error) { @@ -95,7 +95,7 @@ exports.getGraphNode = (req, res, next) => { exports.getGraphEdge = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/graph/edge/' + req.params.chanid; + options.url = common.getSelLNServerUrl() + '/graph/edge/' + req.params.chanid; request(options).then((body) => { logger.info({fileName: 'Graph', msg: 'Edge Info Received: ' + JSON.stringify(body)}); if(undefined === body || body.error) { @@ -119,7 +119,7 @@ exports.getGraphEdge = (req, res, next) => { exports.getQueryRoutes = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/graph/routes/' + req.params.destPubkey + '/' + req.params.amount; + options.url = common.getSelLNServerUrl() + '/graph/routes/' + req.params.destPubkey + '/' + req.params.amount; request(options).then((body) => { logger.info({fileName: 'Graph', msg: 'Query Routes Received: ' + JSON.stringify(body)}); if(undefined === body || body.error) { diff --git a/controllers/lnd/graphInfo.js b/controllers/lnd/graphInfo.js index 08c8a31a..9d42e663 100644 --- a/controllers/lnd/graphInfo.js +++ b/controllers/lnd/graphInfo.js @@ -4,7 +4,7 @@ var common = require('../../common'); exports.getGraphInfo = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/graph/info'; + options.url = common.getSelLNServerUrl() + '/graph/info'; request(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); diff --git a/controllers/lnd/invoices.js b/controllers/lnd/invoices.js index e5bf5f02..ee40abf8 100644 --- a/controllers/lnd/invoices.js +++ b/controllers/lnd/invoices.js @@ -5,7 +5,7 @@ var options = {}; exports.getInvoice = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/invoice/' + req.params.rHashStr; + options.url = common.getSelLNServerUrl() + '/invoice/' + req.params.rHashStr; request(options).then((body) => { logger.info({fileName: 'Invoice', msg: 'Invoice Info Received: ' + JSON.stringify(body)}); if(undefined === body || body.error) { @@ -26,7 +26,7 @@ exports.getInvoice = (req, res, next) => { exports.listInvoices = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/invoices?num_max_invoices=' + req.query.num_max_invoices + '&index_offset=' + req.query.index_offset + + options.url = common.getSelLNServerUrl() + '/invoices?num_max_invoices=' + req.query.num_max_invoices + '&index_offset=' + req.query.index_offset + '&reversed=' + req.query.reversed; request(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); @@ -61,7 +61,7 @@ exports.listInvoices = (req, res, next) => { exports.addInvoice = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/invoices'; + options.url = common.getSelLNServerUrl() + '/invoices'; options.form = JSON.stringify({ memo: req.body.memo, value: req.body.amount, diff --git a/controllers/lnd/newAddress.js b/controllers/lnd/newAddress.js index bf086455..20021880 100644 --- a/controllers/lnd/newAddress.js +++ b/controllers/lnd/newAddress.js @@ -5,7 +5,7 @@ var options = {}; exports.getNewAddress = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/newaddress?type=' + req.query.type; + options.url = common.getSelLNServerUrl() + '/newaddress?type=' + req.query.type; request(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); diff --git a/controllers/lnd/payReq.js b/controllers/lnd/payReq.js index b5223359..26ce4326 100644 --- a/controllers/lnd/payReq.js +++ b/controllers/lnd/payReq.js @@ -5,7 +5,7 @@ var options = {}; exports.decodePayment = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/payreq/' + req.params.payRequest; + options.url = common.getSelLNServerUrl() + '/payreq/' + req.params.payRequest; request(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); diff --git a/controllers/lnd/payments.js b/controllers/lnd/payments.js index dae224f5..2f02cb90 100644 --- a/controllers/lnd/payments.js +++ b/controllers/lnd/payments.js @@ -5,7 +5,7 @@ var options = {}; exports.getPayments = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/payments'; + options.url = common.getSelLNServerUrl() + '/payments'; request(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); diff --git a/controllers/lnd/peers.js b/controllers/lnd/peers.js index 280f0d57..b02a9840 100644 --- a/controllers/lnd/peers.js +++ b/controllers/lnd/peers.js @@ -5,7 +5,7 @@ var options = {}; getAliasForPeers = (peer) => { return new Promise(function(resolve, reject) { - options.url = common.getSelLNDServerUrl() + '/graph/node/' + peer.pub_key; + options.url = common.getSelLNServerUrl() + '/graph/node/' + peer.pub_key; request(options) .then(function(aliasBody) { logger.info({fileName: 'Peers', msg: 'Alias: ' + JSON.stringify(aliasBody.node.alias)}); @@ -18,7 +18,7 @@ getAliasForPeers = (peer) => { exports.getPeers = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/peers'; + options.url = common.getSelLNServerUrl() + '/peers'; request(options).then(function (body) { let peers = (undefined === body.peers) ? [] : body.peers; Promise.all( @@ -43,7 +43,7 @@ exports.getPeers = (req, res, next) => { exports.postPeer = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/peers'; + options.url = common.getSelLNServerUrl() + '/peers'; options.form = JSON.stringify({ addr: { host: req.body.host, pubkey: req.body.pubkey }, perm: req.body.perm @@ -56,7 +56,7 @@ exports.postPeer = (req, res, next) => { error: (undefined === body) ? 'Error From Server!' : body.error }); } else { - options.url = common.getSelLNDServerUrl() + '/peers'; + options.url = common.getSelLNServerUrl() + '/peers'; request(options).then(function (body) { let peers = (undefined === body.peers) ? [] : body.peers; Promise.all( @@ -86,7 +86,7 @@ exports.postPeer = (req, res, next) => { exports.deletePeer = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/peers/' + req.params.peerPubKey; + options.url = common.getSelLNServerUrl() + '/peers/' + req.params.peerPubKey; request.delete(options).then((body) => { logger.info({fileName: 'Peers', msg: 'Detach Peer Response: ' + JSON.stringify(body)}); if(undefined === body || body.error) { diff --git a/controllers/lnd/switch.js b/controllers/lnd/switch.js index becfdc8b..4d061c29 100644 --- a/controllers/lnd/switch.js +++ b/controllers/lnd/switch.js @@ -5,7 +5,7 @@ var options = {}; exports.forwardingHistory = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/switch'; + options.url = common.getSelLNServerUrl() + '/switch'; options.form = {}; if (undefined !== req.body.num_max_events) { options.form.num_max_events = req.body.num_max_events; diff --git a/controllers/lnd/transactions.js b/controllers/lnd/transactions.js index baf390cc..e426c507 100644 --- a/controllers/lnd/transactions.js +++ b/controllers/lnd/transactions.js @@ -5,7 +5,7 @@ var options = {}; exports.getTransactions = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/transactions'; + options.url = common.getSelLNServerUrl() + '/transactions'; request(options).then((body) => { const body_str = (undefined === body) ? '' : JSON.stringify(body); const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); @@ -35,7 +35,7 @@ exports.getTransactions = (req, res, next) => { exports.postTransactions = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/transactions'; + options.url = common.getSelLNServerUrl() + '/transactions'; options.form = { amount: req.body.amount, addr: req.body.address, diff --git a/controllers/lnd/wallet.js b/controllers/lnd/wallet.js index c5341aa3..ec2f7e36 100644 --- a/controllers/lnd/wallet.js +++ b/controllers/lnd/wallet.js @@ -6,7 +6,7 @@ var options = {}; exports.genSeed = (req, res, next) => { options = common.getOptions(); - options.url = common.getSelLNDServerUrl() + '/genseed'; + options.url = common.getSelLNServerUrl() + '/genseed'; if (undefined !== req.params.passphrase) { options.form = JSON.stringify({aezeed_passphrase: atob(req.params.passphrase)}); } @@ -32,13 +32,13 @@ exports.operateWallet = (req, res, next) => { options = common.getOptions(); options.method = 'POST'; if (undefined === req.params.operation || req.params.operation === 'unlockwallet') { - options.url = common.getSelLNDServerUrl() + '/unlockwallet'; + options.url = common.getSelLNServerUrl() + '/unlockwallet'; options.form = JSON.stringify({ wallet_password: Buffer.from(atob(req.body.wallet_password)).toString('base64') }); err_message = 'Unlocking wallet failed! Verify that lnd is running and the wallet is locked!'; } else { - options.url = common.getSelLNDServerUrl() + '/initwallet'; + options.url = common.getSelLNServerUrl() + '/initwallet'; if (undefined !== req.body.aezeed_passphrase && req.body.aezeed_passphrase !== '') { options.form = JSON.stringify({ wallet_password: Buffer.from(atob(req.body.wallet_password)).toString('base64'), diff --git a/routes/c-lightning/balance.js b/routes/c-lightning/balance.js new file mode 100644 index 00000000..ea734f5d --- /dev/null +++ b/routes/c-lightning/balance.js @@ -0,0 +1,8 @@ +const BalanceController = require("../../controllers/c-lightning/balance"); +const express = require("express"); +const router = express.Router(); +const authCheck = require("../authCheck"); + +router.get("/", authCheck, BalanceController.getBalance); + +module.exports = router; diff --git a/routes/c-lightning/channels.js b/routes/c-lightning/channels.js new file mode 100644 index 00000000..31c0aa2f --- /dev/null +++ b/routes/c-lightning/channels.js @@ -0,0 +1,8 @@ +const ChannelsController = require("../../controllers/c-lightning/channels"); +const express = require("express"); +const router = express.Router(); +const authCheck = require("../authCheck"); + +router.get("/localremotebalance", authCheck, ChannelsController.getLocalRemoteBalance); + +module.exports = router; diff --git a/src/app/clightning/cl-root.component.ts b/src/app/clightning/cl-root.component.ts index ecba59f3..2be7bb6f 100644 --- a/src/app/clightning/cl-root.component.ts +++ b/src/app/clightning/cl-root.component.ts @@ -19,28 +19,19 @@ export class CLRootComponent implements OnInit, OnDestroy { constructor(private store: Store, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {} ngOnInit() { - this.store.dispatch(new RTLActions.FetchCLInfo()); this.router.navigate(['./home'], {relativeTo: this.activatedRoute}); - this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_CL_INFO || action.type === RTLActions.INIT_APP_DATA)) + this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_CL_INFO)) .subscribe((infoData: RTLActions.SetCLInfo | RTLActions.InitAppData) => { if(infoData.type === RTLActions.SET_CL_INFO && undefined !== infoData.payload.id) { this.initializeRemainingData(); } - if(infoData.type === RTLActions.INIT_APP_DATA) { - this.store.dispatch(new RTLActions.FetchCLInfo()); - } }); } initializeRemainingData() { this.store.dispatch(new RTLActions.FetchCLFees()); - // this.store.dispatch(new RTLActions.FetchPeers()); - // this.store.dispatch(new RTLActions.FetchBalance('channels')); - // this.store.dispatch(new RTLActions.FetchNetwork()); - // this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'})); - // this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'})); - // this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true})); - // this.store.dispatch(new RTLActions.FetchPayments()); + this.store.dispatch(new RTLActions.FetchCLBalance()); + this.store.dispatch(new RTLActions.FetchCLLocalRemoteBalance()); } ngOnDestroy() { diff --git a/src/app/clightning/home/home.component.html b/src/app/clightning/home/home.component.html index 9d288450..b4e87da6 100644 --- a/src/app/clightning/home/home.component.html +++ b/src/app/clightning/home/home.component.html @@ -1,25 +1,150 @@
-
-
- - - -
Fee Report
-
-
- -
- - Fee Collected - {{fees?.feeCollected}} - - -
- - +
+ + + +
Wallet Balance
+
+
+ + + account_balance_wallet + + +

{{totalBalance.btc_confBalance | number}} + {{information?.currency_unit}}

+ +

{{totalBalance.confBalance | number}} {{information?.smaller_currency_unit}}

+
+
+
+ + +
+
+
+ + + +
Peers
+
+
+ + + group + +

{{information?.num_peers | number}}

+ +

0

+
+
+ + +
+
+
+ + + +
Channel Balance
+
+
+ + + linear_scale + + +

{{lrBalance.btc_localBalance | number}} + {{information?.currency_unit}}

+ +

{{lrBalance.localBalance | number}} {{information?.smaller_currency_unit}}

+
+
+
+ + + +
+
+
+ + + +
Fee Report
+
+
+ + + redeem -
-
+

{{fees?.feeCollected | number}} (mSats)

+
+ + + +
+
+
+ + + +
Channel Status
+
+
+ +
+ + Active + +

{{information?.num_active_channels}}

+
+ +
+ + Inactive + +

{{information?.num_inactive_channels}}

+
+ +
+ + Pending + +

{{information?.num_pending_channels}}

+
+ +
+
+ + +
+
+
+
+
+
+
+ + + +
Local-Remote Channel Capacity
+
+
+ +
+
+ + +
+
+ + +
+
-

Sats

+ +

Sats

+
\ No newline at end of file diff --git a/src/app/clightning/home/home.component.scss b/src/app/clightning/home/home.component.scss index ca8052d8..2f58c21d 100644 --- a/src/app/clightning/home/home.component.scss +++ b/src/app/clightning/home/home.component.scss @@ -10,3 +10,7 @@ .card-chnl-balances { min-height: 354px; } + +.channel-status-list { + max-height: 46px !important; +} \ No newline at end of file diff --git a/src/app/clightning/home/home.component.ts b/src/app/clightning/home/home.component.ts index a0a25ea4..e237e27d 100644 --- a/src/app/clightning/home/home.component.ts +++ b/src/app/clightning/home/home.component.ts @@ -4,11 +4,10 @@ import { takeUntil } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { LoggerService } from '../../shared/services/logger.service'; -import { GetInfoCL, FeesCL } from '../../shared/models/clModels'; -import { LightningNode } from '../../shared/models/RTLconfig'; +import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL } from '../../shared/models/clModels'; +import { SelNodeChild } from '../../shared/models/RTLconfig'; import * as fromRTLReducer from '../../store/rtl.reducers'; -import * as fromCLReducer from '../store/cl.reducers'; @Component({ selector: 'rtl-cl-home', @@ -16,36 +15,87 @@ import * as fromCLReducer from '../store/cl.reducers'; styleUrls: ['./home.component.scss'] }) export class CLHomeComponent implements OnInit, OnDestroy { + public selNode: SelNodeChild = {}; public fees: FeesCL; public information: GetInfoCL = {}; - public flgLoading: Array = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network + public totalBalance: BalanceCL = {}; + public lrBalance: LocalRemoteBalanceCL = {}; + public flgLoading: Array = [true, true, true, true]; private unsub: Array> = [new Subject(), new Subject(), new Subject()]; + public position = 'below'; + barPadding = 0; + maxBalanceValue = 0; + lrBalances = [...[{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}]]; + flgTotalCalculated = false; + view = []; + yAxisLabel = 'Balance'; + colorScheme = {domain: ['#FF0000']}; - constructor(private logger: LoggerService, private store: Store) {} + constructor(private logger: LoggerService, private store: Store) { + switch (true) { + case (window.innerWidth <= 730): + this.view = [250, 352]; + break; + case (window.innerWidth > 415 && window.innerWidth <= 730): + this.view = [280, 352]; + break; + case (window.innerWidth > 730 && window.innerWidth <= 1024): + this.view = [300, 352]; + break; + case (window.innerWidth > 1024 && window.innerWidth <= 1280): + this.view = [350, 352]; + break; + default: + this.view = [300, 352]; + break; + } + Object.assign(this, this.lrBalances); + } ngOnInit() { + this.flgTotalCalculated = false; this.store.select('cl') .pipe(takeUntil(this.unsub[0])) - .subscribe((clStore: fromCLReducer.CLState) => { - clStore.effectErrorsCl.forEach(effectsErr => { + .subscribe((rtlStore) => { + rtlStore.effectErrorsCl.forEach(effectsErr => { if (effectsErr.action === 'FetchCLInfo') { this.flgLoading[0] = 'error'; } if (effectsErr.action === 'FetchCLFees') { this.flgLoading[1] = 'error'; } + if (effectsErr.action === 'FetchCLBalance') { + this.flgLoading[2] = 'error'; + } + if (effectsErr.action === 'FetchCLLocalRemoteBalance') { + this.flgLoading[3] = 'error'; + } }); - this.information = clStore.information; + this.selNode = rtlStore.nodeSettings; + this.information = rtlStore.information if (this.flgLoading[0] !== 'error') { this.flgLoading[0] = (undefined !== this.information.id) ? false : true; } - this.fees = clStore.fees; + + this.fees = rtlStore.fees; if (this.flgLoading[1] !== 'error') { this.flgLoading[1] = (undefined !== this.fees.feeCollected) ? false : true; } - this.logger.info(clStore); - }); + this.totalBalance = rtlStore.balance; + if (this.flgLoading[2] !== 'error') { + this.flgLoading[2] = ('' !== this.totalBalance) ? false : true; + } + + this.lrBalance = rtlStore.localRemoteBalance; + this.maxBalanceValue = (rtlStore.localRemoteBalance.localBalance > rtlStore.localRemoteBalance.remoteBalance) ? rtlStore.localRemoteBalance.localBalance : rtlStore.localRemoteBalance.remoteBalance; + this.lrBalances = [...[{'name': 'Local Balance', 'value': +rtlStore.localRemoteBalance.localBalance}, {'name': 'Remote Balance', 'value': +rtlStore.localRemoteBalance.remoteBalance}]]; + if (this.flgLoading[3] !== 'error') { + this.flgLoading[3] = ('' !== this.lrBalance) ? false : true; + } + + this.logger.info(rtlStore); + }); } ngOnDestroy() { diff --git a/src/app/clightning/store/cl.effects.ts b/src/app/clightning/store/cl.effects.ts index e154f426..3a0dbe83 100644 --- a/src/app/clightning/store/cl.effects.ts +++ b/src/app/clightning/store/cl.effects.ts @@ -7,33 +7,33 @@ import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators'; import { environment, API_URL } from '../../../environments/environment'; import { LoggerService } from '../../shared/services/logger.service'; -import { GetInfoCL, FeesCL } from '../../shared/models/clModels'; +import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL } from '../../shared/models/clModels'; import * as fromRTLReducer from '../../store/rtl.reducers'; import * as RTLActions from '../../store/rtl.actions'; @Injectable() export class CLEffects implements OnDestroy { - dialogRef: any; - CHILD_API_URL = API_URL + '/cl'; + dialogRef: any; + CHILD_API_URL = API_URL + '/cl'; - constructor( - private actions$: Actions, - private httpClient: HttpClient, - private store: Store, - private logger: LoggerService) { } + constructor( + private actions$: Actions, + private httpClient: HttpClient, + private store: Store, + private logger: LoggerService) { } - @Effect() - infoFetchCL = this.actions$.pipe( - ofType(RTLActions.FETCH_CL_INFO), - withLatestFrom(this.store.select('root')), - mergeMap(([action, store]) => { - this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLInfo')); - return this.httpClient.get(this.CHILD_API_URL + environment.GETINFO_API) - .pipe( - map((info) => { + @Effect() + infoFetchCL = this.actions$.pipe( + ofType(RTLActions.FETCH_CL_INFO), + withLatestFrom(this.store.select('root')), + mergeMap(([action, store]) => { + this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLInfo')); + return this.httpClient.get(this.CHILD_API_URL + environment.GETINFO_API) + .pipe( + map((info) => { this.logger.info(info); - let chainObj = {chain: '', network: ''}; + let chainObj = { chain: '', network: '' }; if (info.network === 'testnet') { chainObj.chain = 'Bitcoin'; chainObj.network = 'Testnet'; @@ -47,53 +47,95 @@ export class CLEffects implements OnDestroy { chainObj.chain = 'Litecoin'; chainObj.network = 'Testnet'; } - sessionStorage.setItem('clUnlocked', 'true'); - const node_data = { - identity_pubkey: info.id, - alias: info.alias, - testnet: (info.network === 'testnet' || info.network === 'litecoin-testnet') ? true : false, - chains: [chainObj], - version: info.version, - currency_unit: 'BTC', - smaller_currency_unit: 'Sats', - numberOfPendingChannels: info.num_pending_channels - }; - this.store.dispatch(new RTLActions.SetNodeData(node_data)); - return { - type: RTLActions.SET_CL_INFO, - payload: (undefined !== info) ? info : {} - }; - }), - catchError((err) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLInfo', code: err.status, message: err.error.error })); - return of(); - }) - ); - } - )); + sessionStorage.setItem('clUnlocked', 'true'); + const node_data = { + identity_pubkey: info.id, + alias: info.alias, + testnet: (info.network === 'testnet' || info.network === 'litecoin-testnet') ? true : false, + chains: [chainObj], + version: info.version, + currency_unit: 'BTC', + smaller_currency_unit: 'Sats', + numberOfPendingChannels: info.num_pending_channels + }; + this.store.dispatch(new RTLActions.SetNodeData(node_data)); + return { + type: RTLActions.SET_CL_INFO, + payload: (undefined !== info) ? info : {} + }; + }), + catchError((err) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLInfo', code: err.status, message: err.error.error })); + return of(); + }) + ); + } + )); - @Effect() - fetchFeesCL = this.actions$.pipe( - ofType(RTLActions.FETCH_CL_FEES), - mergeMap((action: RTLActions.FetchCLFees) => { - this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLFees')); - return this.httpClient.get(this.CHILD_API_URL + environment.FEES_API); - }), - map((fees) => { - this.logger.info(fees); - return { - type: RTLActions.SET_CL_FEES, - payload: (undefined !== fees) ? fees : {} - }; - }), - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLFees', code: err.status, message: err.error.error })); - return of(); - } - )); + @Effect() + fetchFeesCL = this.actions$.pipe( + ofType(RTLActions.FETCH_CL_FEES), + mergeMap((action: RTLActions.FetchCLFees) => { + this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLFees')); + return this.httpClient.get(this.CHILD_API_URL + environment.FEES_API); + }), + map((fees) => { + this.logger.info(fees); + return { + type: RTLActions.SET_CL_FEES, + payload: (undefined !== fees) ? fees : {} + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLFees', code: err.status, message: err.error.error })); + return of(); + } + )); - ngOnDestroy() { } + @Effect() + fetchBalanceCL = this.actions$.pipe( + ofType(RTLActions.FETCH_CL_BALANCE), + mergeMap((action: RTLActions.FetchCLBalance) => { + this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLBalance')); + return this.httpClient.get(this.CHILD_API_URL + environment.BALANCE_API); + }), + map((balance) => { + this.logger.info(balance); + return { + type: RTLActions.SET_CL_BALANCE, + payload: (undefined !== balance) ? balance : {} + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLBalance', code: err.status, message: err.error.error })); + return of(); + } + )); + + @Effect() + fetchLocalRemoteBalanceCL = this.actions$.pipe( + ofType(RTLActions.FETCH_CL_LOCAL_REMOTE_BALANCE), + mergeMap((action: RTLActions.FetchCLLocalRemoteBalance) => { + this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLLocalRemoteBalance')); + return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API + '/localremotebalance'); + }), + map((lrBalance) => { + this.logger.info(lrBalance); + return { + type: RTLActions.SET_CL_LOCAL_REMOTE_BALANCE, + payload: (undefined !== lrBalance) ? lrBalance : {} + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLLocalRemoteBalance', code: err.status, message: err.error.error })); + return of(); + } + )); + + ngOnDestroy() { } } diff --git a/src/app/clightning/store/cl.reducers.ts b/src/app/clightning/store/cl.reducers.ts index 86bad282..fb16acf0 100644 --- a/src/app/clightning/store/cl.reducers.ts +++ b/src/app/clightning/store/cl.reducers.ts @@ -1,5 +1,5 @@ import { SelNodeChild } from '../../shared/models/RTLconfig'; -import { GetInfoCL, FeesCL } from '../../shared/models/clModels'; +import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL } from '../../shared/models/clModels'; import { ErrorPayload } from '../../shared/models/errorPayload'; import * as RTLActions from '../../store/rtl.actions'; @@ -8,13 +8,17 @@ export interface CLState { nodeSettings: SelNodeChild; information: GetInfoCL; fees: FeesCL; + balance: BalanceCL; + localRemoteBalance: LocalRemoteBalanceCL; } export const initCLState: CLState = { effectErrorsCl: [], - nodeSettings: { channelBackupPath: 'my dummy path', satsToBTC: false }, + nodeSettings: { channelBackupPath: '', satsToBTC: false }, information: {}, - fees: {} + fees: {}, + balance: {}, + localRemoteBalance: {} } export function CLReducer(state = initCLState, action: RTLActions.RTLActions) { @@ -51,6 +55,16 @@ export function CLReducer(state = initCLState, action: RTLActions.RTLActions) { ...state, fees: action.payload }; + case RTLActions.SET_CL_BALANCE: + return { + ...state, + balance: action.payload + }; + case RTLActions.SET_CL_LOCAL_REMOTE_BALANCE: + return { + ...state, + localRemoteBalance: action.payload + }; default: return state; } diff --git a/src/app/lnd/lnd-root.component.ts b/src/app/lnd/lnd-root.component.ts index 3aa6e595..9dd88920 100644 --- a/src/app/lnd/lnd-root.component.ts +++ b/src/app/lnd/lnd-root.component.ts @@ -19,7 +19,6 @@ export class LNDRootComponent implements OnInit, OnDestroy { constructor(private store: Store, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {} ngOnInit() { - this.store.dispatch(new RTLActions.FetchInfo()); this.router.navigate(['./home'], {relativeTo: this.activatedRoute}); this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_INFO || action.type === RTLActions.INIT_APP_DATA)) .subscribe((infoData: RTLActions.SetInfo | RTLActions.InitAppData) => { diff --git a/src/app/lnd/store/lnd.effects.ts b/src/app/lnd/store/lnd.effects.ts index bb3c69a5..2a90a451 100644 --- a/src/app/lnd/store/lnd.effects.ts +++ b/src/app/lnd/store/lnd.effects.ts @@ -808,14 +808,6 @@ export class LNDEffects implements OnDestroy { }) ); - @Effect({ dispatch: false }) - showLNDConfig = this.actions$.pipe( - ofType(RTLActions.SHOW_CONFIG), - map((action: RTLActions.ShowConfig) => { - return action.payload; - }) - ); - @Effect() SetChannelTransaction = this.actions$.pipe( ofType(RTLActions.SET_CHANNEL_TRANSACTION), diff --git a/src/app/lnd/store/lnd.reducers.ts b/src/app/lnd/store/lnd.reducers.ts index c7ba695d..299aa37e 100644 --- a/src/app/lnd/store/lnd.reducers.ts +++ b/src/app/lnd/store/lnd.reducers.ts @@ -32,7 +32,7 @@ export interface LNDState { export const initLNDState: LNDState = { effectErrorsLnd: [], - nodeSettings: { channelBackupPath: 'my dummy path', satsToBTC: false }, + nodeSettings: { channelBackupPath: '', satsToBTC: false }, information: {}, peers: [], fees: {}, diff --git a/src/app/shared/components/server-config/server-config.component.html b/src/app/shared/components/server-config/server-config.component.html index d9e74e2e..c874e24d 100644 --- a/src/app/shared/components/server-config/server-config.component.html +++ b/src/app/shared/components/server-config/server-config.component.html @@ -10,7 +10,7 @@
RTL - LND + {{lnImplementationStr}} BITCOIND
diff --git a/src/app/shared/components/server-config/server-config.component.ts b/src/app/shared/components/server-config/server-config.component.ts index 8b34e14d..0d1ef7e8 100644 --- a/src/app/shared/components/server-config/server-config.component.ts +++ b/src/app/shared/components/server-config/server-config.component.ts @@ -16,7 +16,8 @@ import * as fromRTLReducer from '../../../store/rtl.reducers'; export class ServerConfigComponent implements OnInit, OnDestroy { public selNode: LightningNode; public selectedNodeType = 'rtl'; - public showLND = false; + public showLnConfig = false; + public lnImplementationStr = ''; public showBitcoind = false; public configData = ''; public fileFormat = 'INI'; @@ -34,16 +35,17 @@ export class ServerConfigComponent implements OnInit, OnDestroy { } }); this.configData = ''; - this.showLND = false; + this.showLnConfig = false; this.showBitcoind = false; this.selNode = rtlStore.selNode; - if (undefined !== this.selNode.authentication && undefined !== this.selNode.authentication.lndConfigPath && this.selNode.authentication.lndConfigPath !== '') { - this.showLND = true; + this.lnImplementationStr = this.selNode.lnImplementation.toLowerCase() === 'clightning' ? 'C-Lightning' : 'LND'; + if (undefined !== this.selNode.authentication && undefined !== this.selNode.authentication.configPath && this.selNode.authentication.configPath !== '') { + this.showLnConfig = true; } if (undefined !== this.selNode.authentication && undefined !== this.selNode.authentication.bitcoindConfigPath && this.selNode.authentication.bitcoindConfigPath !== '') { this.showBitcoind = true; } - if (this.selectedNodeType === 'lnd' && !this.showLND) { + if (this.selectedNodeType === 'ln' && !this.showLnConfig) { this.selectedNodeType = 'rtl'; } if (this.selectedNodeType === 'bitcoind' && !this.showBitcoind) { @@ -60,7 +62,7 @@ export class ServerConfigComponent implements OnInit, OnDestroy { onShowConfig() { this.store.dispatch(new RTLActions.OpenSpinner('Opening Config File...')); this.store.dispatch(new RTLActions.FetchConfig(this.selectedNodeType)); - this.rtlEffects.showLNDConfig + this.rtlEffects.showLnConfig .pipe(takeUntil(this.unsubs[1])) .subscribe((config: any) => { const configFile = config.data; diff --git a/src/app/shared/models/RTLconfig.ts b/src/app/shared/models/RTLconfig.ts index 14804291..808e9126 100644 --- a/src/app/shared/models/RTLconfig.ts +++ b/src/app/shared/models/RTLconfig.ts @@ -17,7 +17,7 @@ export class Settings { public satsToBTC: boolean, public bitcoindConfigPath?: string, public enableLogging?: boolean, - public lndServerUrl?: string, + public lnServerUrl?: string, public channelBackupPath?: string ) { } } @@ -25,7 +25,7 @@ export class Settings { export class Authentication { constructor( public nodeAuthType?: string, - public lndConfigPath?: string, + public configPath?: string, public bitcoindConfigPath?: string ) { } } diff --git a/src/app/shared/models/clModels.ts b/src/app/shared/models/clModels.ts index bd83f43c..66b95a5f 100644 --- a/src/app/shared/models/clModels.ts +++ b/src/app/shared/models/clModels.ts @@ -19,9 +19,27 @@ export interface GetInfoCL { network?: string; msatoshi_fees_collected?: number; fees_collected_msat?: string; + currency_unit?: string; + smaller_currency_unit?: string; } export interface FeesCL { feeCollected?: number; btc_feeCollected?: number; } + +export interface BalanceCL { + totalBalance?: number; + confBalance?: number; + unconfBalance?: number; + btc_totalBalance?: number; + btc_confBalance?: number; + btc_unconfBalance?: number; +} + +export interface LocalRemoteBalanceCL { + localBalance?: number; + remoteBalance?: number; + btc_localBalance?: number; + btc_remoteBalance?: number; +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index d9205a2d..d23733a8 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -65,8 +65,7 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe'; QRCodeModule, NgxChartsModule, RouterModule, - HttpClientModule, - NgxChartsModule + HttpClientModule ], exports: [ FormsModule, diff --git a/src/app/store/rtl.actions.ts b/src/app/store/rtl.actions.ts index 0fd35d5c..d88d522c 100644 --- a/src/app/store/rtl.actions.ts +++ b/src/app/store/rtl.actions.ts @@ -1,7 +1,7 @@ import { MatDialogConfig } from '@angular/material'; import { Action } from '@ngrx/store'; -import { GetInfoCL } from '../shared/models/clModels'; +import { GetInfoCL, FeesCL } from '../shared/models/clModels'; import { RTLConfiguration, Settings, LightningNode, GetInfoRoot, SelNodeChild } from '../shared/models/RTLconfig'; import { ErrorPayload } from '../shared/models/errorPayload'; @@ -95,13 +95,17 @@ export const SET_FORWARDING_HISTORY = 'SET_FORWARDING_HISTORY'; export const GET_QUERY_ROUTES = 'GET_QUERY_ROUTES'; export const SET_QUERY_ROUTES = 'SET_QUERY_ROUTES'; +export const RESET_CL_STORE = 'RESET_CL_STORE'; +export const CLEAR_EFFECT_ERROR_CL = 'CLEAR_EFFECT_ERROR_CL'; +export const EFFECT_ERROR_CL = 'EFFECT_ERROR_CL'; export const FETCH_CL_INFO = 'FETCH_CL_INFO'; export const SET_CL_INFO = 'SET_CL_INFO'; export const FETCH_CL_FEES = 'FETCH_CL_FEES'; export const SET_CL_FEES = 'SET_CL_FEES'; -export const RESET_CL_STORE = 'RESET_CL_STORE'; -export const CLEAR_EFFECT_ERROR_CL = 'CLEAR_EFFECT_ERROR_CL'; -export const EFFECT_ERROR_CL = 'EFFECT_ERROR_CL'; +export const FETCH_CL_BALANCE = 'FETCH_CL_BALANCE'; +export const SET_CL_BALANCE = 'SET_CL_BALANCE'; +export const FETCH_CL_LOCAL_REMOTE_BALANCE = 'FETCH_CL_LOCAL_REMOTE_BALANCE'; +export const SET_CL_LOCAL_REMOTE_BALANCE = 'SET_CL_LOCAL_REMOTE_BALANCE'; export class ClearEffectErrorRoot implements Action { readonly type = CLEAR_EFFECT_ERROR_ROOT; @@ -528,6 +532,24 @@ export class FetchCLFees implements Action { export class SetCLFees implements Action { readonly type = SET_CL_FEES; + constructor(public payload: FeesCL) {} +} + +export class FetchCLBalance implements Action { + readonly type = FETCH_CL_BALANCE; +} + +export class SetCLBalance implements Action { + readonly type = SET_CL_BALANCE; + constructor(public payload: {}) {} +} + +export class FetchCLLocalRemoteBalance implements Action { + readonly type = FETCH_CL_LOCAL_REMOTE_BALANCE; +} + +export class SetCLLocalRemoteBalance implements Action { + readonly type = SET_CL_LOCAL_REMOTE_BALANCE; constructor(public payload: {}) {} } @@ -554,4 +576,5 @@ export type RTLActions = GenSeed | GenSeedResponse | InitWallet | InitWalletResponse | UnlockWallet | FetchConfig | ShowConfig | PeerLookup | ChannelLookup | InvoiceLookup | SetLookup | IsAuthorized | IsAuthorizedRes | Signin | Signout | InitAppData | - FetchCLInfo | SetCLInfo | FetchCLFees | SetCLFees; + FetchCLInfo | SetCLInfo | FetchCLFees | SetCLFees | + FetchCLBalance | SetCLBalance | FetchCLLocalRemoteBalance | SetCLLocalRemoteBalance; diff --git a/src/app/store/rtl.effects.ts b/src/app/store/rtl.effects.ts index 6dc48b16..d9a2a489 100644 --- a/src/app/store/rtl.effects.ts +++ b/src/app/store/rtl.effects.ts @@ -147,7 +147,7 @@ export class RTLEffects implements OnDestroy { ); @Effect({ dispatch: false }) - showLNDConfig = this.actions$.pipe( + showLnConfig = this.actions$.pipe( ofType(RTLActions.SHOW_CONFIG), map((action: RTLActions.ShowConfig) => { return action.payload; @@ -204,9 +204,11 @@ export class RTLEffects implements OnDestroy { this.logger.info('Successfully Authorized!'); this.SetToken(postRes.token); if(rootStore.selNode.lnImplementation.toLowerCase() === 'clightning') { - this.router.navigate(['/cl/']); + this.store.dispatch(new RTLActions.FetchCLInfo()); + this.router.navigate(['/cl/home']); } else { - this.router.navigate(['/lnd/']); + this.store.dispatch(new RTLActions.FetchInfo()); + this.router.navigate(['/lnd/home']); } }), catchError((err) => { @@ -258,12 +260,15 @@ export class RTLEffects implements OnDestroy { if(action.payload.lnImplementation.toLowerCase() === 'clightning') { this.router.navigate(['/cl/home']); this.CHILD_API_URL = API_URL + '/cl'; - return { type: RTLActions.FETCH_CL_INFO }; + return { + type: RTLActions.FETCH_CL_INFO + } } else { this.router.navigate(['/lnd/home']); this.CHILD_API_URL = API_URL + '/lnd'; - this.store.dispatch(new RTLActions.FetchInfo()); - return { type: RTLActions.FETCH_INFO }; + return { + type: RTLActions.FETCH_INFO + } } } else { return { diff --git a/src/app/store/rtl.reducers.ts b/src/app/store/rtl.reducers.ts index 4cd4c853..42b2ec86 100644 --- a/src/app/store/rtl.reducers.ts +++ b/src/app/store/rtl.reducers.ts @@ -14,7 +14,7 @@ export interface RootState { } const initNodeSettings = { flgSidenavOpened: true, flgSidenavPinned: true, menu: 'Vertical', menuType: 'Regular', theme: 'dark-blue', satsToBTC: false, channelBackupPath: '' }; -const initNodeAuthentication = { nodeAuthType: 'CUSTOM', lndConfigPath: '', bitcoindConfigPath: '' }; +const initNodeAuthentication = { nodeAuthType: 'CUSTOM', configPath: '', bitcoindConfigPath: '' }; const initRootState: RootState = { effectErrorsRoot: [],