Add real price ratio

This commit is contained in:
SkyfallWasTaken 2024-07-23 10:39:11 +01:00
parent ca2acbffe6
commit 17c19361ab
5 changed files with 64 additions and 14 deletions

7
Cargo.lock generated
View file

@ -37,6 +37,7 @@ dependencies = [
"console_error_panic_hook",
"getrandom",
"indoc",
"maplit",
"pretty_assertions",
"reqwest",
"scraper",
@ -631,6 +632,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "markup5ever"
version = "0.11.0"

View file

@ -25,6 +25,7 @@ reqwest = "0.12.5"
[dev-dependencies]
pretty_assertions = "1.4.0"
maplit = "1.0.2"
[package.metadata.cargo-machete]
ignored = ["getrandom"]

View file

@ -12,6 +12,10 @@
- `NTFY_URL` - URL for ntfy
- `SLACK_GROUP_ID` - ID of the Slack group to ping
## Key-value keys
- `real_prices` - stores the real-world prices of items. equivalent to a `HashMap<String, i32>`, where `String` is the `id` parameter. prices are in USD.
- `items` - stores old items (you don't need to worry about this one)
## Tech Stack
- **Cloudflare Workers** for running the monitor on the edge.
- **Rust** for the monitor's code. I love its type safety, as well as libraries such as `serde`.

View file

@ -3,7 +3,11 @@ use serde_json::json;
use crate::items::ShopItem;
pub fn format_item_diff(old: &ShopItem, new: &ShopItem) -> Option<String> {
pub fn format_item_diff(
old: &ShopItem,
new: &ShopItem,
real_price: Option<&i32>,
) -> Option<String> {
if old == new {
// The items are the exact same
return None;
@ -19,13 +23,21 @@ pub fn format_item_diff(old: &ShopItem, new: &ShopItem) -> Option<String> {
if old.price != new.price {
result.push(format!(
"*Price:* {} → {} {}",
"*Price:* {} → {} {}{}",
old.price,
new.price,
if old.price > new.price {
"🔽"
} else {
"🔼"
},
if let Some(real_price) = real_price {
format!(
" _(${real_price} - ${}/hr)_",
(*real_price as f32) / (new.price as f32)
)
} else {
"".into()
}
));
}
@ -257,21 +269,23 @@ mod diff_tests {
let old = ShopItem {
full_name: "Test".into(),
price: 1,
id: "1".into(),
..Default::default()
};
let new = ShopItem {
full_name: "Test".into(),
price: 2,
id: "1".into(),
..Default::default()
};
assert_eq!(
format_item_diff(&old, &new),
format_item_diff(&old, &new, Some(&50)), // Let's say it's $50
Some(
indoc! {"
*Name:* Test
*Price:* 1 2 🔼"}
*Price:* 1 2 🔼 _($50 - $25/hr)_"}
.into()
)
);
@ -282,17 +296,19 @@ mod diff_tests {
let old = ShopItem {
full_name: "Test".into(),
description: Some("Lorem ipsum".into()),
price: 2,
..Default::default()
};
let new = ShopItem {
full_name: "Test".into(),
description: Some("Dolor sit amet".into()),
price: 2,
..Default::default()
};
assert_eq!(
format_item_diff(&old, &new),
format_item_diff(&old, &new, Some(&50)),
Some(
indoc! {"
*Name:* Test
@ -317,7 +333,7 @@ mod diff_tests {
};
assert_eq!(
format_item_diff(&old, &new),
format_item_diff(&old, &new, Some(&50)),
Some(
indoc! {"
*Name:* Test
@ -332,17 +348,19 @@ mod diff_tests {
let old = ShopItem {
full_name: "Test".into(),
stock: Some(10),
price: 2,
..Default::default()
};
let new = ShopItem {
full_name: "Test".into(),
stock: None,
price: 2,
..Default::default()
};
assert_eq!(
format_item_diff(&old, &new),
format_item_diff(&old, &new, Some(&50)),
Some(
indoc! {"
*Name:* Test
@ -367,7 +385,7 @@ mod diff_tests {
};
assert_eq!(
format_item_diff(&old, &new),
format_item_diff(&old, &new, Some(&50)),
Some(
indoc! {"
*Name:* Test
@ -392,7 +410,7 @@ mod diff_tests {
};
assert_eq!(
format_item_diff(&old, &new),
format_item_diff(&old, &new, Some(&50)),
Some(
indoc! {"
*Name:* Test
@ -410,6 +428,6 @@ mod diff_tests {
..Default::default()
};
assert_eq!(format_item_diff(&item, &item), None);
assert_eq!(format_item_diff(&item, &item, Some(&50)), None);
}
}

View file

@ -1,3 +1,5 @@
use std::collections::HashMap;
use items::ShopItems;
use reqwest::Client;
use worker::*;
@ -48,9 +50,13 @@ async fn run_scrape(env: Env) -> Result<String> {
kv.put("items", &available_items)?.execute().await?;
return Ok("No old items found, storing new items".into());
};
let Some(real_prices) = kv.get("real_prices").json::<HashMap<String, i32>>().await? else {
console_debug!("No real prices found!");
return Err("No real prices found! This is a bug.".into());
};
// Compare the old items with the new items.
let result = diff_old_new_items(&old_items, &available_items);
let result = diff_old_new_items(&old_items, &available_items, real_prices);
// Check if there are any updates.
if result.is_empty() {
@ -89,7 +95,11 @@ async fn run_scrape(env: Env) -> Result<String> {
Ok(result.join("\n\n"))
}
fn diff_old_new_items(old_items: &ShopItems, new_items: &ShopItems) -> Vec<String> {
fn diff_old_new_items(
old_items: &ShopItems,
new_items: &ShopItems,
real_prices: HashMap<String, i32>,
) -> Vec<String> {
let mut result: Vec<String> = Vec::new();
for item in new_items {
// TODO: not very efficient.
@ -97,7 +107,7 @@ fn diff_old_new_items(old_items: &ShopItems, new_items: &ShopItems) -> Vec<Strin
match old_item {
Some(old) => {
if let Some(diff) = format::format_item_diff(old, item) {
if let Some(diff) = format::format_item_diff(old, item, real_prices.get(&item.id)) {
result.push(diff);
}
}
@ -123,6 +133,7 @@ mod diff_old_new_items_tests {
use indoc::formatdoc;
use items::ShopItem;
use maplit::hashmap;
use pretty_assertions::assert_eq;
#[test]
@ -130,12 +141,14 @@ mod diff_old_new_items_tests {
let item_1 = ShopItem {
full_name: "Item 1".into(),
description: Some("Description 1".into()),
price: 200,
id: "1".into(),
..Default::default()
};
let item_2 = ShopItem {
full_name: "Item 2".into(),
description: Some("Description 2".into()),
price: 50,
id: "2".into(),
..Default::default()
};
@ -143,7 +156,14 @@ mod diff_old_new_items_tests {
let old_items = vec![item_1.clone(), item_2.clone()];
let new_items = vec![item_1.clone()];
let result = diff_old_new_items(&old_items, &new_items);
let result = diff_old_new_items(
&old_items,
&new_items,
hashmap! {
"1".into() => 100,
"2".into() => 200,
},
);
assert_eq!(result.len(), 1);
assert_eq!(