You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
8.0 KiB
317 lines
8.0 KiB
import { createSelector } from 'reselect'
|
|
import { ipcRenderer } from 'electron'
|
|
import { bech32 } from 'lib/utils'
|
|
|
|
// ------------------------------------
|
|
// Constants
|
|
// ------------------------------------
|
|
export const GET_DESCRIBE_NETWORK = 'GET_DESCRIBE_NETWORK'
|
|
export const RECEIVE_DESCRIBE_NETWORK = 'RECEIVE_DESCRIBE_NETWORK'
|
|
|
|
export const GET_QUERY_ROUTES = 'GET_QUERY_ROUTES'
|
|
export const RECEIVE_QUERY_ROUTES = 'RECEIVE_QUERY_ROUTES'
|
|
|
|
export const SET_CURRENT_ROUTE = 'SET_CURRENT_ROUTE'
|
|
|
|
export const SET_CURRENT_CHANNEL = 'SET_CURRENT_CHANNEL'
|
|
|
|
export const SET_CURRENT_TAB = 'SET_CURRENT_TAB'
|
|
|
|
export const SET_CURRENT_PEER = 'SET_CURRENT_PEER'
|
|
|
|
export const UPDATE_PAY_REQ = 'UPDATE_PAY_REQ'
|
|
export const RESET_PAY_REQ = 'RESET_PAY_REQ'
|
|
|
|
export const UPDATE_SELECTED_PEERS = 'UPDATE_SELECTED_PEERS'
|
|
export const CLEAR_SELECTED_PEERS = 'CLEAR_SELECTED_PEERS'
|
|
|
|
export const UPDATE_SELECTED_CHANNELS = 'UPDATE_SELECTED_CHANNELS'
|
|
export const CLEAR_SELECTED_CHANNELS = 'CLEAR_SELECTED_CHANNELS'
|
|
|
|
export const GET_INFO_AND_QUERY_ROUTES = 'GET_INFO_AND_QUERY_ROUTES'
|
|
export const RECEIVE_INFO_AND_QUERY_ROUTES = 'RECEIVE_INFO_AND_QUERY_ROUTES'
|
|
export const CLEAR_QUERY_ROUTES = 'CLEAR_QUERY_ROUTES'
|
|
|
|
// ------------------------------------
|
|
// Actions
|
|
// ------------------------------------
|
|
export function getDescribeNetwork() {
|
|
return {
|
|
type: GET_DESCRIBE_NETWORK
|
|
}
|
|
}
|
|
|
|
export function getQueryRoutes(pubkey) {
|
|
return {
|
|
type: GET_QUERY_ROUTES,
|
|
pubkey
|
|
}
|
|
}
|
|
|
|
export function setCurrentRoute(route) {
|
|
return {
|
|
type: SET_CURRENT_ROUTE,
|
|
route
|
|
}
|
|
}
|
|
|
|
export function setCurrentChannel(selectedChannel) {
|
|
return {
|
|
type: SET_CURRENT_CHANNEL,
|
|
selectedChannel
|
|
}
|
|
}
|
|
|
|
export function setCurrentTab(currentTab) {
|
|
return {
|
|
type: SET_CURRENT_TAB,
|
|
currentTab
|
|
}
|
|
}
|
|
|
|
export function setCurrentPeer(currentPeer) {
|
|
return {
|
|
type: SET_CURRENT_PEER,
|
|
currentPeer
|
|
}
|
|
}
|
|
|
|
export function updatePayReq(pay_req) {
|
|
return {
|
|
type: UPDATE_PAY_REQ,
|
|
pay_req
|
|
}
|
|
}
|
|
|
|
export function resetPayReq() {
|
|
return {
|
|
type: RESET_PAY_REQ
|
|
}
|
|
}
|
|
|
|
export function updateSelectedPeers(peer) {
|
|
return {
|
|
type: UPDATE_SELECTED_PEERS,
|
|
peer
|
|
}
|
|
}
|
|
|
|
export function updateSelectedChannels(channel) {
|
|
return {
|
|
type: UPDATE_SELECTED_CHANNELS,
|
|
channel
|
|
}
|
|
}
|
|
|
|
export function getInvoiceAndQueryRoutes() {
|
|
return {
|
|
type: GET_INFO_AND_QUERY_ROUTES
|
|
}
|
|
}
|
|
|
|
export function clearQueryRoutes() {
|
|
return {
|
|
type: CLEAR_QUERY_ROUTES
|
|
}
|
|
}
|
|
|
|
export function clearSelectedPeers() {
|
|
return {
|
|
type: CLEAR_SELECTED_PEERS
|
|
}
|
|
}
|
|
|
|
export function clearSelectedChannels() {
|
|
return {
|
|
type: CLEAR_SELECTED_CHANNELS
|
|
}
|
|
}
|
|
|
|
// Send IPC event for describeNetwork
|
|
export const fetchDescribeNetwork = () => dispatch => {
|
|
dispatch(getDescribeNetwork())
|
|
ipcRenderer.send('lnd', { msg: 'describeNetwork' })
|
|
}
|
|
|
|
// Receive IPC event for describeNetwork
|
|
export const receiveDescribeNetwork = (event, { nodes, edges }) => dispatch =>
|
|
dispatch({ type: RECEIVE_DESCRIBE_NETWORK, nodes, edges })
|
|
|
|
export const queryRoutes = (pubkey, amount) => dispatch => {
|
|
dispatch(getQueryRoutes(pubkey))
|
|
ipcRenderer.send('lnd', { msg: 'queryRoutes', data: { pubkey, amount } })
|
|
}
|
|
|
|
export const receiveQueryRoutes = (event, { routes }) => dispatch =>
|
|
dispatch({ type: RECEIVE_QUERY_ROUTES, routes })
|
|
|
|
// take a payreq and query routes for it
|
|
export const fetchInvoiceAndQueryRoutes = payreq => dispatch => {
|
|
dispatch(getInvoiceAndQueryRoutes())
|
|
ipcRenderer.send('lnd', { msg: 'getInvoiceAndQueryRoutes', data: { payreq } })
|
|
}
|
|
|
|
export const receiveInvoiceAndQueryRoutes = (event, { routes }) => dispatch =>
|
|
dispatch({ type: RECEIVE_INFO_AND_QUERY_ROUTES, routes })
|
|
|
|
// ------------------------------------
|
|
// Action Handlers
|
|
// ------------------------------------
|
|
const ACTION_HANDLERS = {
|
|
[GET_DESCRIBE_NETWORK]: state => ({ ...state, networkLoading: true }),
|
|
[RECEIVE_DESCRIBE_NETWORK]: (state, { nodes, edges }) => ({
|
|
...state,
|
|
networkLoading: false,
|
|
nodes,
|
|
edges
|
|
}),
|
|
|
|
[GET_QUERY_ROUTES]: (state, { pubkey }) => ({
|
|
...state,
|
|
networkLoading: true,
|
|
selectedNode: { pubkey, routes: [], currentRoute: {} }
|
|
}),
|
|
[RECEIVE_QUERY_ROUTES]: (state, { routes }) => ({
|
|
...state,
|
|
networkLoading: false,
|
|
selectedNode: { pubkey: state.selectedNode.pubkey, routes, currentRoute: routes[0] }
|
|
}),
|
|
|
|
[SET_CURRENT_ROUTE]: (state, { route }) => ({ ...state, currentRoute: route }),
|
|
|
|
[SET_CURRENT_CHANNEL]: (state, { selectedChannel }) => ({ ...state, selectedChannel }),
|
|
|
|
[SET_CURRENT_TAB]: (state, { currentTab }) => ({ ...state, currentTab }),
|
|
|
|
[SET_CURRENT_PEER]: (state, { currentPeer }) => ({ ...state, currentPeer }),
|
|
|
|
[UPDATE_PAY_REQ]: (state, { pay_req }) => ({ ...state, pay_req }),
|
|
[RESET_PAY_REQ]: state => ({ ...state, pay_req: '' }),
|
|
|
|
[GET_INFO_AND_QUERY_ROUTES]: state => ({ ...state, fetchingInvoiceAndQueryingRoutes: true }),
|
|
[RECEIVE_INFO_AND_QUERY_ROUTES]: (state, { routes }) => ({
|
|
...state,
|
|
fetchingInvoiceAndQueryingRoutes: false,
|
|
payReqRoutes: routes
|
|
}),
|
|
[CLEAR_QUERY_ROUTES]: state => ({ ...state, payReqRoutes: [], currentRoute: {} }),
|
|
|
|
[UPDATE_SELECTED_PEERS]: (state, { peer }) => {
|
|
let selectedPeers
|
|
|
|
if (state.selectedPeers.includes(peer)) {
|
|
selectedPeers = state.selectedPeers.filter(
|
|
selectedPeer => selectedPeer.pub_key !== peer.pub_key
|
|
)
|
|
}
|
|
|
|
if (!state.selectedPeers.includes(peer)) {
|
|
selectedPeers = [...state.selectedPeers, peer]
|
|
}
|
|
|
|
return {
|
|
...state,
|
|
selectedPeers
|
|
}
|
|
},
|
|
[CLEAR_SELECTED_PEERS]: state => ({ ...state, selectedPeers: [] }),
|
|
|
|
[UPDATE_SELECTED_CHANNELS]: (state, { channel }) => {
|
|
let selectedChannels
|
|
|
|
if (state.selectedChannels.includes(channel)) {
|
|
selectedChannels = state.selectedChannels.filter(
|
|
selectedChannel => selectedChannel.chan_id !== channel.chan_id
|
|
)
|
|
}
|
|
|
|
if (!state.selectedChannels.includes(channel)) {
|
|
selectedChannels = [...state.selectedChannels, channel]
|
|
}
|
|
|
|
return {
|
|
...state,
|
|
selectedChannels
|
|
}
|
|
},
|
|
[CLEAR_SELECTED_CHANNELS]: state => ({ ...state, selectedChannels: [] })
|
|
}
|
|
|
|
// ------------------------------------
|
|
// Selectors
|
|
// ------------------------------------
|
|
const networkSelectors = {}
|
|
const selectedPeersSelector = state => state.network.selectedPeers
|
|
const selectedChannelsSelector = state => state.network.selectedChannels
|
|
const payReqSelector = state => state.network.pay_req
|
|
const currentRouteSelector = state => state.network.currentRoute
|
|
|
|
// networkSelectors.currentRouteHopChanIds = createSelector(
|
|
// currentRouteSelector,
|
|
// (currentRoute) => {
|
|
// if (!currentRoute.hops) { return [] }
|
|
|
|
// return currentRoute.hops.map(hop => hop.chan_id)
|
|
// }
|
|
// )
|
|
|
|
networkSelectors.selectedPeerPubkeys = createSelector(selectedPeersSelector, peers =>
|
|
peers.map(peer => peer.pub_key)
|
|
)
|
|
|
|
networkSelectors.selectedChannelIds = createSelector(selectedChannelsSelector, channels =>
|
|
channels.map(channel => channel.chan_id)
|
|
)
|
|
|
|
networkSelectors.payReqIsLn = createSelector(payReqSelector, input => {
|
|
if (!input.startsWith('ln')) {
|
|
return false
|
|
}
|
|
|
|
try {
|
|
bech32.decode(input)
|
|
return true
|
|
} catch (e) {
|
|
return false
|
|
}
|
|
})
|
|
|
|
networkSelectors.currentRouteChanIds = createSelector(currentRouteSelector, route => {
|
|
if (!route.hops || !route.hops.length) {
|
|
return []
|
|
}
|
|
|
|
return route.hops.map(hop => hop.chan_id)
|
|
})
|
|
|
|
export { networkSelectors }
|
|
|
|
// ------------------------------------
|
|
// Initial State
|
|
// ------------------------------------
|
|
const initialState = {
|
|
networkLoading: false,
|
|
nodes: [],
|
|
edges: [],
|
|
selectedChannel: {},
|
|
|
|
currentTab: 1,
|
|
|
|
currentPeer: {},
|
|
currentRoute: {},
|
|
|
|
fetchingInvoiceAndQueryingRoutes: false,
|
|
pay_req: '',
|
|
payReqRoutes: [],
|
|
selectedPeers: [],
|
|
selectedChannels: []
|
|
}
|
|
|
|
// ------------------------------------
|
|
// Reducer
|
|
// ------------------------------------
|
|
export default function activityReducer(state = initialState, action) {
|
|
const handler = ACTION_HANDLERS[action.type]
|
|
|
|
return handler ? handler(state, action) : state
|
|
}
|
|
|