bug fixes & improvements & missing features & font loader

This commit is contained in:
2026-04-07 00:36:21 +03:00
parent ad0d2fda0a
commit b6287906a9
50 changed files with 4087 additions and 1843 deletions

View File

@@ -0,0 +1,77 @@
use axum::{
Router,
extract::{Path, State},
http::{StatusCode, header},
response::IntoResponse,
routing::get,
Json,
};
use dreport_layout::font_provider::FontProvider;
use serde::Serialize;
use std::sync::Arc;
use crate::font_registry::FontRegistry;
#[derive(Serialize)]
struct FontFamilyResponse {
family: String,
variants: Vec<FontVariantResponse>,
}
#[derive(Serialize)]
struct FontVariantResponse {
weight: u16,
italic: bool,
}
/// GET /api/fonts — list all available font families
async fn list_fonts(
State(registry): State<Arc<FontRegistry>>,
) -> Json<Vec<FontFamilyResponse>> {
let families = registry.list_families();
let response: Vec<FontFamilyResponse> = families
.into_iter()
.map(|f| FontFamilyResponse {
family: f.family,
variants: f.variants
.into_iter()
.map(|v| FontVariantResponse {
weight: v.weight,
italic: v.italic,
})
.collect(),
})
.collect();
Json(response)
}
/// GET /api/fonts/:family/:weight/:italic — serve font binary
async fn get_font(
State(registry): State<Arc<FontRegistry>>,
Path((family, weight, italic)): Path<(String, u16, String)>,
) -> impl IntoResponse {
let is_italic = italic == "true" || italic == "1";
match registry.get_font_bytes(&family, weight, is_italic) {
Some(data) => (
StatusCode::OK,
[(header::CONTENT_TYPE, "font/ttf")],
data.to_vec(),
)
.into_response(),
None => (
StatusCode::NOT_FOUND,
format!(
"Font bulunamadı: {} weight={} italic={}",
family, weight, is_italic
),
)
.into_response(),
}
}
pub fn router() -> Router<Arc<FontRegistry>> {
Router::new()
.route("/api/fonts", get(list_fonts))
.route("/api/fonts/{family}/{weight}/{italic}", get(get_font))
}

View File

@@ -1,8 +1,9 @@
use axum::{Router, routing::get, Json};
use dreport_layout::FontData;
use serde::Serialize;
use std::sync::Arc;
use crate::font_registry::FontRegistry;
#[derive(Serialize)]
struct HealthResponse {
status: &'static str,
@@ -16,6 +17,6 @@ async fn health() -> Json<HealthResponse> {
})
}
pub fn router() -> Router<Arc<Vec<FontData>>> {
pub fn router() -> Router<Arc<FontRegistry>> {
Router::new().route("/api/health", get(health))
}

View File

@@ -1,12 +1,15 @@
mod fonts;
mod health;
mod render;
use axum::Router;
use dreport_layout::FontData;
use std::sync::Arc;
pub fn router() -> Router<Arc<Vec<FontData>>> {
use crate::font_registry::FontRegistry;
pub fn router() -> Router<Arc<FontRegistry>> {
Router::new()
.merge(health::router())
.merge(render::router())
.merge(fonts::router())
}

View File

@@ -6,10 +6,10 @@ use axum::{
routing::post,
Json,
};
use dreport_layout::FontData;
use serde::Deserialize;
use std::sync::Arc;
use crate::font_registry::FontRegistry;
use crate::models::Template;
#[derive(Deserialize)]
@@ -20,28 +20,39 @@ pub struct RenderRequest {
/// POST /api/render — Template + Data → PDF
pub async fn render(
State(fonts): State<Arc<Vec<FontData>>>,
State(registry): State<Arc<FontRegistry>>,
Json(payload): Json<RenderRequest>,
) -> impl IntoResponse {
// 1. Layout hesapla
let layout = dreport_layout::compute_layout(&payload.template, &payload.data, &fonts);
// CPU-intensive layout + PDF render'ı blocking thread'de çalıştır
let result = tokio::task::spawn_blocking(move || {
// Template'in fonts alanına göre sadece gerekli fontları yükle
let fonts = registry.fonts_for_families(&payload.template.fonts);
let layout = dreport_layout::compute_layout(&payload.template, &payload.data, &fonts)
.map_err(|e| format!("Layout error: {}", e))?;
dreport_layout::pdf_render::render_pdf(&layout, &fonts)
})
.await;
// 2. PDF render
match dreport_layout::pdf_render::render_pdf(&layout, &fonts) {
Ok(pdf_bytes) => (
match result {
Ok(Ok(pdf_bytes)) => (
StatusCode::OK,
[(header::CONTENT_TYPE, "application/pdf")],
pdf_bytes,
)
.into_response(),
Ok(Err(err)) => (
StatusCode::INTERNAL_SERVER_ERROR,
format!("PDF render hatası: {}", err),
)
.into_response(),
Err(err) => (
StatusCode::INTERNAL_SERVER_ERROR,
format!("PDF render hatasi: {}", err),
format!("Task hatası: {}", err),
)
.into_response(),
}
}
pub fn router() -> Router<Arc<Vec<FontData>>> {
pub fn router() -> Router<Arc<FontRegistry>> {
Router::new().route("/api/render", post(render))
}