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 crate::config::{get_cache_path, println_and_exit};
use crate::config::get_cache_path;
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 exists: bool = conn.query_row(
"SELECT EXISTS(SELECT code FROM currencies WHERE currencies.code = UPPER($1))",
@ -22,18 +21,20 @@ pub fn check_code(code: &String) -> Result<bool>
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 mut stmt = conn.prepare("SELECT code, text FROM currencies ORDER BY code")?;
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");
let mut result: Vec<[String;2]> = Vec::new();
let mut result: Vec<[String; 2]> = Vec::new();
for code in ret {
let i = code.unwrap();
let z = [i[0].clone(),i[1].clone()];
let z = [i[0].clone(), i[1].clone()];
result.push(z);
}
stmt.finalize()?;
@ -41,20 +42,22 @@ pub fn list_currencies() -> Result<Vec<[String;2]>>
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 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
.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");
let mut result: Vec<[String;2]> = Vec::new();
let mut result: Vec<[String; 2]> = Vec::new();
for code in ret {
let i = code.unwrap();
let z = [i[0].clone(),i[1].clone()];
let z = [i[0].clone(), i[1].clone()];
result.push(z);
}
stmt.finalize()?;
@ -62,8 +65,7 @@ pub fn list_rates(code_from: &String ) -> Result<Vec<[String;2]>>
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 exists: bool = conn.query_row(
"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)
}
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 rate: String = conn.query_row(
"SELECT rate
@ -91,8 +92,7 @@ pub fn get_rate(code_from: &String, code_to: &String) -> Result<String>
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 next_update: u64 = conn.query_row(
"SELECT next_update FROM currencies WHERE currencies.code = UPPER($1)",
@ -108,8 +108,7 @@ pub fn add_rates(
next_update: u64,
code_from: &String,
rates: &HashMap<String, serde_json::Value>,
) -> Result<()>
{
) -> Result<()> {
let conn = Connection::open(get_cache_path())?;
for (code_to, rate) in rates {
@ -133,8 +132,7 @@ pub fn add_rates(
Ok(())
}
pub fn add_code(code: [String; 2]) -> Result<()>
{
pub fn add_code(code: [String; 2]) -> Result<()> {
let conn = Connection::open(get_cache_path())?;
conn.execute(
"
@ -146,8 +144,7 @@ pub fn add_code(code: [String; 2]) -> Result<()>
conn.close().expect(CANNOT_CLOSE_MSG);
Ok(())
}
pub fn get_api_key() -> Result<String>
{
pub fn get_api_key() -> Result<String> {
let conn = Connection::open(get_cache_path())?;
let api_key: String = conn.query_row(
"SELECT value FROM config WHERE config.name = 'API_KEY'",
@ -158,8 +155,7 @@ pub fn get_api_key() -> Result<String>
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())?;
conn.execute(
"
@ -174,11 +170,10 @@ pub fn set_api_key(key: String) -> Result<()>
Ok(())
}
pub fn create_cache() -> Result<()>
{
pub fn create_cache() -> Result<()> {
let path = &get_cache_path();
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() {
match remove_file(path) {
@ -186,10 +181,10 @@ pub fn create_cache() -> Result<()>
Err(_e) => match metadata(path) {
Ok(md) => {
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_ENV_NAME: &str = "CURRENCY_ENDPOINT";
pub fn get_endpoint() -> String
{
pub fn get_endpoint() -> String {
let ret: String;
match var_os(REST_ENDPOINT_ENV_NAME) {
Some(val) => ret = val.to_str().unwrap().to_string(),
@ -18,8 +17,7 @@ pub fn get_endpoint() -> String
ret
}
pub fn get_cache_path() -> PathBuf
{
pub fn get_cache_path() -> PathBuf {
let mut path: PathBuf = PathBuf::new();
match var_os(CACHE_LOCATION_ENV_NAME) {
Some(val) => path.push(val),
@ -31,15 +29,9 @@ pub fn get_cache_path() -> PathBuf
path
}
pub fn get_current_time() -> u64
{
pub fn get_current_time() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}
pub fn println_and_exit(msg: &str)
{
println!("{}", msg);
exit(1)
}

View File

@ -1,8 +1,7 @@
use crate::*;
use rust_decimal::prelude::*;
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")
<= config::get_current_time()
{
@ -10,25 +9,20 @@ pub async fn update_rate(code: &String)
.await
.expect("Error while fetching rates");
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 {
config::println_and_exit("Exceeded API limit when getting rates")
panic!("Exceeded API limit when getting rates")
} 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") {
config::println_and_exit(
format!("Code {} doesn't exists, use correct code!", code_from).as_str(),
)
panic!("Code {} doesn't exists, use correct code!", code_from);
}
if !cache::check_code(code_to).expect("Error on getting code status") {
config::println_and_exit(
format!("Code {} doesn't exists, use correct code!", code_to).as_str(),
)
panic!("Code {} doesn't exists, use correct code!", code_to);
}
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")
@ -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")
}
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() {
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 from_currency = find(code_from);
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);
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();

View File

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

View File

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