bump version to 0.0.5
This commit is contained in:
@@ -4,7 +4,7 @@ export default {
|
|||||||
app: {
|
app: {
|
||||||
name: 'koins',
|
name: 'koins',
|
||||||
identifier: 'koins.tzgyn.com',
|
identifier: 'koins.tzgyn.com',
|
||||||
version: '0.0.4',
|
version: '0.0.5',
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
// Vite builds to dist/, we copy from there
|
// Vite builds to dist/, we copy from there
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import {
|
import { MoneroWalletRpc, MoneroRpcConnection, connectToWalletRpc, connectToDaemonRpc } from 'monero-ts'
|
||||||
MoneroWalletRpc,
|
|
||||||
MoneroRpcConnection,
|
|
||||||
connectToWalletRpc,
|
|
||||||
connectToDaemonRpc,
|
|
||||||
} from 'monero-ts'
|
|
||||||
import { getBinaryPath, getWalletDir } from './binary'
|
import { getBinaryPath, getWalletDir } from './binary'
|
||||||
import { existsSync, readdirSync } from 'fs'
|
import { existsSync, readdirSync } from 'fs'
|
||||||
|
import { log, logError } from '../logger'
|
||||||
|
|
||||||
const DEFAULT_DAEMON = 'xmr-node.cakewallet.com:18081'
|
const DEFAULT_DAEMON = 'xmr-node.cakewallet.com:18081'
|
||||||
|
|
||||||
@@ -65,20 +61,13 @@ async function waitForRpc(
|
|||||||
let lastErr = ''
|
let lastErr = ''
|
||||||
while (Date.now() - start < timeoutMs) {
|
while (Date.now() - start < timeoutMs) {
|
||||||
try {
|
try {
|
||||||
await Bun.connect({
|
const conn = rpcConnection(state)
|
||||||
hostname: '127.0.0.1',
|
const res = await conn.sendJsonRequest('get_version', {})
|
||||||
port: state.rpcPort,
|
if (res?.result?.version) {
|
||||||
socket: {
|
console.log(`[monero] RPC ready after ${Date.now() - start}ms`)
|
||||||
open(s) {
|
return
|
||||||
s.end()
|
}
|
||||||
},
|
lastErr = JSON.stringify(res)
|
||||||
close() {},
|
|
||||||
data() {},
|
|
||||||
error() {},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
console.log(`[monero] RPC ready after ${Date.now() - start}ms`)
|
|
||||||
return
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
lastErr = String(e)
|
lastErr = String(e)
|
||||||
}
|
}
|
||||||
@@ -89,6 +78,28 @@ async function waitForRpc(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function connectClient(
|
||||||
|
state: MoneroWalletState,
|
||||||
|
): Promise<MoneroWalletRpc> {
|
||||||
|
let lastErr = ''
|
||||||
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
||||||
|
try {
|
||||||
|
const client = (await connectToWalletRpc(
|
||||||
|
rpcUrl(state),
|
||||||
|
state.rpcUser,
|
||||||
|
state.rpcPassword,
|
||||||
|
)) as MoneroWalletRpc
|
||||||
|
console.log(`[monero] MoneroWalletRpc connected (attempt ${attempt})`)
|
||||||
|
return client
|
||||||
|
} catch (e) {
|
||||||
|
lastErr = String(e)
|
||||||
|
console.log(`[monero] connectToWalletRpc attempt ${attempt} failed:`, e)
|
||||||
|
if (attempt < 3) await new Promise((r) => setTimeout(r, 1000))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Failed to connect to monero-wallet-rpc: ${lastErr}`)
|
||||||
|
}
|
||||||
|
|
||||||
export async function start(
|
export async function start(
|
||||||
state: MoneroWalletState,
|
state: MoneroWalletState,
|
||||||
daemonAddress: string = DEFAULT_DAEMON,
|
daemonAddress: string = DEFAULT_DAEMON,
|
||||||
@@ -169,6 +180,9 @@ export async function start(
|
|||||||
`[monero] wallet-rpc process exited with code ${exitCode}`,
|
`[monero] wallet-rpc process exited with code ${exitCode}`,
|
||||||
error?.message ?? '',
|
error?.message ?? '',
|
||||||
)
|
)
|
||||||
|
log(
|
||||||
|
`[monero] wallet-rpc process exited with code ${exitCode} ${error?.message ?? ''}`,
|
||||||
|
)
|
||||||
if (state.saveTimer) {
|
if (state.saveTimer) {
|
||||||
clearInterval(state.saveTimer)
|
clearInterval(state.saveTimer)
|
||||||
state.saveTimer = null
|
state.saveTimer = null
|
||||||
@@ -222,12 +236,9 @@ export async function start(
|
|||||||
console.log(`[monero] RPC server is ready`)
|
console.log(`[monero] RPC server is ready`)
|
||||||
|
|
||||||
console.log(`[monero] connecting MoneroWalletRpc client...`)
|
console.log(`[monero] connecting MoneroWalletRpc client...`)
|
||||||
state.wallet = (await connectToWalletRpc(
|
state.wallet = await connectClient(state)
|
||||||
rpcUrl(state),
|
|
||||||
state.rpcUser,
|
|
||||||
state.rpcPassword,
|
|
||||||
)) as MoneroWalletRpc
|
|
||||||
console.log(`[monero] MoneroWalletRpc connected successfully`)
|
console.log(`[monero] MoneroWalletRpc connected successfully`)
|
||||||
|
log(`[monero] wallet-rpc started, RPC ready`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function stop(state: MoneroWalletState) {
|
export async function stop(state: MoneroWalletState) {
|
||||||
@@ -241,6 +252,7 @@ export async function stop(state: MoneroWalletState) {
|
|||||||
if (state.wallet) {
|
if (state.wallet) {
|
||||||
await rawRpc(state, 'store')
|
await rawRpc(state, 'store')
|
||||||
console.log(`[monero] wallet saved before stop`)
|
console.log(`[monero] wallet saved before stop`)
|
||||||
|
log(`[monero] wallet saved before stop`)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`[monero] wallet save before stop failed:`, e)
|
console.log(`[monero] wallet save before stop failed:`, e)
|
||||||
@@ -309,9 +321,20 @@ export async function openWallet(
|
|||||||
password: string,
|
password: string,
|
||||||
) {
|
) {
|
||||||
console.log(`[monero] opening wallet: ${name}`)
|
console.log(`[monero] opening wallet: ${name}`)
|
||||||
if (!state.wallet) throw new Error('Wallet RPC not started')
|
// Self-heal: the client connection may have been lost while the
|
||||||
await state.wallet.openWallet(name, password)
|
// wallet-rpc process is still running (e.g. stale-process cleanup).
|
||||||
console.log(`[monero] wallet opened: ${name}`)
|
if (!state.wallet) {
|
||||||
|
if (!state.process) throw new Error('Wallet RPC not started')
|
||||||
|
log(`[monero] reconnecting wallet client before open (${name})`)
|
||||||
|
state.wallet = await connectClient(state)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await state.wallet.openWallet(name, password)
|
||||||
|
log(`[monero] wallet opened: ${name}`)
|
||||||
|
} catch (e) {
|
||||||
|
logError(`[monero] wallet open failed (${name})`, e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function closeWallet(state: MoneroWalletState) {
|
export async function closeWallet(state: MoneroWalletState) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
isConnected,
|
isConnected,
|
||||||
} from '../../lib/monero'
|
} from '../../lib/monero'
|
||||||
import type { MoneroWalletState } from '../../lib/monero'
|
import type { MoneroWalletState } from '../../lib/monero'
|
||||||
|
import { log, logError } from '../../lib/logger'
|
||||||
|
|
||||||
export function createMoneroHandlers(state: {
|
export function createMoneroHandlers(state: {
|
||||||
manager: MoneroWalletState | null
|
manager: MoneroWalletState | null
|
||||||
@@ -64,10 +65,12 @@ export function createMoneroHandlers(state: {
|
|||||||
await walletStart(state.manager, daemonAddress)
|
await walletStart(state.manager, daemonAddress)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('[rpc] moneroStart error:', e)
|
console.log('[rpc] moneroStart error:', e)
|
||||||
|
logError('[rpc] moneroStart error', e)
|
||||||
return { running: false, walletOpen: false, connected: false }
|
return { running: false, walletOpen: false, connected: false }
|
||||||
}
|
}
|
||||||
const connected = await isConnected(state.manager)
|
const connected = await isConnected(state.manager)
|
||||||
console.log('[rpc] moneroStart complete, connected:', connected)
|
console.log('[rpc] moneroStart complete, connected:', connected)
|
||||||
|
log(`[rpc] moneroStart complete, connected: ${connected}`)
|
||||||
return { running: true, walletOpen: false, connected }
|
return { running: true, walletOpen: false, connected }
|
||||||
},
|
},
|
||||||
moneroStop: async () => {
|
moneroStop: async () => {
|
||||||
@@ -129,7 +132,13 @@ export function createMoneroHandlers(state: {
|
|||||||
console.log('[rpc] moneroOpenWallet:', name)
|
console.log('[rpc] moneroOpenWallet:', name)
|
||||||
if (!state.manager)
|
if (!state.manager)
|
||||||
throw new Error('Monero wallet RPC not started')
|
throw new Error('Monero wallet RPC not started')
|
||||||
await walletOpen(state.manager, name, password)
|
try {
|
||||||
|
await walletOpen(state.manager, name, password)
|
||||||
|
log(`[rpc] moneroOpenWallet ok: ${name}`)
|
||||||
|
} catch (e) {
|
||||||
|
logError(`[rpc] moneroOpenWallet failed (${name})`, e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
},
|
},
|
||||||
moneroGetBalance: async () => {
|
moneroGetBalance: async () => {
|
||||||
console.log('[rpc] moneroGetBalance')
|
console.log('[rpc] moneroGetBalance')
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ export const MoneroWallet = () => {
|
|||||||
if (loginInFlight) return loginInFlight
|
if (loginInFlight) return loginInFlight
|
||||||
loginInFlight = (async () => {
|
loginInFlight = (async () => {
|
||||||
accountType = 'monero'
|
accountType = 'monero'
|
||||||
|
error = ''
|
||||||
beginOpening()
|
beginOpening()
|
||||||
try {
|
try {
|
||||||
if (installed && !running) {
|
if (installed && !running) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
let xrpBalances = $state<Record<string, { balance: number; funded: boolean }>>({})
|
let xrpBalances = $state<Record<string, { balance: number; funded: boolean }>>({})
|
||||||
let loadingXrp = $state(true)
|
let loadingXrp = $state(true)
|
||||||
let loadingXmr = $state(true)
|
let loadingXmr = $state(true)
|
||||||
|
let fetchXrpInFlight = false
|
||||||
|
|
||||||
let feError = $state<string | null>(null)
|
let feError = $state<string | null>(null)
|
||||||
|
|
||||||
@@ -70,10 +71,13 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function fetchXrp() {
|
async function fetchXrp() {
|
||||||
|
if (fetchXrpInFlight) return
|
||||||
|
fetchXrpInFlight = true
|
||||||
loadingXrp = true
|
loadingXrp = true
|
||||||
const rpc = electrobun.rpc
|
const rpc = electrobun.rpc
|
||||||
if (!rpc) {
|
if (!rpc) {
|
||||||
loadingXrp = false
|
loadingXrp = false
|
||||||
|
fetchXrpInFlight = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -92,6 +96,7 @@
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
loadingXrp = false
|
loadingXrp = false
|
||||||
|
fetchXrpInFlight = false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchXmr() {
|
async function fetchXmr() {
|
||||||
@@ -111,12 +116,31 @@
|
|||||||
onMount(() => {
|
onMount(() => {
|
||||||
frontendLog('dashboard mounted')
|
frontendLog('dashboard mounted')
|
||||||
moneroWallet.init().catch((e) => frontendLogError('moneroWallet.init() failed', e))
|
moneroWallet.init().catch((e) => frontendLogError('moneroWallet.init() failed', e))
|
||||||
xrpWallet.init().then(async () => {
|
xrpWallet.init().catch((e) => frontendLogError('xrpWallet.init() failed', e))
|
||||||
await fetchXrp()
|
|
||||||
})
|
|
||||||
fetchXmr()
|
fetchXmr()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Wait for the XRP wallet list to load, then fetch balances.
|
||||||
|
$effect(() => {
|
||||||
|
if (xrpWallet.ready && xrpWallet.wallets.length > 0) {
|
||||||
|
fetchXrp()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Self-heal: if the monero wallet list never got loaded (e.g. the server
|
||||||
|
// was starting while the dashboard rendered), retry login once.
|
||||||
|
$effect(() => {
|
||||||
|
if (
|
||||||
|
moneroWallet.ready &&
|
||||||
|
!moneroWallet.walletOpen &&
|
||||||
|
!moneroWallet.opening &&
|
||||||
|
moneroWallet.wallets.length === 0 &&
|
||||||
|
!moneroWallet.error
|
||||||
|
) {
|
||||||
|
void moneroWallet.login()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (moneroWallet.walletOpen) {
|
if (moneroWallet.walletOpen) {
|
||||||
fetchXmr()
|
fetchXmr()
|
||||||
@@ -205,7 +229,7 @@
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent class="flex flex-1 flex-col justify-center">
|
<CardContent class="flex flex-1 flex-col justify-center">
|
||||||
{#if loadingXrp}
|
{#if !xrpWallet.ready || loadingXrp || (xrpWallet.wallets.length > 0 && Object.keys(xrpBalances).length === 0)}
|
||||||
<div class="h-14 flex items-center"><Loader /></div>
|
<div class="h-14 flex items-center"><Loader /></div>
|
||||||
{:else}
|
{:else}
|
||||||
<p class="font-mono text-xl tabular-nums">{fmtBal(xrpTotalBalance)}</p>
|
<p class="font-mono text-xl tabular-nums">{fmtBal(xrpTotalBalance)}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user