From a5489495f4143ba3b31be26bd218f5f854d91b27 Mon Sep 17 00:00:00 2001 From: chodak166 Date: Fri, 16 Jan 2026 20:42:20 +0100 Subject: [PATCH] WIP: basic API --- apps/app_api/src/api.rs | 2 + apps/app_api/src/api/major_pl.rs | 119 +++++++++++++++++++++++++++++++ apps/app_api/src/container.rs | 15 ++++ 3 files changed, 136 insertions(+) create mode 100644 apps/app_api/src/api/major_pl.rs diff --git a/apps/app_api/src/api.rs b/apps/app_api/src/api.rs index dbca53b..97c8167 100644 --- a/apps/app_api/src/api.rs +++ b/apps/app_api/src/api.rs @@ -4,9 +4,11 @@ use std::sync::Arc; pub mod dictionary; pub mod health; +pub mod major_pl; pub fn routes() -> Router> { Router::new() .nest("/api", health::routes()) .nest("/api", dictionary::routes()) + .nest("/api", major_pl::routes()) } diff --git a/apps/app_api/src/api/major_pl.rs b/apps/app_api/src/api/major_pl.rs new file mode 100644 index 0000000..c4caad0 --- /dev/null +++ b/apps/app_api/src/api/major_pl.rs @@ -0,0 +1,119 @@ +use axum::{ + Json, Router, + extract::{Path, Query, State}, + http::StatusCode, + response::IntoResponse, + routing::get, +}; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; + +use crate::state::AppState; + +#[derive(Debug, Deserialize)] +pub struct EncodeQuery { + pub dict: Option, +} + +#[derive(Debug, Deserialize)] +pub struct DecodeQuery { + pub dict: Option, +} + +#[derive(Debug, Serialize)] +pub struct EncodeResponse { + pub input: String, + pub dict: String, + pub result: Vec>, +} + +#[derive(Debug, Serialize)] +pub struct EncodePart { + pub value: u64, + pub words: Vec, +} + +#[derive(Debug, Serialize)] +pub struct DecodeResponse { + pub input: String, + pub result: String, +} + +#[derive(Debug, Serialize)] +pub struct ErrorResponse { + pub error: String, +} + +impl IntoResponse for ErrorResponse { + fn into_response(self) -> axum::response::Response { + (StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response() + } +} + +impl From for ErrorResponse { + fn from(err: anyhow::Error) -> Self { + Self { + error: err.to_string(), + } + } +} + +pub async fn encode_handler( + State(state): State>, + Path(input): Path, + Query(params): Query, +) -> Result, ErrorResponse> { + let dict_name = params.dict.unwrap_or_else(|| "demo_pl".to_string()); + let encoder = state + .container + .create_encoder(&dict_name) + .await + .map_err(|e| anyhow::anyhow!("Failed to create encoder: {}", e))?; + let result = encoder + .encode(&input) + .map_err(|e| anyhow::anyhow!("Failed to encode: {}", e))?; + + let encoded_parts: Vec> = result + .iter() + .map(|split| { + split + .iter() + .map(|part| EncodePart { + value: part.value, + words: part.words.clone(), + }) + .collect() + }) + .collect(); + + Ok(Json(EncodeResponse { + input, + dict: dict_name, + result: encoded_parts, + })) +} + +pub async fn decode_handler( + State(state): State>, + Path(input): Path, + Query(_params): Query, +) -> Result, ErrorResponse> { + let decoder = state + .container + .create_decoder() + .map_err(|e| anyhow::anyhow!("Failed to create decoder: {}", e))?; + let result = decoder + .decode(&input) + .map_err(|e| anyhow::anyhow!("Failed to decode: {}", e))?; + + Ok(Json(DecodeResponse { + input, + result: result.as_str().to_string(), + })) +} + +pub fn routes() -> Router> { + Router::new() + .route("/encode/major_pl/{input}", get(encode_handler)) + .route("/decode/major_pl/{input}", get(decode_handler)) +} diff --git a/apps/app_api/src/container.rs b/apps/app_api/src/container.rs index 9a319a7..6f6be09 100644 --- a/apps/app_api/src/container.rs +++ b/apps/app_api/src/container.rs @@ -28,4 +28,19 @@ impl Container { dict_repo.use_dict(dict_name); Ok(Arc::new(dict_repo)) } + + pub fn create_decoder(&self) -> anyhow::Result> { + Ok(Box::new(major::Decoder::new(major::rules_pl::get_rules()))) + } + + pub async fn create_encoder(&self, dict_name: &str) -> anyhow::Result> { + let dict = self.create_dict_repo(dict_name).await?; + let decoder = self.create_decoder()?; + let words_stream = dict.stream_batches(1000).await.unwrap(); + let lvmap = major::LenValueMap::from_stream(words_stream, &(*decoder)) + .await + .unwrap(); + let encoder = major::Encoder::new(lvmap); + Ok(Box::new(encoder)) + } }