feat: 111125/logger

This commit is contained in:
NguyenAnhQuan 2025-11-11 17:16:43 +07:00
parent 80babfd455
commit cb67afb1a5
10 changed files with 133 additions and 68 deletions

View File

@ -2,6 +2,7 @@ import { ipcMain, dialog, app } from 'electron'
import fs from 'fs'
import path from 'path'
import { encrypt, fromEncryptedJson } from './utils/keystore'
import logger from './logger'
const neptuneNative = require('@neptune/native')
@ -13,15 +14,14 @@ ipcMain.handle('wallet:createKeystore', async (_event, seed, password) => {
const savePath = path.join(process.cwd(), 'wallets')
fs.mkdirSync(savePath, { recursive: true })
// Use timestamp for filename
const timestamp = Date.now()
const fileName = `neptune-wallet-${timestamp}.json`
const filePath = path.join(savePath, fileName)
fs.writeFileSync(filePath, keystore)
return { filePath }
} catch (error) {
console.error('Error creating keystore:', error)
} catch (error: any) {
logger.error('Error creating keystore:', error.message)
throw error
}
})
@ -46,8 +46,8 @@ ipcMain.handle('wallet:saveKeystoreAs', async (_event, seed: string, password: s
fs.writeFileSync(filePath, keystore)
return { filePath }
} catch (error) {
console.error('Error saving keystore (Save As):', error)
} catch (error: any) {
logger.error('Error saving keystore (Save As):', error.message)
throw error
}
})
@ -58,8 +58,8 @@ ipcMain.handle('wallet:decryptKeystore', async (_event, filePath, password) => {
const phrase = await fromEncryptedJson(json, password)
return { phrase }
} catch (error) {
console.error('Error decrypting keystore ipc:', error)
} catch (error: any) {
logger.error('Error decrypting keystore ipc:', error.message)
throw error
}
})
@ -91,14 +91,14 @@ ipcMain.handle('wallet:checkKeystore', async () => {
if (typeof height === 'number' && Number.isFinite(height)) {
minBlockHeight = height
}
} catch (error) {
console.warn('Unable to read minBlockHeight from keystore:', error)
} catch (error: any) {
logger.warn('Unable to read minBlockHeight from keystore:', error.message)
}
return { exists: true, filePath: resolvedPath, minBlockHeight }
} catch (error) {
console.error('Error checking keystore ipc:', error)
return { exists: false, filePath: null, minBlockHeight: null, error: String(error) }
} catch (error: any) {
logger.error('Error checking keystore ipc:', error.message)
return { exists: false, filePath: null, minBlockHeight: null, error: error.message }
}
})
@ -130,9 +130,9 @@ ipcMain.handle(
fs.writeFileSync(normalizedPath, JSON.stringify(walletJson, null, 2), 'utf-8')
return { success: true, minBlockHeight }
} catch (error) {
console.error('Error updating min block height:', error)
return { success: false, error: String(error) }
} catch (error: any) {
logger.error('Error updating min block height:', error.message)
return { success: false, error: error.message }
}
}
)
@ -162,9 +162,9 @@ ipcMain.handle(
}
return { success: true, minBlockHeight: null }
} catch (error) {
console.error('Error reading min block height:', error)
return { success: false, error: String(error), minBlockHeight: null }
} catch (error: any) {
logger.error('Error reading min block height:', error.message)
return { success: false, error: error.message, minBlockHeight: null }
}
}
)
@ -173,8 +173,8 @@ ipcMain.handle('wallet:generateKeysFromSeed', async (_event, seedPhrase: string[
try {
const wallet = new neptuneNative.WalletManager()
return wallet.generateKeysFromSeed(seedPhrase)
} catch (error) {
console.error('Error generating keys from seed ipc:', error)
} catch (error: any) {
logger.error('Error generating keys from seed ipc:', error.message)
throw error
}
})
@ -188,7 +188,6 @@ ipcMain.handle('wallet:buildTransaction', async (_event, args) => {
import.meta.env.VITE_APP_API,
spendingKeyHex,
inputAdditionRecords,
// pass minBlockHeight from args if provided, default 0
typeof args?.minBlockHeight === 'number' && Number.isFinite(args.minBlockHeight)
? args.minBlockHeight
: 0,
@ -197,8 +196,12 @@ ipcMain.handle('wallet:buildTransaction', async (_event, args) => {
fee
)
return JSON.parse(result)
} catch (error) {
console.error('Error building transaction with primitive proof ipc:', error)
} catch (error: any) {
logger.error('Error building transaction with primitive proof ipc:', error.message)
throw error
}
})
ipcMain.on('log:info', (_, msg: string) => logger.info(msg))
ipcMain.on('log:warn', (_, msg: string) => logger.warn(msg))
ipcMain.on('log:error', (_, msg: string) => logger.error(msg))

33
electron/logger.ts Normal file
View File

@ -0,0 +1,33 @@
import { app } from 'electron'
import log from 'electron-log'
const isDev = app.isPackaged
console.log('isDev :>> ', isDev);
if (!isDev) {
log.transports.file.level = 'info'
log.transports.console.level = false
log.transports.file.format = '{y}-{m}-{d} {h}:{i}:{s} [{level}] {text}'
}
export const logger = {
info: (...args: any[]) => {
if (isDev) console.log('[INFO]', ...args)
else log.info(...args)
},
warn: (...args: any[]) => {
if (isDev) console.warn('[WARN]', ...args)
else log.warn(...args)
},
error: (...args: any[]) => {
if (isDev) console.error('[ERROR]', ...args)
else log.error(...args)
},
debug: (...args: any[]) => {
if (isDev) console.debug('[DEBUG]', ...args)
else log.debug(...args)
},
}
export default logger

View File

@ -2,12 +2,14 @@ import { app, BrowserWindow } from 'electron'
import path from 'node:path'
import started from 'electron-squirrel-startup'
import './ipcHandlers'
import logger from './logger'
if (started) {
app.quit()
}
const createWindow = () => {
logger.info('App started')
const mainWindow = new BrowserWindow({
width: 800,
height: 800,
@ -38,6 +40,7 @@ app.on('ready', createWindow)
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
logger.info('App closed')
if (process.platform !== 'darwin') {
app.quit()
}

View File

@ -18,3 +18,9 @@ contextBridge.exposeInMainWorld('walletApi', {
getMinBlockHeight: (filePath: string | null) =>
ipcRenderer.invoke('wallet:getMinBlockHeight', filePath),
})
contextBridge.exposeInMainWorld('logger', {
info: (msg: string) => ipcRenderer.send('log:info', msg),
warn: (msg: string) => ipcRenderer.send('log:warn', msg),
error: (msg: string) => ipcRenderer.send('log:error', msg),
})

10
package-lock.json generated
View File

@ -16,6 +16,7 @@
"ant-design-vue": "^4.2.6",
"axios": "^1.6.8",
"crypto": "^1.0.1",
"electron-log": "^5.4.3",
"electron-squirrel-startup": "^1.0.1",
"pinia": "^2.1.7",
"vue": "^3.4.21",
@ -5807,6 +5808,15 @@
"node": ">=10"
}
},
"node_modules/electron-log": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-5.4.3.tgz",
"integrity": "sha512-sOUsM3LjZdugatazSQ/XTyNcw8dfvH1SYhXWiJyfYodAAKOZdHs0txPiLDXFzOZbhXgAgshQkshH2ccq0feyLQ==",
"license": "MIT",
"engines": {
"node": ">= 14"
}
},
"node_modules/electron-squirrel-startup": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/electron-squirrel-startup/-/electron-squirrel-startup-1.0.1.tgz",

View File

@ -26,6 +26,7 @@
"ant-design-vue": "^4.2.6",
"axios": "^1.6.8",
"crypto": "^1.0.1",
"electron-log": "^5.4.3",
"electron-squirrel-startup": "^1.0.1",
"pinia": "^2.1.7",
"vue": "^3.4.21",

View File

@ -30,11 +30,10 @@ export function useNeptuneWallet() {
await initWasm()
wasmInitialized = true
} catch (err) {
} catch (err: any) {
wasmInitialized = false
const errorMsg = 'Failed to initialize Neptune WASM'
console.error('WASM init error:', err)
throw new Error(errorMsg)
await (window as any).logger.error('WASM init error:', err.message)
throw new Error('Failed to initialize Neptune WASM')
}
})()
@ -59,8 +58,8 @@ export function useNeptuneWallet() {
store.setAddress(addressResult)
return result
} catch (err) {
console.error('Error generating wallet:', err)
} catch (err: any) {
await (window as any).logger.error('Error generating wallet:', err.message)
throw err
}
}
@ -93,8 +92,8 @@ export function useNeptuneWallet() {
spendingKey: result.spending_key_hex,
address: addressResult,
}
} catch (err) {
console.error('Error recovering wallet from seed:', err)
} catch (err: any) {
await (window as any).logger.error('Error recovering wallet from seed:', err.message)
throw err
}
}
@ -128,14 +127,14 @@ export function useNeptuneWallet() {
store.setAddress(addressResult)
await loadMinBlockHeightFromKeystore()
} catch (err) {
} catch (err: any) {
if (
err instanceof Error &&
(err.message.includes('Unsupported state') ||
err.message.includes('unable to authenticate'))
) {
console.error('Invalid password')
} else console.error('Error decrypting keystore:', err)
await (window as any).logger.error('Invalid password')
} else await (window as any).logger.error('Error decrypting keystore:', err.message)
throw err
}
@ -147,8 +146,8 @@ export function useNeptuneWallet() {
store.setKeystorePath(result.filePath)
store.setMinBlockHeight(null)
return result.filePath
} catch (err) {
console.error('Error creating keystore:', err)
} catch (err: any) {
await (window as any).logger.error('Error creating keystore:', err.message)
throw err
}
}
@ -158,8 +157,8 @@ export function useNeptuneWallet() {
const result = await (window as any).walletApi.saveKeystoreAs(seed, password)
if (!result.filePath) throw new Error('User canceled')
return result.filePath
} catch (err) {
console.error('Error saving keystore:', err)
} catch (err: any) {
await (window as any).logger.error('Error saving keystore:', err.message)
throw err
}
}
@ -175,8 +174,8 @@ export function useNeptuneWallet() {
store.setMinBlockHeight(toFiniteNumber(height))
}
return true
} catch (err) {
console.error('Error checking keystore:', err)
} catch (err: any) {
await (window as any).logger.error('Error checking keystore:', err.message)
throw err
}
}
@ -202,8 +201,8 @@ export function useNeptuneWallet() {
)
if (!response.success) throw new Error('Failed to update min block height')
store.setMinBlockHeight(minBlockHeight)
} catch (err) {
console.error('Error saving min block height:', err)
} catch (err: any) {
await (window as any).logger.error('Error saving min block height:', err.message)
throw err
}
}
@ -220,8 +219,8 @@ export function useNeptuneWallet() {
store.setMinBlockHeight(minBlockHeight)
return minBlockHeight
} catch (err) {
console.error('Error loading min block height:', err)
} catch (err: any) {
await (window as any).logger.error('Error loading min block height:', err.message)
throw err
}
}
@ -249,8 +248,8 @@ export function useNeptuneWallet() {
await persistMinBlockHeight(utxoList)
return result
} catch (err) {
console.error('Error getting UTXOs:', err)
} catch (err: any) {
await (window as any).logger.error('Error getting UTXOs:', err.message)
throw err
}
}
@ -275,8 +274,8 @@ export function useNeptuneWallet() {
balance: result?.balance || result,
pendingBalance: result?.pendingBalance || result,
}
} catch (err) {
console.error('Error getting balance:', err)
} catch (err: any) {
await (window as any).logger.error('Error getting balance:', err.message)
throw err
}
}
@ -286,8 +285,8 @@ export function useNeptuneWallet() {
const response = await API.getBlockHeight()
const result = response?.result || response
return result?.height || result
} catch (err) {
console.error('Error getting block height:', err)
} catch (err: any) {
await (window as any).logger.error('Error getting block height:', err.message)
throw err
}
}
@ -299,8 +298,8 @@ export function useNeptuneWallet() {
store.setNetwork((result.network + 'net') as 'mainnet' | 'testnet')
return result
} catch (err) {
console.error('Error getting network info:', err)
} catch (err: any) {
await (window as any).logger.error('Error getting network info:', err.message)
throw err
}
}
@ -327,8 +326,8 @@ export function useNeptuneWallet() {
const response = await API.broadcastSignedTransaction(transactionHex)
const result = response?.result || response
return result
} catch (err) {
console.error('Error sending transaction:', err)
} catch (err: any) {
await (window as any).logger.error('Error sending transaction:', err.message)
throw err
}
}
@ -345,8 +344,8 @@ export function useNeptuneWallet() {
const addressResult = await getAddressFromSeed(store.getSeedPhrase)
store.setAddress(addressResult)
}
} catch (err) {
console.error('Error setting network:', err)
} catch (err: any) {
await (window as any).logger.error('Error setting network:', err.message)
throw err
}
}

View File

@ -32,7 +32,6 @@ const loadUtxos = async () => {
loading.value = true
const result = await getUtxos()
if (result.error) {
console.error(result.error.message)
message.error('Failed to load UTXOs')
loading.value = false
return
@ -40,7 +39,6 @@ const loadUtxos = async () => {
loading.value = false
} catch (err) {
message.error('Failed to load UTXOs')
console.error('Error loading UTXOs:', err)
} finally {
loading.value = false
}
@ -63,8 +61,8 @@ watch(
<div class="debug-header">
<h3 class="debug-title">IN USE UTXOS</h3>
<div class="debug-info">
<p><span>COUNT</span> {{ inUseUtxosCount }}</p>
<p><span>AMOUNT</span> {{ inUseUtxosAmount }} <strong>NPT</strong></p>
<p><span>COUNT</span> <strong>{{ inUseUtxosCount }}</strong></p>
<p><span>AMOUNT</span> <strong>{{ inUseUtxosAmount }}</strong> <strong>NPT</strong></p>
</div>
</div>
@ -116,6 +114,10 @@ watch(
font-weight: var(--font-bold);
margin-right: var(--spacing-sm);
}
strong {
color: var(--primary-color);
}
}
}
}

View File

@ -158,9 +158,11 @@ const displayAddress = computed(() => {
<div class="amount-row">
<div class="amount-field">
<div class="form-group">
<label class="form-label">
Amount <span class="required">*</span>
<span class="balance-info">Available: {{ availableBalance }} NPT</span>
<label class="form-label-extra">
<span class="form-label"> Amount <span class="required">*</span> </span>
<span class="balance-info"
>Available: <strong>{{ availableBalance }}</strong> NPT</span
>
</label>
<input
v-model="outputAmounts"
@ -285,12 +287,17 @@ const displayAddress = computed(() => {
gap: var(--spacing-xs);
}
.form-label-extra {
display: flex;
justify-content: space-between;
align-items: center;
}
.form-label {
font-size: var(--font-sm);
font-weight: var(--font-medium);
color: var(--text-primary);
display: flex;
justify-content: space-between;
align-items: center;
.required {

View File

@ -21,6 +21,7 @@ const activeTabKey = inject<ComputedRef<string>>('activeTabKey')
const availableBalance = ref<string>('0.00000000')
const pendingBalance = ref<string>('0.00000000')
const loading = ref(false)
const sendingLoading = ref(false)
const error = ref<string | null>(null)
const showSeedModal = ref(false)
const isSendingMode = ref(false)
@ -63,7 +64,7 @@ const handleSendTransaction = async (data: {
fee: string
}) => {
try {
loading.value = true
sendingLoading.value = true
const payload = {
spendingKeyHex: neptuneStore.getSpendingKey || '',
inputAdditionRecords: neptuneStore.getUtxos?.map((utxo: Utxo) => utxo.additionRecord),
@ -89,7 +90,7 @@ const handleSendTransaction = async (data: {
} catch (error) {
message.error('Failed to send transaction')
} finally {
loading.value = false
sendingLoading.value = false
}
}
@ -235,14 +236,14 @@ watch(
<!-- Send Transaction View -->
<div v-else-if="isSendingMode" class="send-transaction-wrapper">
<SendTransactionComponent
:is-loading="loading"
:is-loading="sendingLoading"
:available-balance="availableBalance"
@cancel="handleCancelSend"
@send="handleSendTransaction"
/>
<!-- Loading Overlay -->
<div v-if="loading" class="sending-overlay">
<div v-if="sendingLoading" class="sending-overlay">
<div class="sending-content">
<SpinnerCommon size="large" />
<p class="sending-text">Sending...</p>