diff --git a/Cargo.lock b/Cargo.lock index 9815a686..99136123 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,9 +134,9 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arboard" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" +checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "core-graphics 0.23.2", @@ -850,9 +850,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ "jobserver", "libc", @@ -1776,9 +1776,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "event-listener" @@ -2803,9 +2803,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2926,9 +2926,9 @@ dependencies = [ [[package]] name = "infer" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" +checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" dependencies = [ "cfb", ] @@ -4234,7 +4234,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 2.0.2", + "proc-macro-crate 1.1.0", "proc-macro2", "quote", "syn 2.0.46", @@ -4329,7 +4329,6 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.6.0", "block2", - "dispatch", "libc", "objc2", ] @@ -4572,9 +4571,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" dependencies = [ "memchr", "thiserror", @@ -4583,9 +4582,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" dependencies = [ "pest", "pest_generator", @@ -4593,9 +4592,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" dependencies = [ "pest", "pest_meta", @@ -4606,9 +4605,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", @@ -4819,9 +4818,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plist" @@ -5312,9 +5311,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] @@ -5331,9 +5330,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick 1.1.3", "memchr", @@ -6393,25 +6392,24 @@ dependencies = [ [[package]] name = "softbuffer" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d623bff5d06f60d738990980d782c8c866997d9194cfe79ecad00aa2f76826dd" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "bytemuck", "cfg_aliases", - "core-graphics 0.23.2", + "core-graphics 0.24.0", "foreign-types", "js-sys", "log", "objc2", - "objc2-app-kit", "objc2-foundation", "objc2-quartz-core", "raw-window-handle", - "redox_syscall 0.5.3", + "redox_syscall 0.5.4", "wasm-bindgen", "web-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6862,9 +6860,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.29.1" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a97abbc7d6cfd0720da3e06fcb1cf2ac87cbfdb5bbbce103a1279a211c4d81" +checksum = "82e7ede56f9ef03a0bb384c7b2bed4f3985ee7f3f79ec887c50d8466eec21096" dependencies = [ "bitflags 2.6.0", "cocoa", @@ -6918,13 +6916,12 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.0.0-rc.8" +version = "2.0.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8345ccc676ef16e26b61fc0f5340b4e770678b1e1f53f08c69ebdac5e56b422" +checksum = "eb3c3b1c7ac5b72d59da307b84af900a0098c74c9d7369f65018cd8ec0eb50fb" dependencies = [ "anyhow", "bytes", - "cocoa", "dirs", "dunce", "embed_plist", @@ -6939,8 +6936,11 @@ dependencies = [ "log", "mime", "muda", - "objc", + "objc2", + "objc2-app-kit", + "objc2-foundation", "percent-encoding", + "plist", "raw-window-handle", "reqwest", "serde", @@ -6967,9 +6967,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.0.0-rc.7" +version = "2.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5ad5fcfaf02cf79aa6727f6c5df38567d8dce172b00b62690c6bc46c08b7ce" +checksum = "6ff5713e81e02e0b99f5219b275abbd7d2c0cc0f30180e25b1b650e08feeac63" dependencies = [ "anyhow", "cargo_toml", @@ -6989,9 +6989,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.0.0-rc.7" +version = "2.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809ef6316726fc72593d296cf6f4e7461326e310c313d6a6c42b6e7f1e2671cf" +checksum = "5370f2591dcc93d4ff08d9dd168f5097f79b34e859883586a409c627544190e3" dependencies = [ "base64 0.22.1", "brotli 6.0.0", @@ -7016,9 +7016,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.0.0-rc.6" +version = "2.0.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1359e8861d210d25731f8b1bfbb4d111dd06406cf73c59659366ef450364d811" +checksum = "19442dc8ee002ab1926586f6aecb90114f3a1226766008b0c9ac2d9fec9eeb7e" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -7030,9 +7030,9 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.0.0-rc.7" +version = "2.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dded420c86183f592d0fe925ef9447f41e26fa79f0bdfef8d3f17bfbcdbfb7" +checksum = "5e3368e91a98aa55ea4e3e8ccff516bc1ed2f85872c335ec35e9b345469032e0" dependencies = [ "anyhow", "glob", @@ -7084,9 +7084,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.0.0-rc.7" +version = "2.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c72b844f387bfc3341c355f3e16b8cbf4161848fa4e348670effb222cd3ba5" +checksum = "c5f38d8aaa1e81d20e8e208e3e317f81b59fb75c530fbae8a90e72d02001d687" dependencies = [ "dpi", "gtk", @@ -7103,15 +7103,17 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.0.0-rc.7" +version = "2.0.0-rc.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73accf936a7cd01d1382de7850726fdf6c1f6ab3b01ccb7a0950cb852e332596" +checksum = "cf1ef5171e14c8fe3b5a63e75004c20d057747bc3e7fdc5f8ded625f0b29f5c7" dependencies = [ - "cocoa", "gtk", "http 1.1.0", "jni", "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", "percent-encoding", "raw-window-handle", "softbuffer", @@ -7127,9 +7129,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.0.0-rc.7" +version = "2.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53d9fe87e985b273696ae22ce2b9f099a8f1b44bc8fb127467bda5fcb3e4371" +checksum = "31fe4c9148e1b35225e1c00753f24b517ce00041d02eb4b4d6fd10613a47736c" dependencies = [ "brotli 6.0.0", "cargo_metadata", @@ -7728,9 +7730,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131a65b2cef2081bc14dbcd414c906edbfa3bb5323dd7e748cc298614681196b" +checksum = "044d7738b3d50f288ddef035b793228740ad4d927f5466b0af55dc15e7e03cfe" dependencies = [ "core-graphics 0.24.0", "crossbeam-channel", @@ -7951,9 +7953,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" @@ -8036,11 +8038,10 @@ dependencies = [ [[package]] name = "urlpattern" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bd5ff03aea02fa45b13a7980151fe45009af1980ba69f651ec367121a31609" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" dependencies = [ - "derive_more", "regex", "serde", "unic-ucd-ident", @@ -8450,12 +8451,13 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window-vibrancy" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cdd6999298d969289d8078dae02ce798ad23452075985cccba8b6326711ecf" +checksum = "3ea403deff7b51fff19e261330f71608ff2cdef5721d72b64180bb95be7c4150" dependencies = [ - "cocoa", - "objc", + "objc2", + "objc2-app-kit", + "objc2-foundation", "raw-window-handle", "windows-sys 0.59.0", "windows-version", @@ -8850,9 +8852,9 @@ dependencies = [ [[package]] name = "wry" -version = "0.42.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b8049c8f239cdbfaaea4bacb9646f6b208938ceec0acd5b3e99cd05f70903f" +checksum = "f4d715cf5fe88e9647f3d17b207b6d060d4a88e7171d4ccb2d2c657dd1d44728" dependencies = [ "base64 0.22.1", "block", diff --git a/src-gui/src/models/cliModel.ts b/src-gui/src/models/cliModel.ts index 587c6197..aff0c66c 100644 --- a/src-gui/src/models/cliModel.ts +++ b/src-gui/src/models/cliModel.ts @@ -37,7 +37,7 @@ export function parseCliLogString(log: string): CliLog | string { } else { return log; } - } catch (err) { + } catch { return log; } } diff --git a/src-gui/src/renderer/components/modal/provider/ProviderListDialog.tsx b/src-gui/src/renderer/components/modal/provider/ProviderListDialog.tsx index a0e0021a..d2cf106e 100644 --- a/src-gui/src/renderer/components/modal/provider/ProviderListDialog.tsx +++ b/src-gui/src/renderer/components/modal/provider/ProviderListDialog.tsx @@ -1,7 +1,6 @@ import { Avatar, Button, - CircularProgress, Dialog, DialogActions, DialogContent, @@ -15,14 +14,9 @@ import { import AddIcon from "@material-ui/icons/Add"; import SearchIcon from "@material-ui/icons/Search"; import { ExtendedProviderStatus } from "models/apiModel"; -import { RpcMethod } from "models/rpcModel"; import { useState } from "react"; import { setSelectedProvider } from "store/features/providersSlice"; -import { - useAllProviders, - useAppDispatch, - useIsRpcEndpointBusy, -} from "store/hooks"; +import { useAllProviders, useAppDispatch } from "store/hooks"; import ListSellersDialog from "../listSellers/ListSellersDialog"; import ProviderInfo from "./ProviderInfo"; import ProviderSubmitDialog from "./ProviderSubmitDialog"; @@ -65,13 +59,11 @@ export function ProviderSubmitDialogOpenButton() { export function ListSellersDialogOpenButton() { const [open, setOpen] = useState(false); - const running = useIsRpcEndpointBusy(RpcMethod.LIST_SELLERS); return ( { // Prevents background from being clicked and reopening dialog if (!open) { @@ -81,7 +73,9 @@ export function ListSellersDialogOpenButton() { > setOpen(false)} /> - {running ? : } + + + diff --git a/src-gui/src/renderer/components/pages/help/RpcControlBox.tsx b/src-gui/src/renderer/components/pages/help/RpcControlBox.tsx index 333b88c2..0dbc32a4 100644 --- a/src-gui/src/renderer/components/pages/help/RpcControlBox.tsx +++ b/src-gui/src/renderer/components/pages/help/RpcControlBox.tsx @@ -3,7 +3,7 @@ import FolderOpenIcon from "@material-ui/icons/FolderOpen"; import PlayArrowIcon from "@material-ui/icons/PlayArrow"; import StopIcon from "@material-ui/icons/Stop"; import PromiseInvokeButton from "renderer/components/PromiseInvokeButton"; -import { useIsContextAvailable } from "store/hooks"; +import { useAppSelector, useIsContextAvailable } from "store/hooks"; import InfoBox from "../../modal/swap/InfoBox"; import CliLogsBox from "../../other/RenderedCliLog"; @@ -18,17 +18,16 @@ const useStyles = makeStyles((theme) => ({ export default function RpcControlBox() { const isRunning = useIsContextAvailable(); const classes = useStyles(); + const logs = useAppSelector((s) => s.rpc.logs); return ( - ) : null + } additionalContent={ diff --git a/src-gui/src/renderer/components/pages/wallet/WithdrawWidget.tsx b/src-gui/src/renderer/components/pages/wallet/WithdrawWidget.tsx index 6cbcf9f9..248a1b48 100644 --- a/src-gui/src/renderer/components/pages/wallet/WithdrawWidget.tsx +++ b/src-gui/src/renderer/components/pages/wallet/WithdrawWidget.tsx @@ -3,7 +3,7 @@ import SendIcon from "@material-ui/icons/Send"; import { RpcMethod } from "models/rpcModel"; import { useState } from "react"; import { SatsAmount } from "renderer/components/other/Units"; -import { useAppSelector, useIsRpcEndpointBusy } from "store/hooks"; +import { useAppSelector } from "store/hooks"; import BitcoinIcon from "../../icons/BitcoinIcon"; import InfoBox from "../../modal/swap/InfoBox"; import WithdrawDialog from "../../modal/wallet/WithdrawDialog"; @@ -20,7 +20,6 @@ const useStyles = makeStyles((theme) => ({ export default function WithdrawWidget() { const classes = useStyles(); const walletBalance = useAppSelector((state) => state.rpc.state.balance); - const checkingBalance = useIsRpcEndpointBusy(RpcMethod.GET_BTC_BALANCE); const [showDialog, setShowDialog] = useState(false); function onShowDialog() { @@ -50,7 +49,7 @@ export default function WithdrawWidget() { size="large" onClick={onShowDialog} disabled={ - walletBalance === null || checkingBalance || walletBalance <= 0 + walletBalance === null || walletBalance <= 0 } > Withdraw diff --git a/src-gui/src/renderer/rpc.ts b/src-gui/src/renderer/rpc.ts index 9005a0aa..76ee9796 100644 --- a/src-gui/src/renderer/rpc.ts +++ b/src-gui/src/renderer/rpc.ts @@ -5,6 +5,7 @@ import { BalanceResponse, BuyXmrArgs, BuyXmrResponse, + CliLogEmittedEvent, GetLogsArgs, GetLogsResponse, GetSwapInfoResponse, @@ -20,6 +21,7 @@ import { } from "models/tauriModel"; import { contextStatusEventReceived, + receivedCliLog, rpcSetBalance, rpcSetSwapInfo, } from "store/features/rpcSlice"; @@ -47,6 +49,11 @@ export async function initEventListeners() { console.log("Received context init progress event", event.payload); store.dispatch(contextStatusEventReceived(event.payload)); }); + + listen("cli-log-emitted", (event) => { + console.log("Received cli log event", event.payload); + store.dispatch(receivedCliLog(event.payload)) + }) } async function invoke( diff --git a/src-gui/src/store/features/rpcSlice.ts b/src-gui/src/store/features/rpcSlice.ts index 4bebd3fe..085545a0 100644 --- a/src-gui/src/store/features/rpcSlice.ts +++ b/src-gui/src/store/features/rpcSlice.ts @@ -1,11 +1,14 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { ExtendedProviderStatus, ProviderStatus } from "models/apiModel"; import { + CliLogEmittedEvent, GetSwapInfoResponse, TauriContextStatusEvent, } from "models/tauriModel"; import { MoneroRecoveryResponse } from "../../models/rpcModel"; import { GetSwapInfoResponseExt } from "models/tauriModelExt"; +import { getLogsAndStringsFromRawFileString } from "utils/parseUtils"; +import { CliLog } from "models/cliModel"; interface State { balance: number | null; @@ -27,7 +30,7 @@ interface State { export interface RPCSlice { status: TauriContextStatusEvent | null; state: State; - busyEndpoints: string[]; + logs: (CliLog | string)[]; } const initialState: RPCSlice = { @@ -42,13 +45,18 @@ const initialState: RPCSlice = { updateState: false, }, }, - busyEndpoints: [], + logs: [], }; export const rpcSlice = createSlice({ name: "rpc", initialState, reducers: { + receivedCliLog(slice, action: PayloadAction) { + const buffer = action.payload.buffer; + const logs = getLogsAndStringsFromRawFileString(buffer); + slice.logs = slice.logs.concat(logs); + }, contextStatusEventReceived( slice, action: PayloadAction, @@ -74,17 +82,6 @@ export const rpcSlice = createSlice({ slice.state.swapInfos[action.payload.swap_id] = action.payload as GetSwapInfoResponseExt; }, - rpcSetEndpointBusy(slice, action: PayloadAction) { - if (!slice.busyEndpoints.includes(action.payload)) { - slice.busyEndpoints.push(action.payload); - } - }, - rpcSetEndpointFree(slice, action: PayloadAction) { - const index = slice.busyEndpoints.indexOf(action.payload); - if (index >= 0) { - slice.busyEndpoints.splice(index); - } - }, rpcSetMoneroRecoveryKeys( slice, action: PayloadAction<[string, MoneroRecoveryResponse]>, @@ -105,11 +102,10 @@ export const rpcSlice = createSlice({ export const { contextStatusEventReceived, + receivedCliLog, rpcSetBalance, rpcSetWithdrawTxId, rpcResetWithdrawTxId, - rpcSetEndpointBusy, - rpcSetEndpointFree, rpcSetRendezvousDiscoveredProviders, rpcSetSwapInfo, rpcSetMoneroRecoveryKeys, diff --git a/src-gui/src/store/hooks.ts b/src-gui/src/store/hooks.ts index de956687..47d03a20 100644 --- a/src-gui/src/store/hooks.ts +++ b/src-gui/src/store/hooks.ts @@ -42,10 +42,6 @@ export function useActiveSwapInfo() { return useSwapInfo(swapId); } -export function useIsRpcEndpointBusy(method: string) { - return useAppSelector((state) => state.rpc.busyEndpoints.includes(method)); -} - export function useAllProviders() { return useAppSelector((state) => { const registryProviders = state.providers.registry.providers || []; diff --git a/src-gui/src/utils/parseUtils.ts b/src-gui/src/utils/parseUtils.ts index d4badd8e..12c9cfab 100644 --- a/src-gui/src/utils/parseUtils.ts +++ b/src-gui/src/utils/parseUtils.ts @@ -1,4 +1,4 @@ -import { CliLog } from "models/cliModel"; +import { CliLog, parseCliLogString } from "models/cliModel"; import { Multiaddr } from "multiaddr"; /* @@ -55,19 +55,7 @@ export function getLinesOfString(data: string): string[] { export function getLogsAndStringsFromRawFileString( rawFileData: string, ): (CliLog | string)[] { - return getLinesOfString(rawFileData).map((line) => { - try { - return JSON.parse(line); - } catch { - return line; - } - }); -} - -export function getLogsFromRawFileString(rawFileData: string): CliLog[] { - // TODO: Reimplement this using Tauri - return []; - return getLogsAndStringsFromRawFileString(rawFileData).filter(isCliLog); + return getLinesOfString(rawFileData).map(parseCliLogString); } export function logsToRawString(logs: (CliLog | string)[]): string { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 141f28bc..e1f0bb27 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -138,15 +138,12 @@ fn setup(app: &mut tauri::App) -> Result<(), Box> { match context { Ok(context) => { let state = app_handle.state::>(); - state.write().await.set_context(Arc::new(context)); - // To display to the user that the setup is done, we emit an event to the Tauri frontend tauri_handle.emit_context_init_progress_event(TauriContextStatusEvent::Available); } Err(e) => { println!("Error while initializing context: {:?}", e); - // To display to the user that the setup failed, we emit an event to the Tauri frontend tauri_handle.emit_context_init_progress_event(TauriContextStatusEvent::Failed); } @@ -182,7 +179,8 @@ pub fn run() { RunEvent::Exit | RunEvent::ExitRequested { .. } => { // Here we cleanup the Context when the application is closed // This is necessary to among other things stop the monero-wallet-rpc process - // If the application is forcibly closed, this may not be called + // If the application is forcibly closed, this may not be called. + // TODO: fix that let context = app.state::>().inner().try_read(); match context { diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index 84fefc66..7d021b35 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -81,7 +81,8 @@ pub async fn main() -> Result<()> { // initialize tracing let format = if json { Format::Json } else { Format::Raw }; let log_dir = config.data.dir.join("logs"); - common::tracing_util::init(LevelFilter::DEBUG, format, log_dir).expect("initialize tracing"); + common::tracing_util::init(LevelFilter::DEBUG, format, log_dir, None) + .expect("initialize tracing"); // check for conflicting env / config values if config.monero.network != env_config.monero_network { diff --git a/swap/src/cli/api.rs b/swap/src/cli/api.rs index e32764eb..7c3e3d21 100644 --- a/swap/src/cli/api.rs +++ b/swap/src/cli/api.rs @@ -288,7 +288,12 @@ impl ContextBuilder { }; START.call_once(|| { - let _ = common::tracing_util::init(level_filter, format, data_dir.join("logs")); + let _ = common::tracing_util::init( + level_filter, + format, + data_dir.join("logs"), + self.tauri_handle.clone(), + ); }); let seed = Seed::from_file_or_generate(data_dir.as_path()) diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index 675dd329..d10ee328 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -6,8 +6,9 @@ use strum::Display; use typeshare::typeshare; use uuid::Uuid; -static SWAP_PROGRESS_EVENT_NAME: &str = "swap-progress-update"; -static CONTEXT_INIT_PROGRESS_EVENT_NAME: &str = "context-init-progress-update"; +const SWAP_PROGRESS_EVENT_NAME: &str = "swap-progress-update"; +const CONTEXT_INIT_PROGRESS_EVENT_NAME: &str = "context-init-progress-update"; +const CLI_LOG_EMITTED_EVENT_NAME: &str = "cli-log-emitted"; #[derive(Debug, Clone)] pub struct TauriHandle( @@ -47,6 +48,12 @@ pub trait TauriEmitter { fn emit_context_init_progress_event(&self, event: TauriContextStatusEvent) { let _ = self.emit_tauri_event(CONTEXT_INIT_PROGRESS_EVENT_NAME, event); } + + fn emit_cli_log_event(&self, event: CliLogEmittedEvent) { + let _ = self + .emit_tauri_event(CLI_LOG_EMITTED_EVENT_NAME, event) + .ok(); + } } impl TauriEmitter for TauriHandle { @@ -158,3 +165,14 @@ pub enum TauriSwapProgressEvent { }, Released, } + +/// This event is emitted whenever there is a log message issued in the CLI. +/// +/// It contains a json serialized object containing the log message and metadata. +#[typeshare] +#[derive(Debug, Serialize, Clone)] +#[typeshare] +pub struct CliLogEmittedEvent { + /// The serialized object containing the log message and metadata. + pub buffer: String +} diff --git a/swap/src/common/tracing_util.rs b/swap/src/common/tracing_util.rs index 191c43bf..8be333ab 100644 --- a/swap/src/common/tracing_util.rs +++ b/swap/src/common/tracing_util.rs @@ -1,13 +1,17 @@ +use std::io; use std::path::Path; use std::str::FromStr; use anyhow::Result; use tracing_subscriber::filter::{Directive, LevelFilter}; use tracing_subscriber::fmt::time::UtcTime; +use tracing_subscriber::fmt::MakeWriter; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{fmt, EnvFilter, Layer}; +use crate::cli::api::tauri_bindings::{CliLogEmittedEvent, TauriEmitter, TauriHandle}; + /// Output formats for logging messages. pub enum Format { /// Standard, human readable format. @@ -20,11 +24,12 @@ pub enum Format { /// Besides printing to `stdout`, this will append to a log file. /// Said file will contain JSON-formatted logs of all levels, /// disregarding the arguments to this function. -pub fn init(level_filter: LevelFilter, format: Format, dir: impl AsRef) -> Result<()> { - let env_filter = EnvFilter::from_default_env() - .add_directive(Directive::from_str(&format!("asb={}", &level_filter))?) - .add_directive(Directive::from_str(&format!("swap={}", &level_filter))?); - +pub fn init( + level_filter: LevelFilter, + format: Format, + dir: impl AsRef, + tauri_handle: Option, +) -> Result<()> { // file logger will always write in JSON format and with timestamps let file_appender = tracing_appender::rolling::never(&dir, "swap-all.log"); @@ -34,9 +39,9 @@ pub fn init(level_filter: LevelFilter, format: Format, dir: impl AsRef) -> .with_timer(UtcTime::rfc_3339()) .with_target(false) .json() - .with_filter(env_filter); + .with_filter(env_filter(level_filter)?); - // terminal logger + // terminal loger let is_terminal = atty::is(atty::Stream::Stderr); let terminal_layer = fmt::layer() .with_writer(std::io::stdout) @@ -44,21 +49,83 @@ pub fn init(level_filter: LevelFilter, format: Format, dir: impl AsRef) -> .with_timer(UtcTime::rfc_3339()) .with_target(false); + // tauri layer (forwards logs to the tauri guest when connected) + let tauri_layer = fmt::layer() + .with_writer(TauriWriter::new(tauri_handle)) + .with_ansi(false) + .with_timer(UtcTime::rfc_3339()) + .with_target(false) + .json() + .with_filter(env_filter(level_filter)?); + // combine the layers and start logging, format with json if specified if let Format::Json = format { tracing_subscriber::registry() .with(file_layer) + .with(tauri_layer) .with(terminal_layer.json().with_filter(level_filter)) .init(); } else { tracing_subscriber::registry() .with(file_layer) + .with(tauri_layer) .with(terminal_layer.with_filter(level_filter)) .init(); } - // now we can use the tracing macros to log messages + // Now we can use the tracing macros to log messages tracing::info!(%level_filter, logs_dir=%dir.as_ref().display(), "Initialized tracing"); Ok(()) } + +/// This function controls which crate's logs actually get logged and from which level. +fn env_filter(level_filter: LevelFilter) -> Result { + Ok(EnvFilter::from_default_env() + .add_directive(Directive::from_str(&format!("asb={}", &level_filter))?) + .add_directive(Directive::from_str(&format!("swap={}", &level_filter))?)) +} + +/// A writer that forwards tracing log messages to the tauri guest. +#[derive(Clone)] +pub struct TauriWriter { + tauri_handle: Option, +} + +impl TauriWriter { + /// Create a new Tauri writer that sends log messages to the tauri guest. + pub fn new(tauri_handle: Option) -> Self { + Self { tauri_handle } + } +} + +/// This is needed for tracing to accept this as a writer. +impl<'a> MakeWriter<'a> for TauriWriter { + type Writer = TauriWriter; + + fn make_writer(&'a self) -> Self::Writer { + self.clone() + } +} + +/// For every write issued by tracing we simply pass the string on as an event to the tauri guest. +impl std::io::Write for TauriWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + // Since this function accepts bytes, we need to pass to utf8 first + let owned_buf = buf.to_owned(); + let utf8_string = String::from_utf8(owned_buf) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?; + + // Then send to tauri + self.tauri_handle.emit_cli_log_event(CliLogEmittedEvent { + buffer: utf8_string, + }); + + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + // No-op, we don't need to flush anything + Ok(()) + } +}