feat(cli+tauri): Send logs from host to guest (#90)

* feat(tauri): send logs from cli to tauri

---------

Co-authored-by: binarybaron <binarybaron@unstoppableswap.net>
Co-authored-by: binarybaron <86064887+binarybaron@users.noreply.github.com>
This commit is contained in:
Einliterflasche 2024-09-26 13:09:46 +02:00 committed by GitHub
parent 21608ce4f7
commit 7b79ad6abe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 206 additions and 136 deletions

134
Cargo.lock generated
View file

@ -134,9 +134,9 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]] [[package]]
name = "arboard" name = "arboard"
version = "3.4.0" version = "3.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4"
dependencies = [ dependencies = [
"clipboard-win", "clipboard-win",
"core-graphics 0.23.2", "core-graphics 0.23.2",
@ -850,9 +850,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.1.15" version = "1.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@ -1776,9 +1776,9 @@ dependencies = [
[[package]] [[package]]
name = "error-code" name = "error-code"
version = "3.2.0" version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f"
[[package]] [[package]]
name = "event-listener" name = "event-listener"
@ -2803,9 +2803,9 @@ dependencies = [
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.60" version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"core-foundation-sys", "core-foundation-sys",
@ -2926,9 +2926,9 @@ dependencies = [
[[package]] [[package]]
name = "infer" name = "infer"
version = "0.15.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847"
dependencies = [ dependencies = [
"cfb", "cfb",
] ]
@ -4234,7 +4234,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [ dependencies = [
"proc-macro-crate 2.0.2", "proc-macro-crate 1.1.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.46", "syn 2.0.46",
@ -4329,7 +4329,6 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"block2", "block2",
"dispatch",
"libc", "libc",
"objc2", "objc2",
] ]
@ -4572,9 +4571,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.7.11" version = "2.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9"
dependencies = [ dependencies = [
"memchr", "memchr",
"thiserror", "thiserror",
@ -4583,9 +4582,9 @@ dependencies = [
[[package]] [[package]]
name = "pest_derive" name = "pest_derive"
version = "2.7.11" version = "2.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0"
dependencies = [ dependencies = [
"pest", "pest",
"pest_generator", "pest_generator",
@ -4593,9 +4592,9 @@ dependencies = [
[[package]] [[package]]
name = "pest_generator" name = "pest_generator"
version = "2.7.11" version = "2.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e"
dependencies = [ dependencies = [
"pest", "pest",
"pest_meta", "pest_meta",
@ -4606,9 +4605,9 @@ dependencies = [
[[package]] [[package]]
name = "pest_meta" name = "pest_meta"
version = "2.7.11" version = "2.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"pest", "pest",
@ -4819,9 +4818,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]] [[package]]
name = "plist" name = "plist"
@ -5312,9 +5311,9 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
] ]
@ -5331,9 +5330,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.5" version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [ dependencies = [
"aho-corasick 1.1.3", "aho-corasick 1.1.3",
"memchr", "memchr",
@ -6393,25 +6392,24 @@ dependencies = [
[[package]] [[package]]
name = "softbuffer" name = "softbuffer"
version = "0.4.5" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d623bff5d06f60d738990980d782c8c866997d9194cfe79ecad00aa2f76826dd" checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"cfg_aliases", "cfg_aliases",
"core-graphics 0.23.2", "core-graphics 0.24.0",
"foreign-types", "foreign-types",
"js-sys", "js-sys",
"log", "log",
"objc2", "objc2",
"objc2-app-kit",
"objc2-foundation", "objc2-foundation",
"objc2-quartz-core", "objc2-quartz-core",
"raw-window-handle", "raw-window-handle",
"redox_syscall 0.5.3", "redox_syscall 0.5.4",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -6862,9 +6860,9 @@ dependencies = [
[[package]] [[package]]
name = "tao" name = "tao"
version = "0.29.1" version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3a97abbc7d6cfd0720da3e06fcb1cf2ac87cbfdb5bbbce103a1279a211c4d81" checksum = "82e7ede56f9ef03a0bb384c7b2bed4f3985ee7f3f79ec887c50d8466eec21096"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"cocoa", "cocoa",
@ -6918,13 +6916,12 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]] [[package]]
name = "tauri" name = "tauri"
version = "2.0.0-rc.8" version = "2.0.0-rc.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8345ccc676ef16e26b61fc0f5340b4e770678b1e1f53f08c69ebdac5e56b422" checksum = "eb3c3b1c7ac5b72d59da307b84af900a0098c74c9d7369f65018cd8ec0eb50fb"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
"cocoa",
"dirs", "dirs",
"dunce", "dunce",
"embed_plist", "embed_plist",
@ -6939,8 +6936,11 @@ dependencies = [
"log", "log",
"mime", "mime",
"muda", "muda",
"objc", "objc2",
"objc2-app-kit",
"objc2-foundation",
"percent-encoding", "percent-encoding",
"plist",
"raw-window-handle", "raw-window-handle",
"reqwest", "reqwest",
"serde", "serde",
@ -6967,9 +6967,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-build" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5ad5fcfaf02cf79aa6727f6c5df38567d8dce172b00b62690c6bc46c08b7ce" checksum = "6ff5713e81e02e0b99f5219b275abbd7d2c0cc0f30180e25b1b650e08feeac63"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo_toml", "cargo_toml",
@ -6989,9 +6989,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-codegen" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809ef6316726fc72593d296cf6f4e7461326e310c313d6a6c42b6e7f1e2671cf" checksum = "5370f2591dcc93d4ff08d9dd168f5097f79b34e859883586a409c627544190e3"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"brotli 6.0.0", "brotli 6.0.0",
@ -7016,9 +7016,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-macros" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1359e8861d210d25731f8b1bfbb4d111dd06406cf73c59659366ef450364d811" checksum = "19442dc8ee002ab1926586f6aecb90114f3a1226766008b0c9ac2d9fec9eeb7e"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@ -7030,9 +7030,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7dded420c86183f592d0fe925ef9447f41e26fa79f0bdfef8d3f17bfbcdbfb7" checksum = "5e3368e91a98aa55ea4e3e8ccff516bc1ed2f85872c335ec35e9b345469032e0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"glob", "glob",
@ -7084,9 +7084,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-runtime" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75c72b844f387bfc3341c355f3e16b8cbf4161848fa4e348670effb222cd3ba5" checksum = "c5f38d8aaa1e81d20e8e208e3e317f81b59fb75c530fbae8a90e72d02001d687"
dependencies = [ dependencies = [
"dpi", "dpi",
"gtk", "gtk",
@ -7103,15 +7103,17 @@ dependencies = [
[[package]] [[package]]
name = "tauri-runtime-wry" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73accf936a7cd01d1382de7850726fdf6c1f6ab3b01ccb7a0950cb852e332596" checksum = "cf1ef5171e14c8fe3b5a63e75004c20d057747bc3e7fdc5f8ded625f0b29f5c7"
dependencies = [ dependencies = [
"cocoa",
"gtk", "gtk",
"http 1.1.0", "http 1.1.0",
"jni", "jni",
"log", "log",
"objc2",
"objc2-app-kit",
"objc2-foundation",
"percent-encoding", "percent-encoding",
"raw-window-handle", "raw-window-handle",
"softbuffer", "softbuffer",
@ -7127,9 +7129,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-utils" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53d9fe87e985b273696ae22ce2b9f099a8f1b44bc8fb127467bda5fcb3e4371" checksum = "31fe4c9148e1b35225e1c00753f24b517ce00041d02eb4b4d6fd10613a47736c"
dependencies = [ dependencies = [
"brotli 6.0.0", "brotli 6.0.0",
"cargo_metadata", "cargo_metadata",
@ -7728,9 +7730,9 @@ dependencies = [
[[package]] [[package]]
name = "tray-icon" name = "tray-icon"
version = "0.16.0" version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "131a65b2cef2081bc14dbcd414c906edbfa3bb5323dd7e748cc298614681196b" checksum = "044d7738b3d50f288ddef035b793228740ad4d927f5466b0af55dc15e7e03cfe"
dependencies = [ dependencies = [
"core-graphics 0.24.0", "core-graphics 0.24.0",
"crossbeam-channel", "crossbeam-channel",
@ -7951,9 +7953,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.11.0" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
@ -8036,11 +8038,10 @@ dependencies = [
[[package]] [[package]]
name = "urlpattern" name = "urlpattern"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9bd5ff03aea02fa45b13a7980151fe45009af1980ba69f651ec367121a31609" checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d"
dependencies = [ dependencies = [
"derive_more",
"regex", "regex",
"serde", "serde",
"unic-ucd-ident", "unic-ucd-ident",
@ -8450,12 +8451,13 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "window-vibrancy" name = "window-vibrancy"
version = "0.5.1" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8cdd6999298d969289d8078dae02ce798ad23452075985cccba8b6326711ecf" checksum = "3ea403deff7b51fff19e261330f71608ff2cdef5721d72b64180bb95be7c4150"
dependencies = [ dependencies = [
"cocoa", "objc2",
"objc", "objc2-app-kit",
"objc2-foundation",
"raw-window-handle", "raw-window-handle",
"windows-sys 0.59.0", "windows-sys 0.59.0",
"windows-version", "windows-version",
@ -8850,9 +8852,9 @@ dependencies = [
[[package]] [[package]]
name = "wry" name = "wry"
version = "0.42.0" version = "0.43.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b8049c8f239cdbfaaea4bacb9646f6b208938ceec0acd5b3e99cd05f70903f" checksum = "f4d715cf5fe88e9647f3d17b207b6d060d4a88e7171d4ccb2d2c657dd1d44728"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"block", "block",

View file

@ -37,7 +37,7 @@ export function parseCliLogString(log: string): CliLog | string {
} else { } else {
return log; return log;
} }
} catch (err) { } catch {
return log; return log;
} }
} }

View file

@ -1,7 +1,6 @@
import { import {
Avatar, Avatar,
Button, Button,
CircularProgress,
Dialog, Dialog,
DialogActions, DialogActions,
DialogContent, DialogContent,
@ -15,14 +14,9 @@ import {
import AddIcon from "@material-ui/icons/Add"; import AddIcon from "@material-ui/icons/Add";
import SearchIcon from "@material-ui/icons/Search"; import SearchIcon from "@material-ui/icons/Search";
import { ExtendedProviderStatus } from "models/apiModel"; import { ExtendedProviderStatus } from "models/apiModel";
import { RpcMethod } from "models/rpcModel";
import { useState } from "react"; import { useState } from "react";
import { setSelectedProvider } from "store/features/providersSlice"; import { setSelectedProvider } from "store/features/providersSlice";
import { import { useAllProviders, useAppDispatch } from "store/hooks";
useAllProviders,
useAppDispatch,
useIsRpcEndpointBusy,
} from "store/hooks";
import ListSellersDialog from "../listSellers/ListSellersDialog"; import ListSellersDialog from "../listSellers/ListSellersDialog";
import ProviderInfo from "./ProviderInfo"; import ProviderInfo from "./ProviderInfo";
import ProviderSubmitDialog from "./ProviderSubmitDialog"; import ProviderSubmitDialog from "./ProviderSubmitDialog";
@ -65,13 +59,11 @@ export function ProviderSubmitDialogOpenButton() {
export function ListSellersDialogOpenButton() { export function ListSellersDialogOpenButton() {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const running = useIsRpcEndpointBusy(RpcMethod.LIST_SELLERS);
return ( return (
<ListItem <ListItem
autoFocus autoFocus
button button
disabled={running}
onClick={() => { onClick={() => {
// Prevents background from being clicked and reopening dialog // Prevents background from being clicked and reopening dialog
if (!open) { if (!open) {
@ -81,7 +73,9 @@ export function ListSellersDialogOpenButton() {
> >
<ListSellersDialog open={open} onClose={() => setOpen(false)} /> <ListSellersDialog open={open} onClose={() => setOpen(false)} />
<ListItemAvatar> <ListItemAvatar>
<Avatar>{running ? <CircularProgress /> : <SearchIcon />}</Avatar> <Avatar>
<SearchIcon />
</Avatar>
</ListItemAvatar> </ListItemAvatar>
<ListItemText primary="Discover providers by connecting to a rendezvous point" /> <ListItemText primary="Discover providers by connecting to a rendezvous point" />
</ListItem> </ListItem>

View file

@ -3,7 +3,7 @@ import FolderOpenIcon from "@material-ui/icons/FolderOpen";
import PlayArrowIcon from "@material-ui/icons/PlayArrow"; import PlayArrowIcon from "@material-ui/icons/PlayArrow";
import StopIcon from "@material-ui/icons/Stop"; import StopIcon from "@material-ui/icons/Stop";
import PromiseInvokeButton from "renderer/components/PromiseInvokeButton"; import PromiseInvokeButton from "renderer/components/PromiseInvokeButton";
import { useIsContextAvailable } from "store/hooks"; import { useAppSelector, useIsContextAvailable } from "store/hooks";
import InfoBox from "../../modal/swap/InfoBox"; import InfoBox from "../../modal/swap/InfoBox";
import CliLogsBox from "../../other/RenderedCliLog"; import CliLogsBox from "../../other/RenderedCliLog";
@ -18,17 +18,16 @@ const useStyles = makeStyles((theme) => ({
export default function RpcControlBox() { export default function RpcControlBox() {
const isRunning = useIsContextAvailable(); const isRunning = useIsContextAvailable();
const classes = useStyles(); const classes = useStyles();
const logs = useAppSelector((s) => s.rpc.logs);
return ( return (
<InfoBox <InfoBox
title={`Daemon Controller`} title={`Daemon Controller`}
mainContent={ mainContent={
isRunning ? ( <CliLogsBox
<CliLogsBox label="Swap Daemon Logs (current session only)"
label="Swap Daemon Logs (current session only)" logs={logs}
logs={[]} />
/>
) : null
} }
additionalContent={ additionalContent={
<Box className={classes.actionsOuter}> <Box className={classes.actionsOuter}>

View file

@ -3,7 +3,7 @@ import SendIcon from "@material-ui/icons/Send";
import { RpcMethod } from "models/rpcModel"; import { RpcMethod } from "models/rpcModel";
import { useState } from "react"; import { useState } from "react";
import { SatsAmount } from "renderer/components/other/Units"; import { SatsAmount } from "renderer/components/other/Units";
import { useAppSelector, useIsRpcEndpointBusy } from "store/hooks"; import { useAppSelector } from "store/hooks";
import BitcoinIcon from "../../icons/BitcoinIcon"; import BitcoinIcon from "../../icons/BitcoinIcon";
import InfoBox from "../../modal/swap/InfoBox"; import InfoBox from "../../modal/swap/InfoBox";
import WithdrawDialog from "../../modal/wallet/WithdrawDialog"; import WithdrawDialog from "../../modal/wallet/WithdrawDialog";
@ -20,7 +20,6 @@ const useStyles = makeStyles((theme) => ({
export default function WithdrawWidget() { export default function WithdrawWidget() {
const classes = useStyles(); const classes = useStyles();
const walletBalance = useAppSelector((state) => state.rpc.state.balance); const walletBalance = useAppSelector((state) => state.rpc.state.balance);
const checkingBalance = useIsRpcEndpointBusy(RpcMethod.GET_BTC_BALANCE);
const [showDialog, setShowDialog] = useState(false); const [showDialog, setShowDialog] = useState(false);
function onShowDialog() { function onShowDialog() {
@ -50,7 +49,7 @@ export default function WithdrawWidget() {
size="large" size="large"
onClick={onShowDialog} onClick={onShowDialog}
disabled={ disabled={
walletBalance === null || checkingBalance || walletBalance <= 0 walletBalance === null || walletBalance <= 0
} }
> >
Withdraw Withdraw

View file

@ -5,6 +5,7 @@ import {
BalanceResponse, BalanceResponse,
BuyXmrArgs, BuyXmrArgs,
BuyXmrResponse, BuyXmrResponse,
CliLogEmittedEvent,
GetLogsArgs, GetLogsArgs,
GetLogsResponse, GetLogsResponse,
GetSwapInfoResponse, GetSwapInfoResponse,
@ -20,6 +21,7 @@ import {
} from "models/tauriModel"; } from "models/tauriModel";
import { import {
contextStatusEventReceived, contextStatusEventReceived,
receivedCliLog,
rpcSetBalance, rpcSetBalance,
rpcSetSwapInfo, rpcSetSwapInfo,
} from "store/features/rpcSlice"; } from "store/features/rpcSlice";
@ -47,6 +49,11 @@ export async function initEventListeners() {
console.log("Received context init progress event", event.payload); console.log("Received context init progress event", event.payload);
store.dispatch(contextStatusEventReceived(event.payload)); store.dispatch(contextStatusEventReceived(event.payload));
}); });
listen<CliLogEmittedEvent>("cli-log-emitted", (event) => {
console.log("Received cli log event", event.payload);
store.dispatch(receivedCliLog(event.payload))
})
} }
async function invoke<ARGS, RESPONSE>( async function invoke<ARGS, RESPONSE>(

View file

@ -1,11 +1,14 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { ExtendedProviderStatus, ProviderStatus } from "models/apiModel"; import { ExtendedProviderStatus, ProviderStatus } from "models/apiModel";
import { import {
CliLogEmittedEvent,
GetSwapInfoResponse, GetSwapInfoResponse,
TauriContextStatusEvent, TauriContextStatusEvent,
} from "models/tauriModel"; } from "models/tauriModel";
import { MoneroRecoveryResponse } from "../../models/rpcModel"; import { MoneroRecoveryResponse } from "../../models/rpcModel";
import { GetSwapInfoResponseExt } from "models/tauriModelExt"; import { GetSwapInfoResponseExt } from "models/tauriModelExt";
import { getLogsAndStringsFromRawFileString } from "utils/parseUtils";
import { CliLog } from "models/cliModel";
interface State { interface State {
balance: number | null; balance: number | null;
@ -27,7 +30,7 @@ interface State {
export interface RPCSlice { export interface RPCSlice {
status: TauriContextStatusEvent | null; status: TauriContextStatusEvent | null;
state: State; state: State;
busyEndpoints: string[]; logs: (CliLog | string)[];
} }
const initialState: RPCSlice = { const initialState: RPCSlice = {
@ -42,13 +45,18 @@ const initialState: RPCSlice = {
updateState: false, updateState: false,
}, },
}, },
busyEndpoints: [], logs: [],
}; };
export const rpcSlice = createSlice({ export const rpcSlice = createSlice({
name: "rpc", name: "rpc",
initialState, initialState,
reducers: { reducers: {
receivedCliLog(slice, action: PayloadAction<CliLogEmittedEvent>) {
const buffer = action.payload.buffer;
const logs = getLogsAndStringsFromRawFileString(buffer);
slice.logs = slice.logs.concat(logs);
},
contextStatusEventReceived( contextStatusEventReceived(
slice, slice,
action: PayloadAction<TauriContextStatusEvent>, action: PayloadAction<TauriContextStatusEvent>,
@ -74,17 +82,6 @@ export const rpcSlice = createSlice({
slice.state.swapInfos[action.payload.swap_id] = slice.state.swapInfos[action.payload.swap_id] =
action.payload as GetSwapInfoResponseExt; action.payload as GetSwapInfoResponseExt;
}, },
rpcSetEndpointBusy(slice, action: PayloadAction<string>) {
if (!slice.busyEndpoints.includes(action.payload)) {
slice.busyEndpoints.push(action.payload);
}
},
rpcSetEndpointFree(slice, action: PayloadAction<string>) {
const index = slice.busyEndpoints.indexOf(action.payload);
if (index >= 0) {
slice.busyEndpoints.splice(index);
}
},
rpcSetMoneroRecoveryKeys( rpcSetMoneroRecoveryKeys(
slice, slice,
action: PayloadAction<[string, MoneroRecoveryResponse]>, action: PayloadAction<[string, MoneroRecoveryResponse]>,
@ -105,11 +102,10 @@ export const rpcSlice = createSlice({
export const { export const {
contextStatusEventReceived, contextStatusEventReceived,
receivedCliLog,
rpcSetBalance, rpcSetBalance,
rpcSetWithdrawTxId, rpcSetWithdrawTxId,
rpcResetWithdrawTxId, rpcResetWithdrawTxId,
rpcSetEndpointBusy,
rpcSetEndpointFree,
rpcSetRendezvousDiscoveredProviders, rpcSetRendezvousDiscoveredProviders,
rpcSetSwapInfo, rpcSetSwapInfo,
rpcSetMoneroRecoveryKeys, rpcSetMoneroRecoveryKeys,

View file

@ -42,10 +42,6 @@ export function useActiveSwapInfo() {
return useSwapInfo(swapId); return useSwapInfo(swapId);
} }
export function useIsRpcEndpointBusy(method: string) {
return useAppSelector((state) => state.rpc.busyEndpoints.includes(method));
}
export function useAllProviders() { export function useAllProviders() {
return useAppSelector((state) => { return useAppSelector((state) => {
const registryProviders = state.providers.registry.providers || []; const registryProviders = state.providers.registry.providers || [];

View file

@ -1,4 +1,4 @@
import { CliLog } from "models/cliModel"; import { CliLog, parseCliLogString } from "models/cliModel";
import { Multiaddr } from "multiaddr"; import { Multiaddr } from "multiaddr";
/* /*
@ -55,19 +55,7 @@ export function getLinesOfString(data: string): string[] {
export function getLogsAndStringsFromRawFileString( export function getLogsAndStringsFromRawFileString(
rawFileData: string, rawFileData: string,
): (CliLog | string)[] { ): (CliLog | string)[] {
return getLinesOfString(rawFileData).map((line) => { return getLinesOfString(rawFileData).map(parseCliLogString);
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);
} }
export function logsToRawString(logs: (CliLog | string)[]): string { export function logsToRawString(logs: (CliLog | string)[]): string {

View file

@ -138,15 +138,12 @@ fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
match context { match context {
Ok(context) => { Ok(context) => {
let state = app_handle.state::<RwLock<State>>(); let state = app_handle.state::<RwLock<State>>();
state.write().await.set_context(Arc::new(context)); 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 // 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); tauri_handle.emit_context_init_progress_event(TauriContextStatusEvent::Available);
} }
Err(e) => { Err(e) => {
println!("Error while initializing context: {:?}", e); println!("Error while initializing context: {:?}", e);
// To display to the user that the setup failed, we emit an event to the Tauri frontend // 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); tauri_handle.emit_context_init_progress_event(TauriContextStatusEvent::Failed);
} }
@ -182,7 +179,8 @@ pub fn run() {
RunEvent::Exit | RunEvent::ExitRequested { .. } => { RunEvent::Exit | RunEvent::ExitRequested { .. } => {
// Here we cleanup the Context when the application is closed // Here we cleanup the Context when the application is closed
// This is necessary to among other things stop the monero-wallet-rpc process // 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::<RwLock<State>>().inner().try_read(); let context = app.state::<RwLock<State>>().inner().try_read();
match context { match context {

View file

@ -81,7 +81,8 @@ pub async fn main() -> Result<()> {
// initialize tracing // initialize tracing
let format = if json { Format::Json } else { Format::Raw }; let format = if json { Format::Json } else { Format::Raw };
let log_dir = config.data.dir.join("logs"); 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 // check for conflicting env / config values
if config.monero.network != env_config.monero_network { if config.monero.network != env_config.monero_network {

View file

@ -288,7 +288,12 @@ impl ContextBuilder {
}; };
START.call_once(|| { 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()) let seed = Seed::from_file_or_generate(data_dir.as_path())

View file

@ -6,8 +6,9 @@ use strum::Display;
use typeshare::typeshare; use typeshare::typeshare;
use uuid::Uuid; use uuid::Uuid;
static SWAP_PROGRESS_EVENT_NAME: &str = "swap-progress-update"; const SWAP_PROGRESS_EVENT_NAME: &str = "swap-progress-update";
static CONTEXT_INIT_PROGRESS_EVENT_NAME: &str = "context-init-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)] #[derive(Debug, Clone)]
pub struct TauriHandle( pub struct TauriHandle(
@ -47,6 +48,12 @@ pub trait TauriEmitter {
fn emit_context_init_progress_event(&self, event: TauriContextStatusEvent) { fn emit_context_init_progress_event(&self, event: TauriContextStatusEvent) {
let _ = self.emit_tauri_event(CONTEXT_INIT_PROGRESS_EVENT_NAME, event); 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 { impl TauriEmitter for TauriHandle {
@ -158,3 +165,14 @@ pub enum TauriSwapProgressEvent {
}, },
Released, 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
}

View file

@ -1,13 +1,17 @@
use std::io;
use std::path::Path; use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
use anyhow::Result; use anyhow::Result;
use tracing_subscriber::filter::{Directive, LevelFilter}; use tracing_subscriber::filter::{Directive, LevelFilter};
use tracing_subscriber::fmt::time::UtcTime; use tracing_subscriber::fmt::time::UtcTime;
use tracing_subscriber::fmt::MakeWriter;
use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{fmt, EnvFilter, Layer}; use tracing_subscriber::{fmt, EnvFilter, Layer};
use crate::cli::api::tauri_bindings::{CliLogEmittedEvent, TauriEmitter, TauriHandle};
/// Output formats for logging messages. /// Output formats for logging messages.
pub enum Format { pub enum Format {
/// Standard, human readable format. /// Standard, human readable format.
@ -20,11 +24,12 @@ pub enum Format {
/// Besides printing to `stdout`, this will append to a log file. /// Besides printing to `stdout`, this will append to a log file.
/// Said file will contain JSON-formatted logs of all levels, /// Said file will contain JSON-formatted logs of all levels,
/// disregarding the arguments to this function. /// disregarding the arguments to this function.
pub fn init(level_filter: LevelFilter, format: Format, dir: impl AsRef<Path>) -> Result<()> { pub fn init(
let env_filter = EnvFilter::from_default_env() level_filter: LevelFilter,
.add_directive(Directive::from_str(&format!("asb={}", &level_filter))?) format: Format,
.add_directive(Directive::from_str(&format!("swap={}", &level_filter))?); dir: impl AsRef<Path>,
tauri_handle: Option<TauriHandle>,
) -> Result<()> {
// file logger will always write in JSON format and with timestamps // file logger will always write in JSON format and with timestamps
let file_appender = tracing_appender::rolling::never(&dir, "swap-all.log"); 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<Path>) ->
.with_timer(UtcTime::rfc_3339()) .with_timer(UtcTime::rfc_3339())
.with_target(false) .with_target(false)
.json() .json()
.with_filter(env_filter); .with_filter(env_filter(level_filter)?);
// terminal logger // terminal loger
let is_terminal = atty::is(atty::Stream::Stderr); let is_terminal = atty::is(atty::Stream::Stderr);
let terminal_layer = fmt::layer() let terminal_layer = fmt::layer()
.with_writer(std::io::stdout) .with_writer(std::io::stdout)
@ -44,21 +49,83 @@ pub fn init(level_filter: LevelFilter, format: Format, dir: impl AsRef<Path>) ->
.with_timer(UtcTime::rfc_3339()) .with_timer(UtcTime::rfc_3339())
.with_target(false); .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 // combine the layers and start logging, format with json if specified
if let Format::Json = format { if let Format::Json = format {
tracing_subscriber::registry() tracing_subscriber::registry()
.with(file_layer) .with(file_layer)
.with(tauri_layer)
.with(terminal_layer.json().with_filter(level_filter)) .with(terminal_layer.json().with_filter(level_filter))
.init(); .init();
} else { } else {
tracing_subscriber::registry() tracing_subscriber::registry()
.with(file_layer) .with(file_layer)
.with(tauri_layer)
.with(terminal_layer.with_filter(level_filter)) .with(terminal_layer.with_filter(level_filter))
.init(); .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"); tracing::info!(%level_filter, logs_dir=%dir.as_ref().display(), "Initialized tracing");
Ok(()) Ok(())
} }
/// This function controls which crate's logs actually get logged and from which level.
fn env_filter(level_filter: LevelFilter) -> Result<EnvFilter> {
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<TauriHandle>,
}
impl TauriWriter {
/// Create a new Tauri writer that sends log messages to the tauri guest.
pub fn new(tauri_handle: Option<TauriHandle>) -> 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<usize> {
// 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(())
}
}