v1.0.7, fix Identical filenames caused settings to overwrite each other
This commit is contained in:
39
src/main.rs
39
src/main.rs
@ -22,7 +22,7 @@ use tracing::info;
|
|||||||
|
|
||||||
async fn get_version() -> impl IntoResponse {
|
async fn get_version() -> impl IntoResponse {
|
||||||
Json(serde_json::json!({
|
Json(serde_json::json!({
|
||||||
"version": "1.0.6",
|
"version": "1.0.7",
|
||||||
"timestamp": chrono::Utc::now().timestamp()
|
"timestamp": chrono::Utc::now().timestamp()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -192,17 +192,19 @@ async fn create_print(
|
|||||||
) -> Result<Json<JobView>, (StatusCode, String)> {
|
) -> Result<Json<JobView>, (StatusCode, String)> {
|
||||||
info!("📥 Получен запрос на печать");
|
info!("📥 Получен запрос на печать");
|
||||||
|
|
||||||
let mut settings_map: HashMap<String, PrintSettings> = HashMap::new();
|
let mut settings_list: Vec<Option<PrintSettings>> = Vec::new();
|
||||||
let mut files_data: Vec<(String, bytes::Bytes)> = Vec::new();
|
let mut files_data: Vec<(String, bytes::Bytes)> = Vec::new();
|
||||||
|
|
||||||
while let Some(field) = multipart.next_field().await.unwrap_or(None) {
|
while let Some(field) = multipart.next_field().await.unwrap_or(None) {
|
||||||
let field_name = field.name().unwrap_or("").to_string();
|
let field_name = field.name().unwrap_or("").to_string();
|
||||||
|
|
||||||
if field_name == "settings" {
|
if field_name == "settings" {
|
||||||
if let Ok(text) = field.text().await {
|
let parsed = match field.text().await {
|
||||||
if let Ok(s) = serde_json::from_str::<PrintSettings>(&text) {
|
Ok(text) => serde_json::from_str::<PrintSettings>(&text).ok(),
|
||||||
settings_map.insert(s.filename.clone(), s);
|
Err(_) => None,
|
||||||
}
|
};
|
||||||
}
|
// Пушим даже при ошибке парсинга (None), чтобы индексы не съезжали
|
||||||
|
settings_list.push(parsed);
|
||||||
} else if field_name == "files" {
|
} else if field_name == "files" {
|
||||||
let file_name = field.file_name().unwrap_or("unknown").to_string();
|
let file_name = field.file_name().unwrap_or("unknown").to_string();
|
||||||
if let Ok(data) = field.bytes().await {
|
if let Ok(data) = field.bytes().await {
|
||||||
@ -216,21 +218,26 @@ async fn create_print(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut job_files: Vec<JobFile> = Vec::new();
|
let mut job_files: Vec<JobFile> = Vec::new();
|
||||||
for (file_name, data) in files_data {
|
|
||||||
|
for (i, (file_name, data)) in files_data.into_iter().enumerate() {
|
||||||
let ext = Path::new(&file_name)
|
let ext = Path::new(&file_name)
|
||||||
.extension()
|
.extension()
|
||||||
.and_then(|e| e.to_str())
|
.and_then(|e| e.to_str())
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
|
|
||||||
let temp = if ext.is_empty() {
|
let temp = if ext.is_empty() {
|
||||||
NamedTempFile::new()
|
NamedTempFile::new()
|
||||||
} else {
|
} else {
|
||||||
NamedTempFile::with_suffix(&format!(".{}", ext))
|
NamedTempFile::with_suffix(&format!(".{}", ext))
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(temp) = temp {
|
if let Ok(temp) = temp {
|
||||||
let path = temp.into_temp_path();
|
let path = temp.into_temp_path();
|
||||||
if fs::write(&*path, &data).await.is_ok() {
|
if fs::write(&*path, &data).await.is_ok() {
|
||||||
let settings = settings_map.get(&file_name).cloned();
|
// i-й файл ↔ i-й набор настроек — имена могут совпадать
|
||||||
|
let settings = settings_list.get(i).cloned().flatten();
|
||||||
|
|
||||||
job_files.push(JobFile {
|
job_files.push(JobFile {
|
||||||
name: file_name,
|
name: file_name,
|
||||||
path,
|
path,
|
||||||
@ -258,6 +265,7 @@ async fn create_print(
|
|||||||
|
|
||||||
let view = job.view();
|
let view = job.view();
|
||||||
store.lock().unwrap().insert(job_id.clone(), job);
|
store.lock().unwrap().insert(job_id.clone(), job);
|
||||||
|
|
||||||
Ok(Json(view))
|
Ok(Json(view))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,27 +534,18 @@ fn run_lp(path: &Path, settings: Option<&PrintSettings>, duplex_pass: Option<&st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────────────────────────────────────────────────
|
|
||||||
// СЛОТЫ:
|
|
||||||
// • Первый проход дуплекса (odd) → Upper
|
|
||||||
// • Второй проход дуплекса (even) → Lower (ручная подача)
|
|
||||||
// • Обычная печать (не дуплекс) → Upper
|
|
||||||
// ──────────────────────────────────────────────────────────
|
|
||||||
match duplex_pass {
|
match duplex_pass {
|
||||||
Some("odd") => {
|
Some("odd") => {
|
||||||
// ПЕРВЫЙ проход — обычный лоток
|
|
||||||
cmd.arg("-o").arg("InputSlot=Upper");
|
cmd.arg("-o").arg("InputSlot=Upper");
|
||||||
cmd.arg("-o").arg("page-set=odd");
|
cmd.arg("-o").arg("page-set=odd"); // Нечётные страницы
|
||||||
}
|
}
|
||||||
Some("even") => {
|
Some("even") => {
|
||||||
// ВТОРОЙ проход — ручная подача
|
|
||||||
cmd.arg("-o").arg("InputSlot=Lower");
|
cmd.arg("-o").arg("InputSlot=Lower");
|
||||||
cmd.arg("-o").arg("page-set=even");
|
cmd.arg("-o").arg("page-set=even"); // Чётные страницы
|
||||||
cmd.arg("-o").arg("outputorder=reverse");
|
cmd.arg("-o").arg("outputorder=reverse");
|
||||||
cmd.arg("-o").arg("orientation-requested=6");
|
cmd.arg("-o").arg("orientation-requested=6");
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Обычная односторонняя печать
|
|
||||||
cmd.arg("-o").arg("InputSlot=Upper");
|
cmd.arg("-o").arg("InputSlot=Upper");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user