From 1c8262cd9521a8c68868b5696a87ab95fa4f54d6 Mon Sep 17 00:00:00 2001 From: Subreme <71085002+subreme@users.noreply.github.com> Date: Fri, 26 Nov 2021 14:21:50 +0100 Subject: [PATCH] Change `hidden!()` color to purple Changed the `hidden!()` log color to purple as orange is not part of the ANSI standard, and using a fixed color code to represent it could result in poor legibility in some terminals. Changed comment styling to always use single-line annotations (`//`) for text and multi-line ones (`/* */`) for disabled code blocks, increasing clarity and preventing the https://github.com/stkb/Rewrap extension from accidentally breaking "commented-out" code. --- src/config.rs | 18 +--- src/log.rs | 58 ++++++------ src/monitor.rs | 126 +++++++++----------------- src/stores.rs | 233 ++++++++++++++++++++++--------------------------- src/webhook.rs | 6 +- 5 files changed, 178 insertions(+), 263 deletions(-) diff --git a/src/config.rs b/src/config.rs index bc5a23b..69a7610 100644 --- a/src/config.rs +++ b/src/config.rs @@ -424,8 +424,7 @@ pub struct Settings { // the URL to a product's variant, so the only unique link to each // variant is the Add To Cart one (which is therefore always // included). - // pub atc: Option, - + /* pub atc: Option, */ // Although I was planning to include the option to select whether // to include the item price or not, I decided to "strip users of // this power" as I couldn't figure out a way to make the embeds @@ -533,7 +532,7 @@ pub struct Channel { // to identically named channels, however the `name` is only used // for logging and debugging purposes, and the ID wasn't ever used, // so it was removed. - // pub id: u64, + /* pub id: u64, */ pub url: String, #[serde(default)] pub settings: Alt, @@ -561,16 +560,7 @@ pub struct ChannelHM { // would be used instead of the key to it as the channel name, // however I decided against it. Users are still allowed to include // they field if they choose to, but its value will be ignored. - - // // While this alternative struct could be removed entirely if the - // // `name` field were made optional in the original version, as it is - // // here, I decided to require it instead, so that debugging (and - // // configuring the monitor) doesn't become ridiculously hard. - - // // In this struct, users all allowed to include a `name` field in - // // the struct contained by a `HashMap` if they want to, bypassing - // // the limitation cause by the type not allowing duplicate keys. - // pub name: Option, + /* pub name: Option, */ pub url: String, #[serde(default)] pub settings: Alt, @@ -668,7 +658,7 @@ impl IntoIterator for VecMap { if let VecMap::Vec(events) = self { events.into_iter() } else if let VecMap::Map(eventhms) = self { - // events.values().collect::>().into_iter() + /* events.values().collect::>().into_iter() */ let mut events = Vec::with_capacity(eventhms.len()); diff --git a/src/log.rs b/src/log.rs index 33d336a..33ebee1 100644 --- a/src/log.rs +++ b/src/log.rs @@ -26,11 +26,6 @@ macro_rules! log { // This macro also shouldn't be called outside this file, as it's // implemented in the other macros to save logs to a file. #[macro_export] -/* -// It should only save logs if it isn't called from during tests, as -// those logs would not be useful and could be confusing. -#[cfg(not(test))] -*/ macro_rules! file { // While they weren't included for `log!()`, the parentheses around // the curly brackets are necessary in this macro as the `Write` @@ -40,34 +35,29 @@ macro_rules! file { // trait was already declared, it would be imported twice, causing // the code not to compile. ($($arg:tt)*) => ({ - // Traits must be explicitly imported using `use`. - use std::io::Write; - - if let Ok(mut file) = std::fs::OpenOptions::new() - .write(true) - .create(true) - .append(true) - .open("shopify-monitor.log") - { - let _ = std::write!( - file, - "[{}] {}\n", - chrono::Local::now().format("%F %T%.3f"), - std::format_args!($($arg)*) - ); + // It should only save logs if it isn't called from during tests, as + // those logs would not be useful and could be confusing. + #[cfg(not(test))] { + // Traits must be explicitly imported using `use`. + use std::io::Write; + + if let Ok(mut file) = std::fs::OpenOptions::new() + .write(true) + .create(true) + .append(true) + .open("shopify-monitor.log") + { + let _ = std::write!( + file, + "[{}] {}\n", + chrono::Local::now().format("%F %T%.3f"), + std::format_args!($($arg)*) + ); + } } }); } -/* -// While a test is running, it shouldn't do anything. -#[macro_export] -#[cfg(test)] -macro_rules! file { - ($($arg:tt)*) => {}; -} -*/ - // The other macros take a string literal and some optional parameters, // allowing them to be called in the same way as `println!()`. Its // arguments are then styled differently in each macro, as each type of @@ -165,7 +155,15 @@ macro_rules! hidden { use colored::Colorize; let msg = std::format_args!($($arg)*).to_string(); - crate::log!(msg.black().truecolor(255, 165, 0)); + + // While the program originally used a custom orange + // (#FFAA00) as the color isn't "built-in" to the terminal, + // it was switched to purple so that it can be automatically + // adjusted to be visible regardless of the platform the + // monitor is run on. + /* crate::log!(msg.truecolor(255, 170, 0)); */ + + crate::log!(msg.purple()); } crate::file!("[HIDDEN] {}", std::format_args!($($arg)*)); diff --git a/src/monitor.rs b/src/monitor.rs index 8d50fc7..2ff21b6 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -44,7 +44,7 @@ pub async fn run(stores: Vec) { // `/products.json`, so it has to be added to the // website's URL to get the link to it. let req = client.get( - // format!("{}/products.json?limit=100", + /* format!("{}/products.json?limit=100", */ format!("{}/products.json", &store.url.clone().trim_end_matches('/') )) @@ -65,20 +65,11 @@ pub async fn run(stores: Vec) { .header("sec-fetch-dest", "document") .header("accept-language", "en-US,en;q=0.9") - // .header("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9") - // .header("accept-language", "en-US,en;q=0.9") - // .header("sec-fetch-dest", "document") - // .header("sec-fetch-mode", "navigate") - // .header("sec-fetch-site", "none") - // .header("sec-fetch-user", "?1") - // .header("sec-gpc", "1") - // .header("upgrade-insecure-requests", "1") - .send() .await; if let Ok(res) = req { - // hidden!("Fetched {}! Status: {}!", res.url(), res.status()); + /* hidden!("Fetched {}! Status: {}!", res.url(), res.status()); */ if res.status() == 200 { // In this case, a webhook saying the password @@ -190,7 +181,7 @@ pub async fn run(stores: Vec) { ) ) { - // hidden!("Product {} Updated At: {}", curr.id, curr.updated_at); + /* hidden!("Product {} Updated At: {}", curr.id, curr.updated_at); */ hidden!("{}/product/{} restocked!", store.url, curr.id); success!("{}: `{}` restocked!", store.name, curr.title); @@ -233,11 +224,11 @@ pub async fn run(stores: Vec) { store_logo: store.logo.clone() })); - // hidden!("Pushed a webhook for product {}!", curr.id); + /* hidden!("Pushed a webhook for product {}!", curr.id); */ } } - // hidden!("Sending webhooks for `{}`!", curr.id); + /* hidden!("Sending webhooks for `{}`!", curr.id); */ let length = webhooks.len(); @@ -388,30 +379,6 @@ pub async fn run(stores: Vec) { join_all(tasks).await; } -// This function was scrapped s it raised several issues. -// // I initially wrote this function because the compiler wouldn't allow me to -// // return a value to the `default!()` macro, instead of for the whole -// // function, as setting values with conditionals becomes "weirder" -// // inside nested `if` statements. I changed it not to `.await` the -// // webhook tasks as that required the function to be asynchronous, and -// // the compiler warned that moving Futures isn't thread-safe. -// async fn log_webhooks(length: usize) { -// // The purpose of this conditional statement is to allow for the -// // use of the correct form of a noun in a log message. -// let s: String = if length == 1 { -// // // I'm using `\0`, a null character, instead of an empty -// // // character as the latter doesn't exist. -// // // https://stackoverflow.com/questions/3670505/why-is-there-no-char-empty-like-string-empty -// // '\0' -// "".into() -// } else { -// // 's' -// "s".into() -// }; - -// default!("Sending {} webhook{}...", length, s); -// } - pub fn minimal_products(current_products: Arc>) -> Option> { Some({ let mut products = vec![]; @@ -421,7 +388,7 @@ pub fn minimal_products(current_products: Arc>) -> Option>() // The split is transformed into a vector. - .iter() // The program can now iterate through each char. + // The string is split into characters. + .chars() + // The split is transformed into a vector. + .collect::>() + // The program can now iterate through each char. + .iter() // "Invalid" characters are removed. .filter(|c| c.is_alphanumeric() || c.is_whitespace() || c == &&'.') - .collect::() // The filtered characters are collected into a string. - .trim() // Leading and trailing whitespace is removed. - .into(), // The returned `&str` is converted to a `String`. + // The filtered characters are collected into a string. + .collect::() + // Leading and trailing whitespace is removed. + .trim() + // The returned `&str` is converted to a `String`. + .into(), id: variant.id, }); } @@ -586,15 +536,15 @@ pub fn available_product( // while the two functions' role is to construct the embeds, as they // will differ between item and password-related notifications. async fn request(url: String, msg: Arc) { - // hidden!("`request()` started!"); + /* hidden!("`request()` started!"); */ loop { let status = webhook::send(url.clone(), msg.clone()).await; - // hidden!("Webhook Status: {:?}!", status); + /* hidden!("Webhook Status: {:?}!", status); */ if status == Status::Success { - // hidden!("Successfully sent webhook to {}!", url); + /* hidden!("Successfully sent webhook to {}!", url); */ break; } @@ -624,7 +574,7 @@ pub struct ItemSettings { avatar: Option, color: Option, sizes: bool, - // atc: Option, + /* atc: Option, */ thumbnail: bool, image: bool, footer_text: Option, @@ -639,7 +589,7 @@ pub struct ItemSettings { // `product()` and `Product`, because the `Product` name is already used // by `crate::products::Product`, which is named after `products.json`. async fn item(settings: ItemSettings) { - // hidden!("`item()` started for {}!", product.name.clone()); + /* hidden!("`item()` started for {}!", product.name.clone()); */ let embed = Embed { title: Some(settings.product.name.clone()), @@ -651,13 +601,15 @@ async fn item(settings: ItemSettings) { color: settings.color, fields: { let quantity = if settings.sizes { - // let len = 3 + product.variants.len(); + /* + let len = 3 + product.variants.len(); - // if len % 3 == 2 { - // len + 4 - // } + if len % 3 == 2 { + len + 4 + } - // len + 3 + len + 3 + */ // Since the checks for the number of variants (above // this comment) were removed, the number of fields @@ -698,7 +650,7 @@ async fn item(settings: ItemSettings) { value: settings.product.price.clone(), }); - // hidden!("{} has {} updated variants!", settings.product.name, settings.product.variants.len()); + /* hidden!("{} has {} updated variants!", settings.product.name, settings.product.variants.len()); */ if settings.sizes { for variant in (*settings.product.variants).iter() { @@ -789,7 +741,7 @@ async fn item(settings: ItemSettings) { avatar_url: settings.avatar.clone(), }); - // hidden!("Calling `request()` for {}!", product.name.clone()); + /* hidden!("Calling `request()` for {}!", product.name.clone()); */ request(settings.url, msg).await; } diff --git a/src/stores.rs b/src/stores.rs index 2ba2394..f33a88c 100644 --- a/src/stores.rs +++ b/src/stores.rs @@ -13,7 +13,7 @@ pub fn get() -> Vec { // out where a bug originated from. I didn't use `println!()` as the // example config file is so long that Visual Studio Code's terminal // won't display all of it if you scroll up. - // hidden!("\n{:#?}", config); + /* hidden!("\n{:#?}", config); */ // this vector, which will then be passed to the `monitor::run()` // function, will be filled with one `Store` struct per site listed @@ -377,27 +377,29 @@ pub fn get() -> Vec { // The `color()` function has been temporarily removed. - // // A webhook's embed color can be specified in two - // // places: within the `Event` itself, where it can - // // be individually customized, or in the `Server`'s - // // `ServerSettings`, whose value should be used if - // // one isn't specified for the `Event`. - - // // Creating a function that's only called once [in - // // the code] and requiring so many parameters may - // // seem counter-intuitive, but after wasting some - // // time trying to properly assign values to the - // // `color` variable from within nested `if let` - // // statements (to no avail), I decided to use a - // // function, always using `return`, to "calm down" - // // the compiler. - // let color = color( - // event.color.clone(), - // server.settings.color.clone(), - // server.name.clone(), - // channel.name.clone(), - // channel.id, - // ); + /* + // A webhook's embed color can be specified in two + // places: within the `Event` itself, where it can + // be individually customized, or in the `Server`'s + // `ServerSettings`, whose value should be used if + // one isn't specified for the `Event`. + + // Creating a function that's only called once [in + // the code] and requiring so many parameters may + // seem counter-intuitive, but after wasting some + // time trying to properly assign values to the + // `color` variable from within nested `if let` + // statements (to no avail), I decided to use a + // function, always using `return`, to "calm down" + // the compiler. + let color = color( + event.color.clone(), + server.settings.color.clone(), + server.name.clone(), + channel.name.clone(), + channel.id, + ); + */ let color = parse_color(&color); @@ -407,15 +409,15 @@ pub fn get() -> Vec { if store.name == site.name { let channel = Arc::new(Channel { name: channel.name.clone(), - // id: channel.id.clone(), + /* id: channel.id.clone(), */ url: channel.url.clone(), settings: Settings { username: event_settings.username, avatar: event_settings.avatar, color, sizes: event_settings.sizes, - // atc: event_settings.atc, - // price: event_settings.price, + /* atc: event_settings.atc, */ + /* price: event_settings.price, */ thumbnail: event_settings.thumbnail, image: event_settings.image, footer_text: event_settings.footer_text, @@ -425,25 +427,6 @@ pub fn get() -> Vec { }, }); - // This is no longer the case, as default - // values were removed. - // // There are only three possible values for - // // `restock`, `password_up`, and - // // `password_down` in an `Event` struct, as - // // they are optional and their type is - // // `Option`: - // // - Some(true) - // // - Some(false) - // // - None - - // // Since `restock` has a default value - // // of`true`, this event should be included - // // if its value is either `Some(true)` or - // // `None`, two of the three options. This - // // check can therefore be more concisely - // // made by verifying that its value is NOT - // // `Some(false)`, the third kind. - // It is then added to the list (`Vec`) of // channels that will receive a webhook // notifying the occurrence of an event. @@ -452,10 +435,6 @@ pub fn get() -> Vec { restock.push(channel.clone()); } - // This is also no longer the case. - // // The other two event types default to - // // false, therefore the program only has to - // // check if their value is `Some(true)`. if event.password_up == Some(true) { password_up.push(channel.clone()); } @@ -485,7 +464,7 @@ pub fn get() -> Vec { } } - // hidden!("\n{:#?}", stores); + /* hidden!("\n{:#?}", stores); */ stores } @@ -510,12 +489,6 @@ fn parse_color(color: &Option) -> Option { 0x607d8b } - // The program will return `None` anyway if the code is - // invalid. - // // These are meant to help if someone uses this setting - // // incorrectly (although, wouldn't that technically make it - // // proper usage? :brain:) - // // "null" | "none" | "no" => return None, _ => { if let Ok(val) = u32::from_str_radix(code.trim_start_matches('#'), 16) { if val <= 0xFFFFFF { @@ -533,74 +506,76 @@ fn parse_color(color: &Option) -> Option { None } -// This function has been temporarily removed due to the introduction of -// `Alt`, as it requires changes. It will most likely be updated and -// "added back" in the future. - -// // As explained above, this code was placed in a single-use function to -// // avoid bugs, and to allow for the process to be tested. -// pub fn color( -// event_color: Option, -// server_color: Option, -// server_name: String, -// channel_name: Option, -// channel_id: u64, -// ) -> Option { -// if let Some(code) = event_color { -// let code = code.trim(); - -// if code.is_empty() { -// return None; -// } - -// if code.to_lowercase() == *"server" { -// return color_server(server_color, server_name); -// } - -// if let Ok(val) = u32::from_str_radix(code.trim_start_matches('#'), 16) { -// if val <= 0xFFFFFF { -// return Some(val); -// } -// } - -// // This part will run if the event's color code -// // was invalid. -// hidden!( -// "Invalid Color Code ({}) in {}'s {} channel!", -// code, -// server_name, -// { -// if let Some(name) = channel_name { -// format!("{} ({})", name, channel_id) -// } else { -// format!("{}", channel_id) -// } -// } -// ); -// hidden!("Trying {}'s backup color...", server_name); - -// color_server(server_color, server_name) - -// // If a color isn't provided, the server's one should be used. -// } else { -// color_server(server_color, server_name) -// } -// } - -// // This function is used to replace repetitive segments of the `color()` -// // function above. -// fn color_server(server_color: Option, server_name: String) -> Option { -// if let Some(code) = server_color { -// if let Ok(val) = u32::from_str_radix(code.trim_start_matches('#'), 16) { -// Some(val) -// } else { -// hidden!("Invalid Color Code ({}) in {}!", code, server_name); -// None -// } -// } else { -// None -// } -// } +// These two functions have been temporarily removed due to the +// introduction of `Alt`, as they need to be updated. They will most +// likely be fixed and "added back" in the future. + +/* +// As explained above, this code was placed in a single-use function to +// avoid bugs, and to allow for the process to be tested. +pub fn color( + event_color: Option, + server_color: Option, + server_name: String, + channel_name: Option, + channel_id: u64, +) -> Option { + if let Some(code) = event_color { + let code = code.trim(); + + if code.is_empty() { + return None; + } + + if code.to_lowercase() == *"server" { + return color_server(server_color, server_name); + } + + if let Ok(val) = u32::from_str_radix(code.trim_start_matches('#'), 16) { + if val <= 0xFFFFFF { + return Some(val); + } + } + + // This part will run if the event's color code + // was invalid. + hidden!( + "Invalid Color Code ({}) in {}'s {} channel!", + code, + server_name, + { + if let Some(name) = channel_name { + format!("{} ({})", name, channel_id) + } else { + format!("{}", channel_id) + } + } + ); + hidden!("Trying {}'s backup color...", server_name); + + color_server(server_color, server_name) + + // If a color isn't provided, the server's one should be used. + } else { + color_server(server_color, server_name) + } +} + +// This function is used to replace repetitive segments of the `color()` +// function above. +fn color_server(server_color: Option, server_name: String) -> Option { + if let Some(code) = server_color { + if let Ok(val) = u32::from_str_radix(code.trim_start_matches('#'), 16) { + Some(val) + } else { + hidden!("Invalid Color Code ({}) in {}!", code, server_name); + None + } + } else { + None + } +} +*/ #[derive(Debug)] pub struct Store { @@ -619,11 +594,11 @@ pub struct Store { #[derive(Debug)] pub struct Channel { pub name: String, - // pub id: u64, + /* pub id: u64, */ pub url: String, - // pub include: Option>, - // pub exclude: Option>, - // pub proxies: Option>, + /* pub include: Option>, */ + /* pub exclude: Option>, */ + /* pub proxies: Option>, */ pub settings: Settings, } @@ -633,8 +608,8 @@ pub struct Settings { pub avatar: Option, pub color: Option, pub sizes: bool, - // pub atc: Option, - // pub price: Option, + /* pub atc: Option, */ + /* pub price: Option, */ pub thumbnail: bool, pub image: bool, pub footer_text: Option, diff --git a/src/webhook.rs b/src/webhook.rs index 4861715..76a3d9b 100644 --- a/src/webhook.rs +++ b/src/webhook.rs @@ -4,16 +4,16 @@ use crate::{hidden, message::Message}; use reqwest::Client; use serde::Deserialize; -// use serde_json::to_string_pretty; +/* use serde_json::to_string_pretty; */ use std::sync::Arc; pub async fn send(url: String, msg: Arc) -> Status { - // hidden!("`send()` started!"); + /* hidden!("`send()` started!"); */ // You'd be surprised to hear how many times I uncommented this line // and pasted its output to https://discohook.com to figure out what // was wrong. - // println!("{}", to_string_pretty(&*msg).unwrap()); + /* hidden!("{}", to_string_pretty(&*msg).unwrap()); */ let client = Client::new(); let req = client.post(url.clone()).json(&*msg).send().await;