Update dependencies

This commit is contained in:
2023-09-23 16:45:16 +02:00
parent 1092860b42
commit a894717e52
6 changed files with 369 additions and 501 deletions

708
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -5,12 +5,15 @@ authors = ["Joakim Hulthe <joakim@hulthe.net"]
edition = "2021"
[dependencies]
seed = "0.8.0"
#wasm-bindgen = "0.2.70"
serde = { version = "1", features = ['derive'] }
serde_json = "1"
anyhow = "*"
rand = "0.8.4"
seed = "0.10.0"
serde = { version = "1.0.0", features = ['derive'] }
serde_json = "1.0.0"
rand = "0.8.5"
gloo-console = "0.3.0"
gloo-net = "0.4.0"
csv = "1.2.2"
thiserror = "1.0.48"
wasm-bindgen = "0.2.87"
[dependencies.css_typegen]
git = "https://github.com/hulthe/css_typegen.git"

View File

@ -1,15 +1,16 @@
use crate::css::C;
use crate::custom_list::{fetch_custom_song_list, fetch_custom_song_list_index, CustomLists};
use crate::fetch::fetch_list_of;
use crate::fuzzy::FuzzyScore;
use crate::query::ParsedQuery;
use crate::song::Song;
use anyhow::anyhow;
use gloo_console::error;
use rand::seq::SliceRandom;
use rand::thread_rng;
use seed::app::cmds::timeout;
use seed::browser::util::document;
use seed::{attrs, button, div, empty, error, img, input, p, span, C, IF};
use seed::{log, prelude::*};
use seed::prelude::*;
use seed::{attrs, button, div, empty, img, input, p, span, C, IF};
use std::cmp::Reverse;
use std::collections::HashSet;
use web_sys::Element;
@ -194,12 +195,9 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
autotype_song(model, orders);
}
Msg::Scroll => {
let (scroll, max_scroll) = match get_scroll() {
Ok(v) => v,
Err(e) => {
error!(e);
return;
}
let Some((scroll, max_scroll)) = get_scroll() else {
error!("Failed to get song list element by id:", SONG_LIST_ID);
return;
};
let scroll_left: i32 = max_scroll - scroll;
@ -344,18 +342,10 @@ pub fn view(model: &Model) -> Vec<Node<Msg>> {
}
async fn fetch_songs() -> Option<Msg> {
let response = match fetch("/songs").await.and_then(|r| r.check_status()) {
let mut songs: Vec<Song> = match fetch_list_of("/songs").await {
Ok(response) => response,
Err(e) => {
log!("error fetching songs", e);
return None;
}
};
let mut songs: Vec<Song> = match response.json().await {
Ok(v) => v,
Err(e) => {
log!("error parsing songs", e);
error!("Error fetching songs:", e);
return None;
}
};
@ -374,22 +364,20 @@ pub fn autotype_song(model: &mut Model, orders: &mut impl Orders<Msg>) {
const SONG_LIST_ID: &str = "song_list";
fn get_song_list_element() -> anyhow::Result<Element> {
document()
.get_element_by_id(SONG_LIST_ID)
.ok_or_else(|| anyhow!("Failed to access song list element"))
fn get_song_list_element() -> Option<Element> {
document().get_element_by_id(SONG_LIST_ID)
}
fn scroll_to_top() {
if let Ok(elem) = get_song_list_element() {
if let Some(elem) = get_song_list_element() {
elem.scroll_to_with_x_and_y(0.0, 0.0);
}
}
fn get_scroll() -> anyhow::Result<(i32, i32)> {
fn get_scroll() -> Option<(i32, i32)> {
let list = get_song_list_element()?;
let scroll = list.scroll_top();
let height = list.client_height();
let max = (list.scroll_height() - height).max(0);
Ok((scroll, max))
Some((scroll, max))
}

View File

@ -1,24 +1,19 @@
use std::collections::{HashMap, HashSet};
use seed::{log, prelude::fetch};
use gloo_console::error;
use crate::app::{Loading, Msg};
use crate::{
app::{Loading, Msg},
fetch::fetch_list_of,
};
pub type CustomLists = HashMap<String, Loading<HashSet<String>>>;
pub async fn fetch_custom_song_list_index() -> Option<Msg> {
let response = match fetch("/custom/lists").await.and_then(|r| r.check_status()) {
let custom_lists: Vec<String> = match fetch_list_of("/custom/lists").await {
Ok(response) => response,
Err(e) => {
log!("error fetching custom song list index", e);
return None;
}
};
let custom_lists: Vec<String> = match response.json().await {
Ok(v) => v,
Err(e) => {
log!("error parsing custom song list index", e);
error!("Failed fetching custom song list index:", e);
return None;
}
};
@ -27,21 +22,10 @@ pub async fn fetch_custom_song_list_index() -> Option<Msg> {
}
pub async fn fetch_custom_song_list(list: String) -> Option<Msg> {
let response = match fetch(format!("/custom/list/{list}"))
.await
.and_then(|r| r.check_status())
{
Ok(response) => response,
let song_hashes: HashSet<String> = match fetch_list_of(format!("/custom/list/{list}")).await {
Ok(response) => response.into_iter().collect(),
Err(e) => {
log!("error fetching custom song list", e);
return None;
}
};
let song_hashes: HashSet<String> = match response.json().await {
Ok(v) => v,
Err(e) => {
log!("error parsing custom song list", e);
error!("Failed fetching custom song list:", e);
return None;
}
};

70
src/fetch.rs Normal file
View File

@ -0,0 +1,70 @@
use std::io::Cursor;
use gloo_net::http::{Request, Response};
use serde::de::DeserializeOwned;
use wasm_bindgen::{JsError, JsValue};
const HTTP_ACCEPT: &str = concat!("text/csv, ", "application/json;q=0.9");
#[derive(Debug, thiserror::Error)]
pub enum FetchError {
/// The request returned a non-2XX status code.
#[error("server responded with {code} {text}")]
Status { code: u16, text: String },
/// The response contained an unrecognized or missing content type.
#[error("unknown content type {0:?}")]
UnknownContentType(Option<String>),
/// Another error occured.
#[error("{0}")]
Other(#[from] gloo_net::Error),
#[error("error deserializing csv: {0}")]
Csv(#[from] csv::Error),
}
impl From<FetchError> for JsValue {
fn from(e: FetchError) -> Self {
JsError::new(&e.to_string()).into()
}
}
/// Perform a GET request.
pub async fn fetch(url: impl AsRef<str>) -> Result<Response, FetchError> {
let response = Request::get(url.as_ref())
.header("accept", HTTP_ACCEPT)
.send()
.await?;
if !response.ok() {
return Err(FetchError::Status {
code: response.status(),
text: response.status_text(),
});
}
Ok(response)
}
/// Perform a GET request and try to deserialize the response as a `Vec<T>`.
pub async fn fetch_list_of<T: DeserializeOwned>(
url: impl AsRef<str>,
) -> Result<Vec<T>, FetchError> {
let response = fetch(url.as_ref()).await?;
let headers = response.headers();
let content_type = headers.get("Content-Type").map(|s| s.to_lowercase());
match content_type.as_deref() {
Some("text/csv") => {
let text = response.text().await?;
let reader = csv::Reader::from_reader(Cursor::new(text)).into_deserialize();
let list = reader
.map(|r| r.map_err(FetchError::from))
.collect::<Result<_, _>>()?;
Ok(list)
}
Some("application/json") => Ok(response.json().await?),
_ => Err(FetchError::UnknownContentType(content_type)),
}
}

View File

@ -1,6 +1,7 @@
mod app;
mod css;
mod custom_list;
mod fetch;
mod fuzzy;
mod query;
mod song;