CL Home
This commit is contained in:
Shahana Farooqui 2019-09-02 00:11:37 -04:00
parent 68ccf961d8
commit 1321ff071f
43 changed files with 601 additions and 236 deletions

4
app.js
View File

@ -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"));

View File

@ -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 = () => {

View File

@ -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')}

View File

@ -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;

View File

@ -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 });

View File

@ -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
});
});
};

View File

@ -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
});
});
};

View File

@ -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;

View File

@ -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);
}
})

View File

@ -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)});

View File

@ -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,

View File

@ -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 = '';

View File

@ -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) {

View File

@ -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 {

View File

@ -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) {

View File

@ -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');

View File

@ -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,

View File

@ -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');

View File

@ -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');

View File

@ -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');

View File

@ -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) {

View File

@ -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;

View File

@ -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,

View File

@ -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'),

View File

@ -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;

View File

@ -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;

View File

@ -19,28 +19,19 @@ export class CLRootComponent implements OnInit, OnDestroy {
constructor(private store: Store<fromRTLReducer.RTLState>, 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() {

View File

@ -1,25 +1,150 @@
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="25" class="padding-gap">
<div fxLayout="column">
<mat-card fxFlex="100" [ngClass]="{'custom-card error-border': flgLoading[1]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Fee Report</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="column" class="pl-4">
<mat-list fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start"> Fee Collected </mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{fees?.feeCollected}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
</div>
<mat-progress-bar *ngIf="flgLoading[1]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
<div fxFlex="20" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[2]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center end">
<mat-card-title class="m-0 pt-2">
<h5>Wallet Balance</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">account_balance_wallet</mat-icon>
</mat-card-content>
</mat-card>
</div>
<span *ngIf="information?.currency_unit; else withoutData">
<h3 *ngIf="selNode?.satsToBTC; else smallerUnit1">{{totalBalance.btc_confBalance | number}}
{{information?.currency_unit}}</h3>
<ng-template #smallerUnit1>
<h3>{{totalBalance.confBalance | number}} {{information?.smaller_currency_unit}}</h3>
</ng-template>
</span>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[2]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
<div fxFlex="20" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[0]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Peers</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">group</mat-icon>
</mat-card-content>
<h3 *ngIf="information.num_peers; else zeroPeers">{{information?.num_peers | number}}</h3>
<ng-template #zeroPeers>
<h3>0</h3>
</ng-template>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
<div fxFlex="20" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[3]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Channel Balance</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">linear_scale</mat-icon>
</mat-card-content>
<span *ngIf="information?.currency_unit; else withoutData">
<h3 *ngIf="selNode?.satsToBTC; else smallerUnit2">{{lrBalance.btc_localBalance | number}}
{{information?.currency_unit}}</h3>
<ng-template #smallerUnit2>
<h3>{{lrBalance.localBalance | number}} {{information?.smaller_currency_unit}}</h3>
</ng-template>
</span>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[3]===true || flgLoading[0]===true" mode="indeterminate">
</mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
<div fxFlex="20" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[1]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Fee Report</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">redeem</mat-icon>
</mat-card-content>
<h3>{{fees?.feeCollected | number}} (mSats)</h3>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[1]===true || flgLoading[0]===true" mode="indeterminate">
</mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
<div fxFlex="20" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[0]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Channel Status</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="column" class="pl-4">
<mat-list class="channel-status-list" fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Active</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="start start">
<p class="mat-button-text">{{information?.num_active_channels}}</p>
</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list class="channel-status-list" fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Inactive</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="start start">
<p class="mat-button-text">{{information?.num_inactive_channels}}</p>
</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list class="channel-status-list" fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Pending</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="start start">
<p class="mat-button-text">{{information?.num_pending_channels}}</p>
</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
</div>
<mat-progress-bar *ngIf="flgLoading[6]===true" mode="indeterminate" class="mt-minus-5"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card-content>
</mat-card>
</div>
</div>
<ng-template #withoutData><h3>Sats</h3></ng-template>
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="25" class="padding-gap"></div>
<div fxFlex="50" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[3]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Local-Remote Channel Capacity</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="row" class="card-chnl-balances">
<div fxFlex="100" fxLayoutAlign="center center">
<ngx-charts-bar-vertical [view]="view" [scheme]="colorScheme" [results]="lrBalances"
[yAxisLabel]="yAxisLabel" [yScaleMax]="maxBalanceValue" xAxis="false" yAxis="true" showYAxis="true"
showDataLabel="true" tooltipDisabled="true">
</ngx-charts-bar-vertical>
</div>
</div>
<mat-progress-bar *ngIf="flgLoading[5]===true" mode="indeterminate" class="mt-minus-5"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card-content>
</mat-card>
</div>
</div>
<ng-template #withoutData>
<h3>Sats</h3>
</ng-template>

View File

@ -10,3 +10,7 @@
.card-chnl-balances {
min-height: 354px;
}
.channel-status-list {
max-height: 46px !important;
}

View File

@ -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<Boolean | 'error'> = [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<Boolean | 'error'> = [true, true, true, true];
private unsub: Array<Subject<void>> = [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<fromRTLReducer.RTLState>) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>) {
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() {

View File

@ -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<fromRTLReducer.RTLState>,
private logger: LoggerService) { }
constructor(
private actions$: Actions,
private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>,
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<GetInfoCL>(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<GetInfoCL>(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<FeesCL>(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<FeesCL>(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<BalanceCL>(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<LocalRemoteBalanceCL>(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() { }
}

View File

@ -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;
}

View File

@ -19,7 +19,6 @@ export class LNDRootComponent implements OnInit, OnDestroy {
constructor(private store: Store<fromRTLReducer.RTLState>, 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) => {

View File

@ -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),

View File

@ -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: {},

View File

@ -10,7 +10,7 @@
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-md="row wrap" class="mb-2">
<mat-radio-group fxFlex="20" fxLayoutAlign="start" (change)="onSelectionChange($event)" class="mt-1 mb-1">
<mat-radio-button class="pr-5" value="rtl" [checked]="selectedNodeType=='rtl'">RTL</mat-radio-button>
<mat-radio-button class="pr-5" value="lnd" *ngIf="showLND" [checked]="selectedNodeType=='lnd'">LND</mat-radio-button>
<mat-radio-button class="pr-5" value="ln" *ngIf="showLnConfig" [checked]="selectedNodeType=='ln'">{{lnImplementationStr}}</mat-radio-button>
<mat-radio-button class="pr-5" value="bitcoind" *ngIf="showBitcoind" [checked]="selectedNodeType=='bitcoind'">BITCOIND</mat-radio-button>
</mat-radio-group>
<div fxFlex="30" fxLayoutAlign="space-between stretch">

View File

@ -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;

View File

@ -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
) { }
}

View File

@ -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;
}

View File

@ -65,8 +65,7 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
QRCodeModule,
NgxChartsModule,
RouterModule,
HttpClientModule,
NgxChartsModule
HttpClientModule
],
exports: [
FormsModule,

View File

@ -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;

View File

@ -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 {

View File

@ -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: [],