// This file is part of Locus . // Copyright (C) 2022-2022 Fuwn // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 3. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // Copyright (C) 2022-2022 Fuwn // SPDX-License-Identifier: GPL-3.0-only use std::sync::LazyLock; use serde::Deserialize; use crate::{response::success, route::track_mount}; static REFERRALS: LazyLock> = LazyLock::new(|| { serde_json::from_str(include_str!( "../../content/json/stock_market_referrals.json" )) .unwrap() }); #[derive(Deserialize)] struct Referral { name: String, description: String, url: String, } #[derive(Deserialize, Debug)] struct Quote { c: f64, d: Option, dp: Option, h: f64, l: f64, o: f64, pc: f64, #[allow(unused)] t: i64, } impl Quote { pub fn try_to_string(&self) -> Result { Ok(format!( "Current Price: ${}\nDaily Change: ${} ({}%)\nHigh of the Day: ${}\nLow \ of the Day: ${}\nOpening Price: ${}\nYesterday's Closing Price: ${}", self.c, if let Some(d) = self.d { d } else { return Err(()); }, if let Some(dp) = self.dp { dp } else { return Err(()); }, self.l, self.h, self.o, self.pc, )) } } async fn symbol_to_string(symbol: &str) -> String { let mut quote = None; // https://github.com/seanmonstar/reqwest/issues/1017#issuecomment-1157260218 if let Ok(response) = reqwest::get(&format!( "https://finnhub.io/api/v1/quote?symbol={}&token={}", symbol, std::env::var("FINNHUB_TOKEN") .expect("could not locate FINNHUB_TOKEN environment variable") )) .await { if let Ok(response_content) = response.json::().await { if response_content.dp.is_some() { quote = Some(response_content); } else { return "You have searched for an invalid symbol.".to_string(); } } } quote.as_ref().map_or_else( || { format!( "An API error has occurred while looking up the {symbol} symbol... Take \ this up with Finnhub.", ) }, |quote| quote.try_to_string().unwrap(), ) } pub fn module(router: &mut windmark::router::Router) { track_mount( router, "/stocks/referrals", "Want to start investing in the stock market? Support me by using one of \ my referral links!", |context| { success( &format!( "# Referrals\n\n=> /stocks Dashboard\n=> /cryptocurrency \ Cryptocurrency Dashboard\n=> /stocks/telegram Telegram Groups\n=> \ /stocks/search Search\n\nWant to start investing? Support me by \ using one of my referral links!\n\n{}", REFERRALS .iter() .map(|r| { format!("## {}\n\n{}\n\n=> {} {0}", r.name, r.description, r.url) }) .collect::>() .join("\n") ), &context, ) }, ); track_mount( router, "/stocks", "Explore and search the stock market using Gemini!", |context| { async move { success( &format!( "# The Stock Market\n\n=> /stocks/search Symbol Search\n=> /stocks/referrals Referrals\n=> /cryptocurrency Cryptocurrency Dashboard\n=> /stocks/telegram Telegram Groups\n\n## Popular \ Symbols\n\n### AAPL\n\n{}\n\n### TSLA\n\n{}\n\n## Credits\n\nFinancial data provided by\n\n=> https://finnhub.io/ Finnhub", symbol_to_string("AAPL").await, symbol_to_string("TSLA").await ), &context ) } }, ); track_mount( router, "/stocks/search", "Search for a specific symbol", |context| { async move { let mut symbol = context.url.query().unwrap_or("Symbol Search"); if symbol.is_empty() { symbol = "Symbol Search"; } let mut response = format!( "# {symbol}\n\n=> /stocks Dashboard\n=> /cryptocurrency Cryptocurrency \ Dashboard\n=> /stocks/telegram Telegram Groups\n=> /stocks/search \ Search", ); if symbol != "Symbol Search" { if let Some(query) = context.url.query_pairs().next() { if query.0 == "action" && query.1 == "go" { return windmark::response::Response::input( "Which symbol would you like to explore?", ); } let symbol = query.0; if symbol != "Symbol Search" { response = format!( "{}\n\nYou searched for \"{}\"!\n\n## Key Statistics\n\n{}", response, symbol, symbol_to_string(&symbol).await ); } } } success( &format!( "{response}\n\n## Credits\n\nFinancial data provided by\n\n=> https://finnhub.io/ Finnhub", ), &context ) } }, ); }