diff --git a/Cargo.lock b/Cargo.lock index ea17b2c..53004ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index dca90bd..fb45c15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/README.md b/README.md index 3896fdb..2470e8d 100644 --- a/README.md +++ b/README.md @@ -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`, 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`. diff --git a/src/format.rs b/src/format.rs index 776f734..00ebf1b 100644 --- a/src/format.rs +++ b/src/format.rs @@ -3,7 +3,11 @@ use serde_json::json; use crate::items::ShopItem; -pub fn format_item_diff(old: &ShopItem, new: &ShopItem) -> Option { +pub fn format_item_diff( + old: &ShopItem, + new: &ShopItem, + real_price: Option<&i32>, +) -> Option { 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 { 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); } } diff --git a/src/lib.rs b/src/lib.rs index fc3e54f..6993df3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 { 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::>().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 { Ok(result.join("\n\n")) } -fn diff_old_new_items(old_items: &ShopItems, new_items: &ShopItems) -> Vec { +fn diff_old_new_items( + old_items: &ShopItems, + new_items: &ShopItems, + real_prices: HashMap, +) -> Vec { let mut result: Vec = 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 { - 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!(