\usepackage{rust}
جمّع LaTeX إلى PDF من Rust باستخدام FormaTeX REST API. مكتبتا reqwest وtokio غير المتزامنتان، دون تثبيت TeX Live ودون ملف تنفيذي لتضمينه.
\section{لماذا Rust}
ينسجم عميل reqwest غير المتزامن بشكل طبيعي مع بيئة تشغيل Tokio. جمّع عدة مستندات بالتزامن دون تعقيد إضافي.
يبقى ملف Rust التنفيذي لديك صغيرًا، دون TeX Live ودون apt install texlive-full. يتولى FormaTeX بيئة التجميع بالكامل.
يتناسب النوع Result في Rust جيدًا مع FormaTeX API. حوّل أخطاء HTTP إلى أخطاء المجال على مستوى النوع، دون مفاجآت وقت التشغيل.
\section{Dependencies}
[dependencies] reqwest = { version = "0.12", features = ["json"] } tokio = { version = "1", features = ["full"] } serde_json = "1" serde = { version = "1", features = ["derive"] } # For Axum integration axum = "0.7" bytes = "1"
\section{بداية سريعة}
يجمّع المثال أدناه مستند LaTeX بسيطًا باستخدام reqwest ويكتب ملف PDF الناتج على القرص. اقرأ مفتاح API من البيئة باستخدام std::env::var("FORMATEX_API_KEY") .
use reqwest::Client;
use serde_json::json;
use std::fs;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("FORMATEX_API_KEY")?;
let latex = r#"\documentclass{article}
\usepackage{amsmath}
\begin{document}
Hello from Rust! $E = mc^2$
\end{document}"#;
let client = Client::new();
let response = client
.post("https://api.formatex.io/api/v1/compile")
.header("X-API-Key", &api_key)
.json(&json!({ "latex": latex, "engine": "pdflatex" }))
.send()
.await?;
if !response.status().is_success() {
let body = response.text().await?;
return Err(format!("API error: {body}").into());
}
let pdf = response.bytes().await?;
fs::write("output.pdf", &pdf)?;
println!("PDF saved to output.pdf");
Ok(())
}\section{معالج Axum}
سجّل AppState مشتركًا في موجّه Axum لديك وركّب compile_handler على أي مسار. يقبل المعالج جسم JSON يحتوي على source وengine الاختياري، ثم يبثّ بايتات PDF مباشرة إلى العميل.
use axum::{
body::Bytes,
extract::State,
http::{HeaderMap, StatusCode},
response::{IntoResponse, Response},
Json,
};
use reqwest::Client;
use serde::Deserialize;
#[derive(Clone)]
pub struct AppState {
pub http: Client,
pub api_key: String,
}
#[derive(Deserialize)]
pub struct CompileRequest {
pub source: String,
#[serde(default = "default_engine")]
pub engine: String,
}
fn default_engine() -> String {
"pdflatex".to_string()
}
pub async fn compile_handler(
State(state): State<AppState>,
Json(body): Json<CompileRequest>,
) -> Result<Response, (StatusCode, String)> {
let res = state
.http
.post("https://api.formatex.io/api/v1/compile")
.header("X-API-Key", &state.api_key)
.json(&serde_json::json!({
"latex": body.source,
"engine": body.engine,
}))
.send()
.await
.map_err(|e| (StatusCode::BAD_GATEWAY, e.to_string()))?;
if !res.status().is_success() {
let msg = res.text().await.unwrap_or_default();
return Err((StatusCode::UNPROCESSABLE_ENTITY, msg));
}
let pdf: Bytes = res
.bytes()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
let mut headers = HeaderMap::new();
headers.insert("Content-Type", "application/pdf".parse().unwrap());
headers.insert(
"Content-Disposition",
"attachment; filename=output.pdf".parse().unwrap(),
);
Ok((headers, pdf).into_response())
}\section{Authentication}
احتفظ بمفتاح API في البيئة، ولا تكتبه أبدًا داخل ملفات المصدر. اقرأه عند بدء التشغيل وأوقف التنفيذ فورًا إذا كان مفقودًا:
// Fail fast at startup let api_key = std::env::var( "FORMATEX_API_KEY" ).expect( "FORMATEX_API_KEY not set" );
.env مع الحزمة dotenvy أثناء التطوير المحلي. X-API-Key: <key> .\section{Reference}
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
| latex | string | نعم | كود LaTeX المصدري الكامل كسلسلة نصية |
| engine | string | لا | المحرك المراد استخدامه. الافتراضي: "pdflatex". الخيارات: pdflatex وxelatex وlualatex وlatexmk |
POST https://api.formatex.io/api/v1/compile — يعيد بايتات PDF الخام عند النجاح ( 200)، أو خطأ بصيغة JSON عند الفشل (422/ 401).
\section{معالجة الأخطاء}
افحص response.status().is_success() قبل قراءة الجسم. حوّل أخطاء HTTP إلى نوع الخطأ الخاص بك لنشرها بشكل نظيف:
200 — بايتات PDF الخام. اقرأها باستخدام response.bytes().await? .422 — خطأ في تجميع LaTeX. يحتوي جسم JSON على حقل error مع مقتطف من سجل TeX.401 — مفتاح API غير صالح أو مفقود.\end{rust}
احصل على مفتاح API واحصل على ملف PDF من Rust خلال دقائق، دون الحاجة إلى TeX Live.