Update wallet logging + other stuff
* add canPay and canSend to wallet definition * rename 'default payment method' to 'enabled' and add enable + disable method
This commit is contained in:
parent
a1b343ac89
commit
6ac8785c51
|
@ -228,8 +228,13 @@ export const WalletLoggerProvider = ({ children }) => {
|
|||
const index = store.index('ts')
|
||||
const request = index.getAll()
|
||||
request.onsuccess = () => {
|
||||
const logs = request.result
|
||||
let logs = request.result
|
||||
setLogs((prevLogs) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// in dev mode, useEffect runs twice, so we filter out duplicates here
|
||||
const existingIds = prevLogs.map(({ id }) => id)
|
||||
logs = logs.filter(({ id }) => !existingIds.includes(id))
|
||||
}
|
||||
// sort oldest first to keep same order as logs are appended
|
||||
return [...prevLogs, ...logs].sort((a, b) => a.ts - b.ts)
|
||||
})
|
||||
|
@ -254,16 +259,16 @@ export const WalletLoggerProvider = ({ children }) => {
|
|||
}, [saveLog])
|
||||
|
||||
const deleteLogs = useCallback(async (walletName) => {
|
||||
const wallet = getWalletByName(walletName, me)
|
||||
const wallet = walletName ? getWalletByName(walletName, me) : null
|
||||
|
||||
if (!walletName || wallet.server) {
|
||||
if (!wallet || wallet.canReceive) {
|
||||
await deleteServerWalletLogs({ variables: { wallet: wallet?.type } })
|
||||
}
|
||||
if (!walletName || !wallet.server) {
|
||||
if (!wallet || wallet.canPay) {
|
||||
const tx = idb.current.transaction(idbStoreName, 'readwrite')
|
||||
const objectStore = tx.objectStore(idbStoreName)
|
||||
const idx = objectStore.index('wallet_ts')
|
||||
const request = walletName ? idx.openCursor(window.IDBKeyRange.bound([walletName, -Infinity], [walletName, Infinity])) : idx.openCursor()
|
||||
const request = wallet ? idx.openCursor(window.IDBKeyRange.bound([wallet.name, -Infinity], [wallet.name, Infinity])) : idx.openCursor()
|
||||
request.onsuccess = function (event) {
|
||||
const cursor = event.target.result
|
||||
if (cursor) {
|
||||
|
@ -271,7 +276,7 @@ export const WalletLoggerProvider = ({ children }) => {
|
|||
cursor.continue()
|
||||
} else {
|
||||
// finished
|
||||
setLogs((logs) => logs.filter(l => walletName ? l.wallet !== walletName : false))
|
||||
setLogs((logs) => logs.filter(l => wallet ? l.wallet !== wallet.name : false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,29 +291,33 @@ export const WalletLoggerProvider = ({ children }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export function useWalletLogger (walletName) {
|
||||
export function useWalletLogger (wallet) {
|
||||
const { appendLog, deleteLogs: innerDeleteLogs } = useContext(WalletLoggerContext)
|
||||
|
||||
const log = useCallback(level => message => {
|
||||
if (!wallet) {
|
||||
console.error('cannot log: no wallet set')
|
||||
return
|
||||
}
|
||||
// TODO:
|
||||
// also send this to us if diagnostics was enabled,
|
||||
// very similar to how the service worker logger works.
|
||||
appendLog(walletName, level, message)
|
||||
console[level !== 'error' ? 'info' : 'error'](`[${walletName}]`, message)
|
||||
}, [appendLog, walletName])
|
||||
appendLog(wallet.name, level, message)
|
||||
console[level !== 'error' ? 'info' : 'error'](`[${wallet.name}]`, message)
|
||||
}, [appendLog, wallet?.name])
|
||||
|
||||
const logger = useMemo(() => ({
|
||||
ok: (...message) => log('ok')(message.join(' ')),
|
||||
info: (...message) => log('info')(message.join(' ')),
|
||||
error: (...message) => log('error')(message.join(' '))
|
||||
}), [log, walletName])
|
||||
}), [log, wallet?.name])
|
||||
|
||||
const deleteLogs = useCallback((w) => innerDeleteLogs(w || walletName), [innerDeleteLogs, walletName])
|
||||
const deleteLogs = useCallback((w) => innerDeleteLogs(w?.name || wallet?.name), [innerDeleteLogs, wallet?.name])
|
||||
|
||||
return { logger, deleteLogs }
|
||||
}
|
||||
|
||||
export function useWalletLogs (walletName) {
|
||||
export function useWalletLogs (wallet) {
|
||||
const logs = useContext(WalletLogsContext)
|
||||
return logs.filter(l => !walletName || l.wallet === walletName)
|
||||
return logs.filter(l => !wallet || l.wallet === wallet.name)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useMe } from '@/components/me'
|
|||
import useLocalState from '@/components/use-local-state'
|
||||
import { useWalletLogger } from '@/components/wallet-logger'
|
||||
import { SSR } from '@/lib/constants'
|
||||
import { bolt11Tags } from '@/lib/bolt11'
|
||||
|
||||
// wallet definitions
|
||||
export const WALLET_DEFS = [
|
||||
|
@ -18,25 +19,45 @@ export const Status = {
|
|||
|
||||
export function useWallet (name) {
|
||||
const me = useMe()
|
||||
const { logger } = useWalletLogger(name)
|
||||
|
||||
const wallet = getWalletByName(name, me)
|
||||
const wallet = name ? getWalletByName(name, me) : getEnabledWallet(me)
|
||||
const { logger } = useWalletLogger(wallet)
|
||||
const storageKey = getStorageKey(wallet?.name, me)
|
||||
const [config, saveConfig, clearConfig] = useLocalState(storageKey)
|
||||
|
||||
const isConfigured = !!config
|
||||
|
||||
const sendPayment = useCallback(async (bolt11) => {
|
||||
return await wallet.sendPayment({ bolt11, config, logger })
|
||||
const hash = bolt11Tags(bolt11).payment_hash
|
||||
logger.info('sending payment:', `payment_hash=${hash}`)
|
||||
try {
|
||||
const { preimage } = await wallet.sendPayment({ bolt11, config, logger })
|
||||
logger.ok('payment successful:', `payment_hash=${hash}`, `preimage=${preimage}`)
|
||||
} catch (err) {
|
||||
const message = err.message || err.toString?.()
|
||||
logger.error('payment failed:', `payment_hash=${hash}`, message)
|
||||
throw err
|
||||
}
|
||||
}, [wallet, config, logger])
|
||||
|
||||
const validate = useCallback(async (values) => {
|
||||
return await wallet.validate({ logger, ...values })
|
||||
}, [logger])
|
||||
try {
|
||||
// validate should log custom INFO and OK message
|
||||
return await wallet.validate({ logger, ...values })
|
||||
} catch (err) {
|
||||
const message = err.message || err.toString?.()
|
||||
logger.error(message)
|
||||
throw err
|
||||
}
|
||||
}, [wallet, logger])
|
||||
|
||||
const enable = useCallback(() => {
|
||||
enableWallet(name, me)
|
||||
}, [name, me])
|
||||
logger.ok('wallet enabled')
|
||||
}, [name, me, logger])
|
||||
|
||||
const disable = useCallback(() => {
|
||||
disableWallet(name, me)
|
||||
logger.ok('wallet disabled')
|
||||
}, [name, me, logger])
|
||||
|
||||
return {
|
||||
...wallet,
|
||||
|
@ -46,15 +67,22 @@ export function useWallet (name) {
|
|||
saveConfig,
|
||||
clearConfig,
|
||||
enable,
|
||||
isConfigured,
|
||||
status: config?.enabled ? Status.Enabled : Status.Initialized
|
||||
disable,
|
||||
isConfigured: !!config,
|
||||
status: config?.enabled ? Status.Enabled : Status.Initialized,
|
||||
logger
|
||||
}
|
||||
}
|
||||
|
||||
export function getWalletByName (name, me) {
|
||||
return name
|
||||
? WALLET_DEFS.find(def => def.name === name)
|
||||
: WALLET_DEFS.find(def => {
|
||||
return WALLET_DEFS.find(def => def.name === name)
|
||||
}
|
||||
|
||||
export function getEnabledWallet (me) {
|
||||
// TODO: handle multiple enabled wallets
|
||||
return WALLET_DEFS
|
||||
.filter(def => def.canPay)
|
||||
.find(def => {
|
||||
const key = getStorageKey(def.name, me)
|
||||
const config = SSR ? null : JSON.parse(window?.localStorage.getItem(key))
|
||||
return config?.enabled
|
||||
|
@ -70,6 +98,7 @@ function getStorageKey (name, me) {
|
|||
}
|
||||
|
||||
function enableWallet (name, me) {
|
||||
// mark all wallets as disabled except the one to enable
|
||||
for (const walletDef of WALLET_DEFS) {
|
||||
const toEnable = walletDef.name === name
|
||||
const key = getStorageKey(name, me)
|
||||
|
@ -80,3 +109,11 @@ function enableWallet (name, me) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function disableWallet (name, me) {
|
||||
const key = getStorageKey(name, me)
|
||||
const config = JSON.parse(window.localStorage.getItem(key))
|
||||
if (!config) return
|
||||
config.enabled = false
|
||||
window.localStorage.setItem(key, JSON.stringify(config))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { bolt11Tags } from '@/lib/bolt11'
|
||||
|
||||
export const name = 'lnbits'
|
||||
|
||||
export const canPay = true
|
||||
export const canReceive = false
|
||||
|
||||
export const fields = [
|
||||
{
|
||||
name: 'url',
|
||||
|
@ -25,7 +26,9 @@ export async function validate ({ logger, ...config }) {
|
|||
}
|
||||
|
||||
async function getInfo ({ logger, ...config }) {
|
||||
logger.info('trying to fetch wallet')
|
||||
const response = await getWallet(config.url, config.adminKey)
|
||||
logger.ok('wallet found')
|
||||
return {
|
||||
node: {
|
||||
alias: response.name,
|
||||
|
@ -41,27 +44,18 @@ async function getInfo ({ logger, ...config }) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function sendPayment ({ bolt11, config, logger }) {
|
||||
export async function sendPayment ({ bolt11, config }) {
|
||||
const { url, adminKey } = config
|
||||
|
||||
const hash = bolt11Tags(bolt11).payment_hash
|
||||
logger.info('sending payment:', `payment_hash=${hash}`)
|
||||
const response = await postPayment(url, adminKey, bolt11)
|
||||
|
||||
try {
|
||||
const response = await postPayment(url, adminKey, bolt11)
|
||||
|
||||
const checkResponse = await getPayment(url, adminKey, response.payment_hash)
|
||||
if (!checkResponse.preimage) {
|
||||
throw new Error('No preimage')
|
||||
}
|
||||
|
||||
const preimage = checkResponse.preimage
|
||||
logger.ok('payment successful:', `payment_hash=${hash}`, `preimage=${preimage}`)
|
||||
return { preimage }
|
||||
} catch (err) {
|
||||
logger.error('payment failed:', `payment_hash=${hash}`, err.message || err.toString?.())
|
||||
throw err
|
||||
const checkResponse = await getPayment(url, adminKey, response.payment_hash)
|
||||
if (!checkResponse.preimage) {
|
||||
throw new Error('No preimage')
|
||||
}
|
||||
|
||||
const preimage = checkResponse.preimage
|
||||
return { preimage }
|
||||
}
|
||||
|
||||
async function getWallet (baseUrl, adminKey) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { WalletSecurityBanner } from '@/components/banners'
|
|||
import { WalletLogs } from '@/components/wallet-logger'
|
||||
import { useToast } from '@/components/toast'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useWallet } from '@/components/wallet'
|
||||
import { useWallet, Status } from '@/components/wallet'
|
||||
|
||||
export const getServerSideProps = getGetServerSideProps({ authRequired: true })
|
||||
|
||||
|
@ -34,25 +34,27 @@ export default function WalletSettings () {
|
|||
<Form
|
||||
initial={initial}
|
||||
schema={lnbitsSchema}
|
||||
onSubmit={async ({ isDefault, ...values }) => {
|
||||
onSubmit={async ({ enabled, ...values }) => {
|
||||
try {
|
||||
await wallet.validate(values)
|
||||
wallet.saveConfig(values)
|
||||
wallet.enable()
|
||||
if (enabled) wallet.enable()
|
||||
else wallet.disable()
|
||||
toaster.success('saved settings')
|
||||
router.push('/settings/wallets')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
toaster.danger('failed to attach: ' + err.message || err.toString?.())
|
||||
const message = 'failed to attach: ' + err.message || err.toString?.()
|
||||
toaster.danger(message)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<WalletFields wallet={wallet} />
|
||||
<ClientCheckbox
|
||||
disabled={false}
|
||||
initialValue={false}
|
||||
label='default payment method'
|
||||
name='isDefault'
|
||||
initialValue={wallet.status === Status.Enabled}
|
||||
label='enabled'
|
||||
name='enabled'
|
||||
/>
|
||||
<WalletButtonBar
|
||||
wallet={wallet} onDelete={async () => {
|
||||
|
@ -62,7 +64,9 @@ export default function WalletSettings () {
|
|||
router.push('/settings/wallets')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
toaster.danger('failed to detach: ' + err.message || err.toString?.())
|
||||
const message = 'failed to detach: ' + err.message || err.toString?.()
|
||||
wallet.logger.error(message)
|
||||
toaster.danger(message)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { CenterLayout } from '@/components/layout'
|
||||
import { getGetServerSideProps } from '@/api/ssrApollo'
|
||||
import { WalletLogs } from '@/components/wallet-logs'
|
||||
import { WalletLogs } from '@/components/wallet-logger'
|
||||
|
||||
export const getServerSideProps = getGetServerSideProps({ query: null })
|
||||
|
||||
|
|
Loading…
Reference in New Issue