wip
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use crate::codec::ron::Ron;
|
||||
use crate::codec::ron::RonEncoded;
|
||||
use crate::components::StyledHeader;
|
||||
use crate::components::header::HeaderItem;
|
||||
use crate::components::header::HeaderItems;
|
||||
@@ -12,9 +14,6 @@ use leptos_router::params::Params;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use server_fn::codec::Cbor;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Cursor;
|
||||
use std::path::Path;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::FileList;
|
||||
@@ -110,7 +109,7 @@ fn Hold(wall_uid: models::WallUid, hold: models::Hold) -> impl IntoView {
|
||||
|
||||
let hold = Signal::derive(move || {
|
||||
let refreshed = upload.value().get().map(Result::unwrap);
|
||||
refreshed.unwrap_or(hold.clone())
|
||||
refreshed.map(RonEncoded::into_inner).unwrap_or(hold.clone())
|
||||
});
|
||||
|
||||
// Callback to handle file selection
|
||||
@@ -176,17 +175,28 @@ pub struct Image {
|
||||
file_contents: Vec<u8>,
|
||||
}
|
||||
|
||||
#[server(name = SetImage, input = Cbor)]
|
||||
#[server(
|
||||
name = SetImage,
|
||||
input = Cbor,
|
||||
output = Ron,
|
||||
)]
|
||||
#[tracing::instrument(skip(image), err)]
|
||||
async fn set_image(wall_uid: WallUid, hold_position: HoldPosition, image: Image) -> Result<models::Hold, ServerFnError> {
|
||||
async fn set_image(wall_uid: WallUid, hold_position: HoldPosition, image: Image) -> Result<RonEncoded<models::Hold>, ServerFnError> {
|
||||
use image::ImageDecoder;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
tracing::info!("Setting image, {}, {} bytes", image.file_name, image.file_contents.len());
|
||||
|
||||
let db = expect_context::<crate::server::db::Database>();
|
||||
|
||||
let image = tokio::task::spawn_blocking(move || -> Result<models::Image, ServerFnError> {
|
||||
let img = image::ImageReader::new(Cursor::new(image.file_contents))
|
||||
let mut decoder = image::ImageReader::new(std::io::Cursor::new(image.file_contents))
|
||||
.with_guessed_format()?
|
||||
.decode()?;
|
||||
.into_decoder()?;
|
||||
let orientation = decoder.orientation()?;
|
||||
let mut img = image::DynamicImage::from_decoder(decoder)?;
|
||||
img.apply_orientation(orientation);
|
||||
|
||||
let holds_dir = Path::new("datastore/public/holds");
|
||||
std::fs::create_dir_all(holds_dir)?;
|
||||
@@ -200,7 +210,7 @@ async fn set_image(wall_uid: WallUid, hold_position: HoldPosition, image: Image)
|
||||
|
||||
let filename = format!("hold_row{}_col{}_{width}x{height}_{uid}.webp", hold_position.row, hold_position.col);
|
||||
let path = holds_dir.join(&filename);
|
||||
let mut file = std::fs::File::open(&path)?;
|
||||
let mut file = std::fs::OpenOptions::new().write(true).append(false).create_new(true).open(&path)?;
|
||||
resized.write_to(&mut file, image::ImageFormat::WebP)?;
|
||||
|
||||
let res = models::ImageResolution {
|
||||
@@ -216,34 +226,20 @@ async fn set_image(wall_uid: WallUid, hold_position: HoldPosition, image: Image)
|
||||
})
|
||||
.await??;
|
||||
|
||||
db.write(move |txn| {
|
||||
use redb::ReadableTable;
|
||||
let mut walls = txn.open_table(crate::server::db::current::TABLE_WALLS)?;
|
||||
let mut wall = walls.get(wall_uid)?.expect("todo").value();
|
||||
let hold = db
|
||||
.write(move |txn| {
|
||||
use redb::ReadableTable;
|
||||
let mut walls = txn.open_table(crate::server::db::current::TABLE_WALLS)?;
|
||||
let mut wall = walls.get(wall_uid)?.expect("todo").value();
|
||||
|
||||
if let Some(hold) = wall.holds.get_mut(&hold_position) {
|
||||
let hold = wall.holds.get_mut(&hold_position).expect("hold");
|
||||
hold.image = Some(image);
|
||||
}
|
||||
let hold = hold.clone();
|
||||
walls.insert(wall_uid, wall)?;
|
||||
|
||||
walls.insert(wall_uid, wall);
|
||||
Ok(hold)
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
|
||||
// let state = expect_context::<State>();
|
||||
// state
|
||||
// .persistent
|
||||
// .update(|s| {
|
||||
// if let Some(hold) = s.wall.holds.get_mut(&hold_position) {
|
||||
// hold.image = Some(models::Image { filename });
|
||||
// }
|
||||
// })
|
||||
// .await?;
|
||||
|
||||
// // Return updated hold
|
||||
// let hold = state.persistent.with(|s| s.wall.holds.get(&hold_position).cloned().unwrap()).await;
|
||||
|
||||
let hold = todo!();
|
||||
Ok(hold)
|
||||
Ok(RonEncoded::new(hold))
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use super::db;
|
||||
use super::db::Database;
|
||||
use crate::models;
|
||||
use image::ImageDecoder;
|
||||
use redb::ReadableTable;
|
||||
use redb::ReadableTableMetadata;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use type_toppings::ResultExt;
|
||||
|
||||
@@ -123,22 +126,66 @@ async fn migrate_to_v2(db: &Database) -> Result<(), Box<dyn std::error::Error>>
|
||||
let holds = wall
|
||||
.holds
|
||||
.into_iter()
|
||||
.map(|(hold_position, hold)| {
|
||||
(
|
||||
.map(|(hold_position, hold)| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let image = hold
|
||||
.image
|
||||
.map(|i| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let holds_dir = Path::new("datastore/public/holds");
|
||||
|
||||
let p = holds_dir.join(i.filename);
|
||||
tracing::info!("reading {}", p.display());
|
||||
let file_contents = std::fs::read(p)?;
|
||||
|
||||
let mut decoder = image::ImageReader::new(std::io::Cursor::new(file_contents))
|
||||
.with_guessed_format()?
|
||||
.into_decoder()?;
|
||||
let orientation = decoder.orientation()?;
|
||||
let mut img = image::DynamicImage::from_decoder(decoder)?;
|
||||
img.apply_orientation(orientation);
|
||||
|
||||
std::fs::create_dir_all(holds_dir)?;
|
||||
|
||||
let targets = [(50, 50), (150, 150), (300, 300), (400, 400)];
|
||||
|
||||
let uid = models::ImageUid::create();
|
||||
let mut resolutions = BTreeMap::new();
|
||||
for (width, height) in targets {
|
||||
tracing::info!("resizing to {width}x{height}");
|
||||
let resized = img.resize_to_fill(width, height, image::imageops::FilterType::Lanczos3);
|
||||
|
||||
let filename = format!("hold_row{}_col{}_{width}x{height}_{uid}.webp", hold_position.row, hold_position.col);
|
||||
let path = holds_dir.join(&filename);
|
||||
tracing::info!("opening {}", path.display());
|
||||
let mut file = std::fs::OpenOptions::new().write(true).append(false).create_new(true).open(&path)?;
|
||||
resized.write_to(&mut file, image::ImageFormat::WebP)?;
|
||||
|
||||
let res = models::ImageResolution {
|
||||
width: width.into(),
|
||||
height: height.into(),
|
||||
};
|
||||
resolutions.insert(res, models::ImageFilename { filename });
|
||||
}
|
||||
|
||||
Ok(models::Image { uid, resolutions })
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
Ok((
|
||||
models::v1::HoldPosition {
|
||||
row: hold_position.row,
|
||||
col: hold_position.col,
|
||||
},
|
||||
models::v1::Hold {
|
||||
models::v2::Hold {
|
||||
position: models::v1::HoldPosition {
|
||||
row: hold.position.row,
|
||||
col: hold.position.col,
|
||||
},
|
||||
image: hold.image.map(|i| models::v1::Image { filename: i.filename }),
|
||||
image,
|
||||
},
|
||||
)
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<_, _>>()
|
||||
.unwrap();
|
||||
|
||||
let wall_v2 = models::v2::Wall {
|
||||
uid: wall_uid,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::codec::ron::Ron;
|
||||
use crate::codec::ron::RonEncoded;
|
||||
use crate::models;
|
||||
use leptos::prelude::expect_context;
|
||||
use leptos::server;
|
||||
use server_fn::ServerFnError;
|
||||
|
||||
@@ -13,6 +12,7 @@ use server_fn::ServerFnError;
|
||||
#[tracing::instrument(skip_all, err(Debug))]
|
||||
pub async fn get_walls() -> Result<RonEncoded<Vec<models::Wall>>, ServerFnError> {
|
||||
use crate::server::db::Database;
|
||||
use leptos::prelude::expect_context;
|
||||
use redb::ReadableTable;
|
||||
tracing::debug!("Enter");
|
||||
|
||||
@@ -40,6 +40,7 @@ pub async fn get_walls() -> Result<RonEncoded<Vec<models::Wall>>, ServerFnError>
|
||||
pub(crate) async fn get_wall(wall_uid: models::WallUid) -> Result<RonEncoded<models::Wall>, ServerFnError> {
|
||||
use crate::server::db::Database;
|
||||
use crate::server::db::DatabaseOperationError;
|
||||
use leptos::prelude::expect_context;
|
||||
tracing::debug!("Enter");
|
||||
|
||||
#[derive(Debug, derive_more::Error, derive_more::Display)]
|
||||
@@ -76,6 +77,7 @@ pub(crate) async fn get_wall(wall_uid: models::WallUid) -> Result<RonEncoded<mod
|
||||
pub(crate) async fn get_problems_for_wall(wall_uid: models::WallUid) -> Result<RonEncoded<Vec<models::Problem>>, ServerFnError> {
|
||||
use crate::server::db::Database;
|
||||
use crate::server::db::DatabaseOperationError;
|
||||
use leptos::prelude::expect_context;
|
||||
tracing::debug!("Enter");
|
||||
|
||||
#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
|
||||
@@ -134,6 +136,7 @@ pub(crate) async fn get_problems_for_wall(wall_uid: models::WallUid) -> Result<R
|
||||
pub(crate) async fn get_problem(wall_uid: models::WallUid, problem_uid: models::ProblemUid) -> Result<RonEncoded<models::Problem>, ServerFnError> {
|
||||
use crate::server::db::Database;
|
||||
use crate::server::db::DatabaseOperationError;
|
||||
use leptos::prelude::expect_context;
|
||||
tracing::debug!("Enter");
|
||||
|
||||
#[derive(Debug, derive_more::Error, derive_more::Display)]
|
||||
|
||||
Reference in New Issue
Block a user