Replace exit function with panic, formatting

This commit is contained in:
Mateusz Słodkowicz 2024-03-16 00:29:32 +01:00
parent 44b94ef042
commit 1245a6e2e9
Signed by: materus
GPG Key ID: 28D140BCA60B4FD1
5 changed files with 61 additions and 93 deletions

View File

@ -5,12 +5,11 @@ use std::{
use rusqlite::{Connection, Result}; use rusqlite::{Connection, Result};
use crate::config::{get_cache_path, println_and_exit}; use crate::config::get_cache_path;
const CANNOT_CLOSE_MSG: &str = "Couldn't close sqlite connection"; const CANNOT_CLOSE_MSG: &str = "Couldn't close sqlite connection";
pub fn check_code(code: &String) -> Result<bool> pub fn check_code(code: &String) -> Result<bool> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
let exists: bool = conn.query_row( let exists: bool = conn.query_row(
"SELECT EXISTS(SELECT code FROM currencies WHERE currencies.code = UPPER($1))", "SELECT EXISTS(SELECT code FROM currencies WHERE currencies.code = UPPER($1))",
@ -22,12 +21,14 @@ pub fn check_code(code: &String) -> Result<bool>
Ok(exists) Ok(exists)
} }
pub fn list_currencies() -> Result<Vec<[String;2]>> pub fn list_currencies() -> Result<Vec<[String; 2]>> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
let mut stmt = conn.prepare("SELECT code, text FROM currencies ORDER BY code")?; let mut stmt = conn.prepare("SELECT code, text FROM currencies ORDER BY code")?;
let ret = stmt let ret = stmt
.query_map([], |row| {let v:Result<[String;2]> = Ok([row.get(0)?,row.get(1)?]); v}) .query_map([], |row| {
let v: Result<[String; 2]> = Ok([row.get(0)?, row.get(1)?]);
v
})
.expect("Error while listing currencies"); .expect("Error while listing currencies");
let mut result: Vec<[String; 2]> = Vec::new(); let mut result: Vec<[String; 2]> = Vec::new();
@ -41,14 +42,16 @@ pub fn list_currencies() -> Result<Vec<[String;2]>>
Ok(result) Ok(result)
} }
pub fn list_rates(code_from: &String) -> Result<Vec<[String; 2]>> {
pub fn list_rates(code_from: &String ) -> Result<Vec<[String;2]>>
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
let mut stmt = conn.prepare("SELECT code_to, rate FROM exchange_rates WHERE code_from = $1 ORDER BY code_to")?; let mut stmt = conn.prepare(
"SELECT code_to, rate FROM exchange_rates WHERE code_from = $1 ORDER BY code_to",
)?;
let ret = stmt let ret = stmt
.query_map([code_from], |row| {let v:Result<[String;2]> = Ok([row.get(0)?,row.get(1)?]); v}) .query_map([code_from], |row| {
let v: Result<[String; 2]> = Ok([row.get(0)?, row.get(1)?]);
v
})
.expect("Error while listing rates"); .expect("Error while listing rates");
let mut result: Vec<[String; 2]> = Vec::new(); let mut result: Vec<[String; 2]> = Vec::new();
@ -62,8 +65,7 @@ pub fn list_rates(code_from: &String ) -> Result<Vec<[String;2]>>
Ok(result) Ok(result)
} }
pub fn check_exchange(code_from: &String, code_to: &String) -> Result<bool> pub fn check_exchange(code_from: &String, code_to: &String) -> Result<bool> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
let exists: bool = conn.query_row( let exists: bool = conn.query_row(
"SELECT EXISTS(SELECT code_from, code_to "SELECT EXISTS(SELECT code_from, code_to
@ -77,8 +79,7 @@ pub fn check_exchange(code_from: &String, code_to: &String) -> Result<bool>
Ok(exists) Ok(exists)
} }
pub fn get_rate(code_from: &String, code_to: &String) -> Result<String> pub fn get_rate(code_from: &String, code_to: &String) -> Result<String> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
let rate: String = conn.query_row( let rate: String = conn.query_row(
"SELECT rate "SELECT rate
@ -91,8 +92,7 @@ pub fn get_rate(code_from: &String, code_to: &String) -> Result<String>
Ok(rate) Ok(rate)
} }
pub fn get_next_update(code: &String) -> Result<u64> pub fn get_next_update(code: &String) -> Result<u64> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
let next_update: u64 = conn.query_row( let next_update: u64 = conn.query_row(
"SELECT next_update FROM currencies WHERE currencies.code = UPPER($1)", "SELECT next_update FROM currencies WHERE currencies.code = UPPER($1)",
@ -108,8 +108,7 @@ pub fn add_rates(
next_update: u64, next_update: u64,
code_from: &String, code_from: &String,
rates: &HashMap<String, serde_json::Value>, rates: &HashMap<String, serde_json::Value>,
) -> Result<()> ) -> Result<()> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
for (code_to, rate) in rates { for (code_to, rate) in rates {
@ -133,8 +132,7 @@ pub fn add_rates(
Ok(()) Ok(())
} }
pub fn add_code(code: [String; 2]) -> Result<()> pub fn add_code(code: [String; 2]) -> Result<()> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
conn.execute( conn.execute(
" "
@ -146,8 +144,7 @@ pub fn add_code(code: [String; 2]) -> Result<()>
conn.close().expect(CANNOT_CLOSE_MSG); conn.close().expect(CANNOT_CLOSE_MSG);
Ok(()) Ok(())
} }
pub fn get_api_key() -> Result<String> pub fn get_api_key() -> Result<String> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
let api_key: String = conn.query_row( let api_key: String = conn.query_row(
"SELECT value FROM config WHERE config.name = 'API_KEY'", "SELECT value FROM config WHERE config.name = 'API_KEY'",
@ -158,8 +155,7 @@ pub fn get_api_key() -> Result<String>
Ok(api_key) Ok(api_key)
} }
pub fn set_api_key(key: String) -> Result<()> pub fn set_api_key(key: String) -> Result<()> {
{
let conn = Connection::open(get_cache_path())?; let conn = Connection::open(get_cache_path())?;
conn.execute( conn.execute(
" "
@ -174,11 +170,10 @@ pub fn set_api_key(key: String) -> Result<()>
Ok(()) Ok(())
} }
pub fn create_cache() -> Result<()> pub fn create_cache() -> Result<()> {
{
let path = &get_cache_path(); let path = &get_cache_path();
if path.is_dir() { if path.is_dir() {
println_and_exit("Specified path cache path is dir, not file") panic!("Specified path cache path is dir, not file")
} }
if path.exists() { if path.exists() {
match remove_file(path) { match remove_file(path) {
@ -186,10 +181,10 @@ pub fn create_cache() -> Result<()>
Err(_e) => match metadata(path) { Err(_e) => match metadata(path) {
Ok(md) => { Ok(md) => {
if md.permissions().readonly() { if md.permissions().readonly() {
println_and_exit("Can't modify file"); panic!("Can't modify file");
} }
} }
Err(_e) => println_and_exit("Unknown error while trying to remove old database"), Err(_e) => panic!("Unknown error while trying to remove old database"),
}, },
} }
} }

View File

@ -8,8 +8,7 @@ pub const CACHE_LOCATION_ENV_NAME: &str = "CURRENCY_CACHE";
pub const REST_ENDPOINT: &str = "https://v6.exchangerate-api.com/v6/"; pub const REST_ENDPOINT: &str = "https://v6.exchangerate-api.com/v6/";
pub const REST_ENDPOINT_ENV_NAME: &str = "CURRENCY_ENDPOINT"; pub const REST_ENDPOINT_ENV_NAME: &str = "CURRENCY_ENDPOINT";
pub fn get_endpoint() -> String pub fn get_endpoint() -> String {
{
let ret: String; let ret: String;
match var_os(REST_ENDPOINT_ENV_NAME) { match var_os(REST_ENDPOINT_ENV_NAME) {
Some(val) => ret = val.to_str().unwrap().to_string(), Some(val) => ret = val.to_str().unwrap().to_string(),
@ -18,8 +17,7 @@ pub fn get_endpoint() -> String
ret ret
} }
pub fn get_cache_path() -> PathBuf pub fn get_cache_path() -> PathBuf {
{
let mut path: PathBuf = PathBuf::new(); let mut path: PathBuf = PathBuf::new();
match var_os(CACHE_LOCATION_ENV_NAME) { match var_os(CACHE_LOCATION_ENV_NAME) {
Some(val) => path.push(val), Some(val) => path.push(val),
@ -31,15 +29,9 @@ pub fn get_cache_path() -> PathBuf
path path
} }
pub fn get_current_time() -> u64 pub fn get_current_time() -> u64 {
{
std::time::SystemTime::now() std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default() .unwrap_or_default()
.as_secs() .as_secs()
} }
pub fn println_and_exit(msg: &str)
{
println!("{}", msg);
exit(1)
}

View File

@ -1,8 +1,7 @@
use crate::*; use crate::*;
use rust_decimal::prelude::*; use rust_decimal::prelude::*;
use rusty_money::{iso::find, ExchangeRate, Money}; use rusty_money::{iso::find, ExchangeRate, Money};
pub async fn update_rate(code: &String) pub async fn update_rate(code: &String) {
{
if cache::get_next_update(code).expect("Error getting next update time from cache") if cache::get_next_update(code).expect("Error getting next update time from cache")
<= config::get_current_time() <= config::get_current_time()
{ {
@ -10,25 +9,20 @@ pub async fn update_rate(code: &String)
.await .await
.expect("Error while fetching rates"); .expect("Error while fetching rates");
if status == requests::Status::INVALID { if status == requests::Status::INVALID {
config::println_and_exit("Invalid api key when getting rates") panic!("Invalid api key when getting rates")
} else if status == requests::Status::LIMIT { } else if status == requests::Status::LIMIT {
config::println_and_exit("Exceeded API limit when getting rates") panic!("Exceeded API limit when getting rates")
} else if status == requests::Status::ERROR { } else if status == requests::Status::ERROR {
config::println_and_exit("Unknown error when getting rates") panic!("Unknown error when getting rates")
} }
} }
} }
pub async fn get_rate(code_from: &String, code_to: &String) -> String pub async fn get_rate(code_from: &String, code_to: &String) -> String {
{
if !cache::check_code(code_from).expect("Error on getting code status") { if !cache::check_code(code_from).expect("Error on getting code status") {
config::println_and_exit( panic!("Code {} doesn't exists, use correct code!", code_from);
format!("Code {} doesn't exists, use correct code!", code_from).as_str(),
)
} }
if !cache::check_code(code_to).expect("Error on getting code status") { if !cache::check_code(code_to).expect("Error on getting code status") {
config::println_and_exit( panic!("Code {} doesn't exists, use correct code!", code_to);
format!("Code {} doesn't exists, use correct code!", code_to).as_str(),
)
} }
if (!cache::check_exchange(code_from, code_to).expect("Error on getting exchange status")) if (!cache::check_exchange(code_from, code_to).expect("Error on getting exchange status"))
|| (cache::get_next_update(code_from).expect("Error getting next update time from cache") || (cache::get_next_update(code_from).expect("Error getting next update time from cache")
@ -39,19 +33,18 @@ pub async fn get_rate(code_from: &String, code_to: &String) -> String
cache::get_rate(code_from, code_to).expect("Error when getting cached rate") cache::get_rate(code_from, code_to).expect("Error when getting cached rate")
} }
pub async fn convert_value(code_from: &String, code_to: &String, value: &String) pub async fn convert_value(code_from: &String, code_to: &String, value: &String) {
{
if value.parse::<f64>().is_err() { if value.parse::<f64>().is_err() {
config::println_and_exit(format!("{} is not a number!", value).as_str()) panic!("{} is not a number!", value);
} }
let text_rate = get_rate(code_from, code_to).await; let text_rate = get_rate(code_from, code_to).await;
let from_currency = find(code_from); let from_currency = find(code_from);
if from_currency.is_none() { if from_currency.is_none() {
config::println_and_exit(format!("{} not found in ISO formats", code_from).as_str()) panic!("{} not found in ISO formats", code_from);
} }
let to_currency = find(code_to); let to_currency = find(code_to);
if to_currency.is_none() { if to_currency.is_none() {
config::println_and_exit(format!("{} not found in ISO formats", code_to).as_str()) panic!("{} not found in ISO formats", code_to);
} }
let rate = Decimal::from_str(&text_rate).unwrap(); let rate = Decimal::from_str(&text_rate).unwrap();

View File

@ -14,8 +14,7 @@ mod requests;
#[derive(Parser)] #[derive(Parser)]
#[command(about, long_about = None, arg_required_else_help = true)] #[command(about, long_about = None, arg_required_else_help = true)]
struct Cli struct Cli {
{
/// Currency code to exchange from /// Currency code to exchange from
#[arg(value_names = ["Currency input"])] #[arg(value_names = ["Currency input"])]
currency_from: Option<String>, currency_from: Option<String>,
@ -44,8 +43,7 @@ struct Cli
#[arg(short = 'L', long = "list-rates", value_names = ["currency"])] #[arg(short = 'L', long = "list-rates", value_names = ["currency"])]
list_rates: Option<String>, list_rates: Option<String>,
} }
async fn setup_key(key: String) -> Result<bool, Box<dyn std::error::Error>> async fn setup_key(key: String) -> Result<bool, Box<dyn std::error::Error>> {
{
set_api_key(key)?; set_api_key(key)?;
let status = get_currencies().await?; let status = get_currencies().await?;
if status == requests::Status::INVALID { if status == requests::Status::INVALID {
@ -65,8 +63,7 @@ async fn setup_key(key: String) -> Result<bool, Box<dyn std::error::Error>>
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> async fn main() -> Result<(), Box<dyn std::error::Error>> {
{
let args = Cli::parse(); let args = Cli::parse();
let all_args = let all_args =
@ -75,7 +72,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
args.currency_from.is_some() && (args.currency_to.is_none() || args.value.is_none()); args.currency_from.is_some() && (args.currency_to.is_none() || args.value.is_none());
if args.interactive && (all_args || wrong_args) { if args.interactive && (all_args || wrong_args) {
config::println_and_exit("Do not provide codes and value with --interactive") panic!("Do not provide codes and value with --interactive")
} }
if args.recreate_cache || !config::get_cache_path().exists() { if args.recreate_cache || !config::get_cache_path().exists() {
create_cache()?; create_cache()?;
@ -97,7 +94,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
.len() .len()
> 0) > 0)
{ {
config::println_and_exit("API Key is not set up!"); panic!("API Key is not set up!");
} }
if args.list { if args.list {
let currencies = cache::list_currencies()?; let currencies = cache::list_currencies()?;
@ -108,7 +105,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
let code = args.list_rates.unwrap().clone(); let code = args.list_rates.unwrap().clone();
let check = check_code(&code)?; let check = check_code(&code)?;
if !check { if !check {
config::println_and_exit(format!("Code {} not found", code).as_str()); panic!("Code {} not found", code);
} }
exchange::update_rate(&code).await; exchange::update_rate(&code).await;
let rates = cache::list_rates(&code)?; let rates = cache::list_rates(&code)?;
@ -116,9 +113,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
println!("{} to {} rate: {}", code, rate[0], rate[1]); println!("{} to {} rate: {}", code, rate[0], rate[1]);
} }
} else if wrong_args { } else if wrong_args {
config::println_and_exit( panic!("Not all args specified, provide 'currency from', 'currency to' and 'amount'");
"Not all args specified, provide 'currency from', 'currency to' and 'amount'",
);
} else if all_args { } else if all_args {
convert_value( convert_value(
&args.currency_from.unwrap().to_uppercase(), &args.currency_from.unwrap().to_uppercase(),
@ -132,8 +127,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
} }
Ok(()) Ok(())
} }
async fn interactive() -> Result<(), Box<dyn std::error::Error>> async fn interactive() -> Result<(), Box<dyn std::error::Error>> {
{
let mut key_setup = cache::get_api_key() let mut key_setup = cache::get_api_key()
.expect("Error while getting api key") .expect("Error while getting api key")
.len() .len()

View File

@ -4,8 +4,7 @@ use crate::cache::{self, get_api_key};
use crate::config::get_endpoint; use crate::config::get_endpoint;
use serde::Deserialize; use serde::Deserialize;
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum Status pub enum Status {
{
OK, OK,
INVALID, INVALID,
LIMIT, LIMIT,
@ -13,13 +12,11 @@ pub enum Status
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct CurrencyCodes struct CurrencyCodes {
{
supported_codes: Vec<[String; 2]>, supported_codes: Vec<[String; 2]>,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct ConversionRates struct ConversionRates {
{
base_code: String, base_code: String,
time_next_update_unix: u64, time_next_update_unix: u64,
@ -27,14 +24,12 @@ struct ConversionRates
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct Err struct Err {
{
#[serde(rename = "error-type")] #[serde(rename = "error-type")]
error_type: String, error_type: String,
} }
pub async fn get_rates(code: &String) -> Result<Status, reqwest::Error> pub async fn get_rates(code: &String) -> Result<Status, reqwest::Error> {
{
let response = reqwest::get(format!( let response = reqwest::get(format!(
"{}{}{}{}", "{}{}{}{}",
get_endpoint(), get_endpoint(),
@ -65,8 +60,7 @@ pub async fn get_rates(code: &String) -> Result<Status, reqwest::Error>
Ok(Status::ERROR) Ok(Status::ERROR)
} }
pub async fn get_currencies() -> Result<Status, reqwest::Error> pub async fn get_currencies() -> Result<Status, reqwest::Error> {
{
let response = reqwest::get(format!( let response = reqwest::get(format!(
"{}{}{}", "{}{}{}",
get_endpoint(), get_endpoint(),