Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(log): handle errors #144

Merged
merged 17 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion locales/en/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"failed-to-find-tapplet-version": "Failed to find tapplet version",
"failed-to-obtain-permission-token-lock": "Failed to obtain permission token lock",
"failed-to-obtain-auth-token-lock": "Failed to obtain auth token lock",
"provider-call-failed-for-method": "Provider call failed for method {{ method }} with params {{ params }}",
"failed-to-call-provider": "Provider call failed for method {{ method }} with params {{ params }}",
"failed-to-obtain-local-address": "Failed to obtain local address",
"failed-to-start-tapplet-server": "Failed to start tapplet server",
"tapplet-server-already-running": "Tapplet server already running",
Expand Down
2 changes: 1 addition & 1 deletion locales/pl/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"failed-to-find-tapplet-version": "Nie udało się znaleźć wersji tapplet'u",
"failed-to-obtain-permission-token-lock": "Nie udało się uzyskać blokady tokena uprawnień",
"failed-to-obtain-auth-token-lock": "Nie udało się uzyskać blokady tokena autoryzacji",
"provider-call-failed-for-method": "Wywołanie provider'a nie powiodło się dla metody {{ method }} z parametrami {{ params }}",
"failed-to-call-provider": "Wywołanie provider'a nie powiodło się dla metody {{ method }} z parametrami {{ params }}",
"failed-to-obtain-local-address": "Nie udało się uzyskać lokalnego adresu",
"failed-to-start-tapplet-server": "Nie udało się uruchomić serwera tapplet'u",
"tapplet-server-already-running": "Serwer tapplet'u już działa",
Expand Down
29 changes: 19 additions & 10 deletions src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use crate::{
},
download_utils::{ download_file_with_retries, extract },
error::{
Error::{ self, FailedToObtainPermissionTokenLock, JsonParsingError, RequestError, TappletServerError },
Error::{ self, IOError, FailedToObtainPermissionTokenLock, JsonParsingError, RequestError, TappletServerError },
IOError::*,
RequestError::*,
TappletServerError::*,
},
Expand Down Expand Up @@ -110,13 +111,17 @@ pub async fn call_wallet(
) -> Result<serde_json::Value, Error> {
let permission_token = tokens.permission
.lock()
.inspect_err(|e| error!(target: LOG_TARGET, "❌ Error at call_wallet: {:?}", e))
.map_err(|_| FailedToObtainPermissionTokenLock)?
.clone();
let req_params: serde_json::Value = serde_json::from_str(&params).map_err(|e| JsonParsingError(e))?;

let req_params: serde_json::Value = serde_json
::from_str(&params)
.inspect_err(|e| error!(target: LOG_TARGET, "❌ Error at call_wallet: {:?}", e))
.map_err(|e| JsonParsingError(e))?;
match make_request(Some(permission_token), method, req_params).await {
Ok(res) => Ok(res),
Err(e) => {
error!(target: LOG_TARGET,"❌ Error at call_wallet: {:?}", e);
return Err(Error::RequestFailed { message: e.to_string() });
}
}
Expand All @@ -143,14 +148,16 @@ pub async fn launch_tapplet(

// Extract the tapplet archieve each time before launching
// This way make sure that local files have not been replaced and are not malicious
let _ = extract(&file_path, &tapplet_path.clone()).await;
let _ = extract(&file_path, &tapplet_path.clone()).await
.inspect_err(|e| error!(target: LOG_TARGET, "❌ Error extracting file: {:?}", e))
.map_err(|_| { IOError(FailedToUnpackFile { path: tapplet_path.to_string_lossy().to_string() }) })?;
//TODO should compare integrity field with the one stored in db or from github manifest?
match check_files_and_validate_checksum(tapp_version, tapplet_path.clone()) {
Ok(is_valid) => {
info!(target: LOG_TARGET,"Checksum validated without error. Is valid?: {:?}", is_valid);
info!(target: LOG_TARGET,"Checksum validation successfully with test result: {:?}", is_valid);
}
Err(e) => {
error!(target: LOG_TARGET,"Error validating checksum: {:?}", e);
error!(target: LOG_TARGET,"Error validating checksum: {:?}", e);
return Err(e.into());
}
}
Expand Down Expand Up @@ -228,14 +235,16 @@ pub async fn download_and_extract_tapp(
});
handle.await?.map_err(|_| Error::RequestError(FailedToDownload { url: tapp_version.registry_url.clone() }))?;

let _ = extract(&file_path, &tapplet_path.clone()).await;
let _ = extract(&file_path, &tapplet_path.clone()).await.inspect_err(
|e| error!(target: LOG_TARGET, "❌ Error extracting file: {:?}", e)
);
//TODO should compare integrity field with the one stored in db or from github manifest?
match check_files_and_validate_checksum(tapp_version, tapplet_path.clone()) {
Ok(is_valid) => {
info!(target: LOG_TARGET,"Checksum validated without error. Is valid?: {:?}", is_valid);
info!(target: LOG_TARGET,"Checksum validation successfully with test result: {:?}", is_valid);
}
Err(e) => {
error!(target: LOG_TARGET,"Error validating checksum: {:?}", e);
error!(target: LOG_TARGET,"🚨 Error validating checksum: {:?}", e);
return Err(e.into());
}
}
Expand Down Expand Up @@ -460,6 +469,6 @@ pub fn delete_dev_tapplet(dev_tapplet_id: i32, db_connection: State<'_, Database
pub fn open_log_dir(app_handle: tauri::AppHandle) {
let log_dir = app_handle.path().app_log_dir().expect("Could not get log dir");
if let Err(e) = open::that(log_dir) {
error!(target: LOG_TARGET, "Could not open log dir: {:?}", e);
error!(target: LOG_TARGET, "Could not open log dir: {:?}", e);
}
}
3 changes: 3 additions & 0 deletions src-tauri/src/download_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use tokio::fs::{ File, OpenOptions };
use tokio::io::{ AsyncWriteExt, BufReader };
use tokio::time::sleep;
use tokio_util::compat::{ TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt };
use log::error;

use crate::progress_tracker::ProgressTracker;

Expand Down Expand Up @@ -99,10 +100,12 @@ pub async fn extract(file_path: &Path, dest_dir: &Path) -> Result<(), anyhow::Er
extract_zip(file_path, dest_dir).await?;
}
_ => {
error!(target: LOG_TARGET, "❌ Extract file error: Unsupported file extension",);
return Err(anyhow::anyhow!("Unsupported file extension"));
}
}
None => {
error!(target: LOG_TARGET, "❌ Extract file error: File has no extension",);
return Err(anyhow::anyhow!("File has no extension"));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub enum Error {
#[error("failed-to-find-tapplet-version")] VersionNotFound,
#[error("failed-to-obtain-permission-token-lock")] FailedToObtainPermissionTokenLock,
#[error("failed-to-obtain-auth-token-lock")] FailedToObtainAuthTokenLock,
#[error("provider-call-failed-for-method | method-{method} & params-{params}")] ProviderError {
#[error("failed-to-call-provider | method-{method} & params-{params}")] ProviderError {
method: String,
params: String,
},
Expand Down
7 changes: 3 additions & 4 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ async fn try_get_tokens() -> (String, String) {
loop {
match permission_token().await {
Ok(tokens) => {
info!(target: LOG_TARGET, "permission token ok {:?}", tokens);
info!(target: LOG_TARGET, "✅ WALLET DAEMON permission token found: {:?}", tokens);
return tokens;
}
Err(e) => {
warn!(target: LOG_TARGET, "permission token ERR {:?}", e);
warn!(target: LOG_TARGET, "❌ Wallet Daemon permission token error: {:?}", e);
sleep(Duration::from_millis(500));
continue;
}
Expand Down Expand Up @@ -105,7 +105,6 @@ fn setup_tari_universe(app: &mut tauri::App) -> Result<(), Box<dyn std::error::E
let tokens = app.state::<Tokens>();
let handle = tauri::async_runtime::spawn(try_get_tokens());
let (permission_token, auth_token) = tauri::async_runtime::block_on(handle)?;
info!(target: LOG_TARGET, "permission token found {:?}", permission_token);
tokens.permission
.lock()
.map_err(|_| error::Error::FailedToObtainPermissionTokenLock)?
Expand All @@ -121,7 +120,7 @@ fn setup_tari_universe(app: &mut tauri::App) -> Result<(), Box<dyn std::error::E
let handle_start = tauri::async_runtime::spawn(async move { start(tapplet_assets_path).await });
let (addr, cancel_token) = tauri::async_runtime::block_on(handle_start)?.unwrap();
app.manage(AssetServer { addr, cancel_token });
info!(target: LOG_TARGET, "Tari Universe setup completed successfully");
info!(target: LOG_TARGET, "🚀 Tari Universe setup completed successfully");

Ok(())
}
Expand Down
8 changes: 4 additions & 4 deletions src-tauri/src/progress_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,28 @@ impl ProgressTrackerInner {
}

pub fn update(&self, title: String, title_params: Option<HashMap<String, String>>, progress: u64) {
debug!(target: LOG_TARGET, "Progress: {}% {}", progress, title);
debug!(target: LOG_TARGET, "⏳️️ Progress: {}% {}", progress, title);
self.window
.emit("message", SetupStatusEvent {
event_type: "download_status".to_string(),
title,
title_params,
progress: progress as f64,
})
.inspect_err(|e| error!(target: LOG_TARGET, "Could not emit event 'message': {:?}", e))
.inspect_err(|e| error!(target: LOG_TARGET, "Could not emit event 'message': {:?}", e))
.ok();
}

pub fn update_with_next_max(&self, title: String, title_params: Option<HashMap<String, String>>, progress: u64) {
debug!(target: LOG_TARGET, "Progress: {}% {}", progress, title);
debug!(target: LOG_TARGET, "⏳️️ Progress: {}% {}", progress, title);
self.window
.emit("message", SetupStatusEvent {
event_type: "setup_status".to_string(),
title,
title_params,
progress: ((self.min as f64) + ((self.next_max - self.min) as f64) * ((progress as f64) / 100.0)) / 100.0,
})
.inspect_err(|e| error!(target: LOG_TARGET, "Could not emit event 'message': {:?}", e))
.inspect_err(|e| error!(target: LOG_TARGET, "Could not emit event 'message': {:?}", e))
.ok();
}
}
16 changes: 11 additions & 5 deletions src-tauri/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ use tari_wallet_daemon_client::{
ComponentAddressOrName,
};
use tauri_plugin_http::reqwest::{ self, header::{ AUTHORIZATION, CONTENT_TYPE } };

use log::{ error, info };
use crate::error::Error;

const JSON_CONNECT_ADDRESS: &str = "127.0.0.1:18010"; // TODO use db to get endpoint
const LOG_TARGET: &str = "tari::dan::wallet_daemon";

pub async fn permission_token() -> Result<(String, String), anyhow::Error> {
let req_params = AuthLoginRequest {
Expand Down Expand Up @@ -48,8 +49,7 @@ pub async fn account_create(account_name: Option<String>, permissions_token: Str
key_id: None,
max_fee: None,
};
let resp = make_request(Some(permissions_token), "accounts.create".to_string(), create_acc_params).await?;

let _resp = make_request(Some(permissions_token), "accounts.create".to_string(), create_acc_params).await?;
Ok(())
}

Expand Down Expand Up @@ -109,7 +109,13 @@ pub async fn make_request<T: Serialize>(
}
let resp = builder.json(&body).send().await?.json::<JsonRpcResponse>().await?;
match resp.result {
JsonRpcAnswer::Result(result) => Ok(result),
JsonRpcAnswer::Error(error) => Err(anyhow::Error::msg(error.to_string())),
JsonRpcAnswer::Result(result) => {
info!(target: LOG_TARGET, "👁️‍🗨️ JSON rpc request result: {:?}", result);
Ok(result)
}
JsonRpcAnswer::Error(error) => {
error!(target: LOG_TARGET, "🚨 JSON rpc request error: {:?}", error);
Err(anyhow::Error::msg(error.to_string()))
}
}
}
6 changes: 3 additions & 3 deletions src-tauri/src/tapplet_installer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn get_tapp_download_path(
.path()
.app_data_dir()
.unwrap_or_else(|e| {
error!(target: LOG_TARGET, "Failed to get app dir: {}", e);
error!(target: LOG_TARGET, "Failed to get app dir: {}", e);
PathBuf::from("")
})
.to_path_buf();
Expand Down Expand Up @@ -84,9 +84,9 @@ async fn download_file(url: &str, dest: PathBuf) -> Result<(), Error> {
file.write_all(&chunk).map_err(|_| IOError(FailedToWriteFile { path: path.clone() }))?;
}
} else if response.status().is_server_error() {
println!("Download server error! Status: {:?}", response.status());
error!(target: LOG_TARGET, "❌ Download server error! Status: {:?}", response.status());
} else {
println!("Download failed. Something else happened. Status: {:?}", response);
error!(target: LOG_TARGET, "❌ Download failed! Unknown status. Server response: {:?}", response);
}

Ok(())
Expand Down
7 changes: 5 additions & 2 deletions src-tauri/src/tapplet_server.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use axum::Router;
use log::info;
use log::{ error, info };
use std::{ net::SocketAddr, path::PathBuf };
use tokio::select;
use tokio_util::sync::CancellationToken;
Expand All @@ -24,17 +24,20 @@ pub async fn serve(app: Router, port: u16) -> Result<(String, CancellationToken)
let addr = SocketAddr::from(([127, 0, 0, 1], port));
let listener = tokio::net::TcpListener
::bind(addr).await
.inspect_err(|e| error!(target: LOG_TARGET, "❌ Failed to bind port server error: {:?}", e))
.map_err(|_| TappletServerError(BindPortError { port: addr.to_string() }))?;
let address = listener
.local_addr()
.inspect_err(|e| error!(target: LOG_TARGET, "❌ Failed to obtain local address error: {:?}", e))
.map_err(|_| TappletServerError(FailedToObtainLocalAddress))?
.to_string();

tauri::async_runtime::spawn(async move { axum
::serve(listener, app)
.with_graceful_shutdown(shutdown_signal(cancel_token_clone)).await
.inspect_err(|e| error!(target: LOG_TARGET, "❌ Failed to start server error: {:?}", e))
.map_err(|_| TappletServerError(FailedToStart)) });
info!(target: LOG_TARGET, "Tapplet start process completed successfully");
info!(target: LOG_TARGET, "🚀 Tapplet start process completed successfully");

Ok((address, cancel_token))
}
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/wallet_daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub async fn start_wallet_daemon(
let shutdown = Shutdown::new();
let shutdown_signal = shutdown.to_signal();

info!(target: LOG_TARGET, "Wallet daemon configuration completed successfully");
info!(target: LOG_TARGET, "🚀 Wallet daemon configuration completed successfully");

run_tari_dan_wallet_daemon(config, shutdown_signal).await
}
38 changes: 25 additions & 13 deletions src/components/ErrorSnackBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,35 @@ import React from "react"
import { Language } from "../i18initializer"

const ERROR_KEY_SEPARATOR = "|"
const ERROR_CONTEXT_VAULE_SEPARATOR = "&"

export const resolveBackendErrorMessage = (
translator: TFunction<"errors", undefined>,
error: string,
lng: Language
) => {
const [translationKey, context] = error.split(ERROR_KEY_SEPARATOR)
const contextValues: Record<string, string> = context
.split(ERROR_CONTEXT_VAULE_SEPARATOR)
.reduce<Record<string, string>>((acc, item) => {
const [key, value] = item.split("-")
acc[key.trim()] = value.trim()
return acc
}, {})

return translator(translationKey.trim(), { ...contextValues, lng })
): string => {
const parts = error.split(ERROR_KEY_SEPARATOR)

if (parts.length < 2) {
return translator(error.trim(), { lng })
}

// Extract the nested error name
const nestedErrorPart = parts[1].trim() // Get the second part
const translationKey = nestedErrorPart.split("-").slice(1).join("-") // Extract everything after 'message-'

// Extract the method and params from the remaining part
const context = parts.slice(2).join(ERROR_KEY_SEPARATOR) // Join the remaining parts back
const methodMatch = context.match(/method-([a-zA-Z0-9._]+)/)
const paramsMatch = context.match(/params-(.*)/)

const method = methodMatch ? methodMatch[1] : "unknown method"
const params = paramsMatch ? JSON.parse(paramsMatch[1]) : {}

const formattedParams = JSON.stringify(params, null, 2)
.replace(/"([^"]+)":/g, "$1:") // Remove quotes from keys
.replace(/"([^"]+)"/g, "$1") // Remove quotes from string value

return translator(translationKey.trim(), { method, params: formattedParams, lng })
}

export const ErrorSnackBar = () => {
Expand All @@ -42,7 +54,7 @@ export const ErrorSnackBar = () => {
if (message && message.includes(ERROR_KEY_SEPARATOR)) {
return resolveBackendErrorMessage(t, message, currentLanguage)
}
return message
return t(message)
}, [message, currentLanguage])

return (
Expand Down
7 changes: 6 additions & 1 deletion src/components/TransactionConfirmationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ import { BalanceUpdateView } from "./BalanceUpdate"
import { useTranslation } from "react-i18next"
import { ErrorSource } from "../store/error/error.types"
import { CallFunction, CallMethod } from "@tari-project/tarijs/dist/builders/types/Instruction"
import { resolveBackendErrorMessage } from "./ErrorSnackBar"
import { metadataSelector } from "../store/metadata/metadata.selector"

const selectSimulationById = (state: RootState, id?: number) => (id ? simulationsSelectors.selectById(state, id) : null)

export const TransactionConfirmationModal: React.FC = () => {
const { t } = useTranslation(["components", "common"])
const transaction = useSelector(transactionSelector.getPendingTransaction)
const simulation = useSelector((state: RootState) => selectSimulationById(state, transaction?.id))
const currentLanguage = useSelector(metadataSelector.selectCurrentLanguage)

const dispatch = useDispatch()

const handleClose = async () => {
Expand Down Expand Up @@ -93,7 +97,8 @@ export const TransactionConfirmationModal: React.FC = () => {
</DialogContentText>
{simulation?.status == "failure" && (
<DialogContentText>
{t("simulation-error-msg", { ns: "components" })}: {simulation?.errorMsg}
{t("simulation-error-msg", { ns: "components" })}:{" "}
{resolveBackendErrorMessage(t, simulation?.errorMsg, currentLanguage)}
</DialogContentText>
)}
<DialogContentText>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const Wallet: React.FC = () => {
</Typography>
<Box display="flex" flexDirection="column" gap={2} alignItems="center" py={4}>
<SelectAccount onSubmit={handleCreateAccount} accountsList={accountsList} />
<Paper variant="outlined" elevation={0} sx={{ padding: 1, borderRadius: 2, width: "50%" }}>
<Paper variant="outlined" elevation={0} sx={{ padding: 1, borderRadius: 2, width: "auto", minWidth: 200 }}>
<Stack direction="column" justifyContent="flex-end">
<Typography variant="caption" textAlign="left">{`Name: ${currentAccount?.account.name}`}</Typography>
<Typography variant="caption" textAlign="left">{`${t("address", {
Expand Down
1 change: 0 additions & 1 deletion src/store/provider/provider.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export const initializeAction = () => ({

handleMessage = async (event: MessageEvent<TransactionEvent>) => {
if (!event?.data?.args || !event?.data?.methodName) {
dispatch(errorActions.showError({ message: "no-data-in-event", errorSource: ErrorSource.FRONTEND }))
return
}
if (!event.source) {
Expand Down
1 change: 0 additions & 1 deletion src/store/transaction/transaction.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export type TUProviderMethod = Exclude<keyof TUInternalProvider, "runOne">

export type Transaction = {
methodName: TUProviderMethod
// args: any[]
args: SubmitTransactionRequest[]
id: number
submit: () => void
Expand Down