added env file and the ability to set a interval for data to be grabbed
This commit is contained in:
parent
5d71ada8c9
commit
f9e7f97f00
4 changed files with 178 additions and 72 deletions
1
.env
Normal file
1
.env
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
UPDATE_INTERVAL=12
|
||||||
98
Cargo.lock
generated
98
Cargo.lock
generated
|
|
@ -17,6 +17,21 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -80,6 +95,21 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"time",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.15.7"
|
version = "0.15.7"
|
||||||
|
|
@ -109,6 +139,12 @@ version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dotenv"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encode_unicode"
|
name = "encode_unicode"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
|
@ -328,6 +364,29 @@ dependencies = [
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
@ -453,7 +512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -461,6 +520,8 @@ dependencies = [
|
||||||
name = "mtg_seller_bot"
|
name = "mtg_seller_bot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"dotenv",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -486,6 +547,15 @@ dependencies = [
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
|
|
@ -842,6 +912,17 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
|
@ -997,6 +1078,12 @@ dependencies = [
|
||||||
"try-lock",
|
"try-lock",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
@ -1101,6 +1188,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.4.26"
|
||||||
|
dotenv = "0.15.0"
|
||||||
indicatif = "0.17.5"
|
indicatif = "0.17.5"
|
||||||
reqwest = { version = "0.11.18", features = ["json"] }
|
reqwest = { version = "0.11.18", features = ["json"] }
|
||||||
serde = { version = "1.0.178", features = ["derive"]}
|
serde = { version = "1.0.178", features = ["derive"]}
|
||||||
|
|
|
||||||
85
src/main.rs
85
src/main.rs
|
|
@ -1,44 +1,61 @@
|
||||||
|
/// This program utilizes several external libraries to perform its functions, such as dotenv, serde, tokio, etc.
|
||||||
|
use dotenv;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, env, fs::File, fs::OpenOptions, io::BufReader};
|
use std::{collections::HashMap, env, fs::File, fs::OpenOptions, io::BufReader};
|
||||||
use tokio::time::Duration;
|
use tokio::time::Duration;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
|
||||||
|
/// This structure defines a Card object, consisting of a name and a hashmap of prices.
|
||||||
/// A struct to represent a Card returned from the API.
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct Card {
|
struct Card {
|
||||||
/// The name of the card.
|
|
||||||
name: String,
|
name: String,
|
||||||
/// The prices of the card in various formats.
|
|
||||||
prices: HashMap<String, Option<String>>,
|
prices: HashMap<String, Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct to represent a Card from the local JSON file.
|
/// This structure defines a CardFromFile object, consisting of a name, count, and a USD value.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct CardFromFile {
|
struct CardFromFile {
|
||||||
/// The name of the card.
|
|
||||||
name: String,
|
name: String,
|
||||||
/// The count of this card.
|
|
||||||
count: usize,
|
count: usize,
|
||||||
/// The value of this card in USD.
|
|
||||||
usd_value: Option<String>,
|
usd_value: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct to represent a collection of Cards from the local JSON file.
|
/// This structure defines a CardFile object, consisting of a vector of CardFromFile objects.
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct CardFile {
|
struct CardFile {
|
||||||
/// The list of cards.
|
|
||||||
cards: Vec<CardFromFile>,
|
cards: Vec<CardFromFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main function.
|
/// The main function of the program. It retrieves card price information from an external API and updates a local JSON file.
|
||||||
///
|
/// It accepts a path to a JSON file as an argument and also uses an environment variable, UPDATE_INTERVAL, to determine the frequency of its update cycle.
|
||||||
/// This function reads a local JSON file of cards, sends an API request for each card to get the current price in USD,
|
|
||||||
/// compares the fetched price with the stored price in the local file, and updates the file if there is any difference.
|
|
||||||
///
|
|
||||||
/// Note: There is a delay of 100ms between each API request as per the API rules.
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<std::io::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
dotenv::dotenv().ok();
|
||||||
|
|
||||||
|
// Retrieve the update interval from the .env file or return an error if not present.
|
||||||
|
let update_interval_str = match dotenv::var("UPDATE_INTERVAL") {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("UPDATE_INTERVAL is not defined in the .env file");
|
||||||
|
return Err("UPDATE_INTERVAL is not defined in the .env file".into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Attempt to parse the update interval as a u64 or return an error if it fails.
|
||||||
|
let update_interval = match update_interval_str.parse::<u64>() {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("UPDATE_INTERVAL is not a valid number");
|
||||||
|
return Err("UPDATE_INTERVAL is not a valid number".into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let update_interval = std::time::Duration::from_secs(update_interval * 3600);
|
||||||
|
|
||||||
|
let mut interval = tokio::time::interval(update_interval);
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
|
||||||
|
// Retrieve the file path from the program's arguments or return an error if not present.
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
eprintln!("Please provide the path to the JSON file as an argument.");
|
eprintln!("Please provide the path to the JSON file as an argument.");
|
||||||
|
|
@ -46,20 +63,12 @@ async fn main() -> Result<(), Box<std::io::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_path = &args[1];
|
let file_path = &args[1];
|
||||||
let file = match File::open(file_path) {
|
let file = File::open(file_path)?;
|
||||||
Ok(file) => file,
|
|
||||||
Err(error) => {
|
|
||||||
eprintln!("There was a problem opening the file: {:?}", error);
|
|
||||||
return Err(Box::new(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::NotFound,
|
|
||||||
"File not found",
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
let mut cards_data: CardFile = serde_json::from_reader(reader).unwrap();
|
let mut cards_data: CardFile = serde_json::from_reader(reader)?;
|
||||||
|
|
||||||
|
// Setting up a progress bar for visual representation of the card processing progress.
|
||||||
let pb = ProgressBar::new(cards_data.cards.len() as u64);
|
let pb = ProgressBar::new(cards_data.cards.len() as u64);
|
||||||
let style = ProgressStyle::default_bar()
|
let style = ProgressStyle::default_bar()
|
||||||
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
|
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
|
||||||
|
|
@ -67,18 +76,15 @@ async fn main() -> Result<(), Box<std::io::Error>> {
|
||||||
let style = style.progress_chars("#>-");
|
let style = style.progress_chars("#>-");
|
||||||
pb.set_style(style);
|
pb.set_style(style);
|
||||||
|
|
||||||
|
// For each card in the input file, retrieve the current price information and update the local data if necessary.
|
||||||
for card_from_file in &mut cards_data.cards {
|
for card_from_file in &mut cards_data.cards {
|
||||||
let request_url = format!(
|
let request_url = format!(
|
||||||
"https://api.scryfall.com/cards/named?exact={}",
|
"https://api.scryfall.com/cards/named?exact={}",
|
||||||
card_from_file.name
|
card_from_file.name
|
||||||
);
|
);
|
||||||
let response = reqwest::get(&request_url).await
|
let response = reqwest::get(&request_url).await?;
|
||||||
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?;
|
|
||||||
|
|
||||||
let card: Card = response.json().await
|
|
||||||
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?;
|
|
||||||
|
|
||||||
|
|
||||||
|
let card: Card = response.json().await?;
|
||||||
|
|
||||||
if let Some(price) = card.prices.get("usd") {
|
if let Some(price) = card.prices.get("usd") {
|
||||||
if let Some(price_str) = price {
|
if let Some(price_str) = price {
|
||||||
|
|
@ -88,20 +94,21 @@ async fn main() -> Result<(), Box<std::io::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increment the progress bar and pause for a brief period.
|
||||||
pb.inc(1);
|
pb.inc(1);
|
||||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the progress bar as completed.
|
||||||
pb.finish_with_message("Completed!");
|
pb.finish_with_message("Completed!");
|
||||||
|
|
||||||
|
// Write the updated card data back to the input file.
|
||||||
let file = OpenOptions::new()
|
let file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
.open(file_path)
|
.open(file_path)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
serde_json::to_writer_pretty(file, &cards_data).unwrap();
|
serde_json::to_writer_pretty(file, &cards_data)?;
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue