use serde::{Deserialize, Serialize};
use skyzen::{
routing::{CreateRouteNode, Params, Route, Router},
utils::Json,
Result as SkyResult,
};
use skyzen_services::{Kv, Storage};
use skyzen_test::mock::{InMemoryKv, InMemoryStorage};
#[derive(Debug, Serialize, Deserialize)]
struct FileMetadata {
name: String,
size: usize,
}
#[derive(Debug, Deserialize)]
struct UploadRequest {
name: String,
content: String,
}
async fn list_files(kv: Kv) -> SkyResult<Json<Vec<String>>> {
let keys = kv
.list(Some("file:"))
.await
.map_err(|e| skyzen::Error::msg(e.to_string()))?;
Ok(Json(keys))
}
async fn get_file(kv: Kv, params: Params) -> SkyResult<Json<Option<FileMetadata>>> {
let name = params.get("name")?;
let meta = kv
.get_json::<FileMetadata>(&format!("file:{name}"))
.await
.map_err(|e| skyzen::Error::msg(e.to_string()))?;
Ok(Json(meta))
}
async fn upload_file(
kv: Kv,
storage: Storage,
Json(body): Json<UploadRequest>,
) -> SkyResult<&'static str> {
let data = body.content.into_bytes();
let meta = FileMetadata {
name: body.name.clone(),
size: data.len(),
};
storage
.put(&body.name, data)
.await
.map_err(|e| skyzen::Error::msg(e.to_string()))?;
kv.put_json(&format!("file:{}", body.name), &meta)
.await
.map_err(|e| skyzen::Error::msg(e.to_string()))?;
Ok("uploaded")
}
fn build_router(kv: Kv, storage: Storage) -> Router {
Route::new((
"/files".at(list_files),
"/files".post(upload_file),
"/files".route(("/{name}".at(get_file),)),
))
.with(kv)
.with(storage)
.build()
}
#[skyzen::main]
fn main() -> Router {
let kv = Kv::new(InMemoryKv::new());
let storage = Storage::new(InMemoryStorage::new());
build_router(kv, storage)
}