Spaces:
Running
Running
Upload main.rs
Browse files- src/main.rs +69 -28
src/main.rs
CHANGED
|
@@ -47,7 +47,6 @@ struct CdnCacheEntry {
|
|
| 47 |
expires_at: std::time::Instant,
|
| 48 |
}
|
| 49 |
|
| 50 |
-
#[derive(Clone)]
|
| 51 |
struct AppState {
|
| 52 |
api: Arc<Mutex<APIClient>>,
|
| 53 |
api_by_arl: Arc<RwLock<HashMap<String, Arc<Mutex<APIClient>>>>>,
|
|
@@ -943,34 +942,76 @@ async fn send_audio(
|
|
| 943 |
let mime = if ext == "flac" { "audio/flac" } else { "audio/mpeg" };
|
| 944 |
let filename = format!("track_{}.{}", q.id, ext);
|
| 945 |
|
| 946 |
-
// Загружаем в Telegram через
|
|
|
|
|
|
|
|
|
|
| 947 |
let tg_url = format!("https://api.telegram.org/bot{}/sendAudio", bot_token);
|
| 948 |
-
let
|
| 949 |
-
.
|
| 950 |
-
.
|
| 951 |
-
.
|
| 952 |
-
|
| 953 |
-
.
|
| 954 |
-
.
|
| 955 |
-
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
|
| 959 |
-
|
| 960 |
-
|
| 961 |
-
|
| 962 |
-
|
| 963 |
-
|
| 964 |
-
|
| 965 |
-
|
| 966 |
-
|
| 967 |
-
|
| 968 |
-
|
| 969 |
-
|
| 970 |
-
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 974 |
|
| 975 |
let file_id = tg_json.pointer("/result/audio/file_id")
|
| 976 |
.and_then(|v| v.as_str())
|
|
|
|
| 47 |
expires_at: std::time::Instant,
|
| 48 |
}
|
| 49 |
|
|
|
|
| 50 |
struct AppState {
|
| 51 |
api: Arc<Mutex<APIClient>>,
|
| 52 |
api_by_arl: Arc<RwLock<HashMap<String, Arc<Mutex<APIClient>>>>>,
|
|
|
|
| 942 |
let mime = if ext == "flac" { "audio/flac" } else { "audio/mpeg" };
|
| 943 |
let filename = format!("track_{}.{}", q.id, ext);
|
| 944 |
|
| 945 |
+
// Загружаем в Telegram через отдельный клиент.
|
| 946 |
+
// Для api.telegram.org в некоторых средах HF прямое соединение с no_proxy()
|
| 947 |
+
// падает на TLS handshake, поэтому здесь даем reqwest использовать env proxy
|
| 948 |
+
// и принудительно уходим на HTTP/1.1 с короткими ретраями.
|
| 949 |
let tg_url = format!("https://api.telegram.org/bot{}/sendAudio", bot_token);
|
| 950 |
+
let tg_http = reqwest::Client::builder()
|
| 951 |
+
.http1_only()
|
| 952 |
+
.connect_timeout(Duration::from_secs(20))
|
| 953 |
+
.timeout(Duration::from_secs(180))
|
| 954 |
+
.tcp_keepalive(Duration::from_secs(30))
|
| 955 |
+
.build()
|
| 956 |
+
.unwrap();
|
| 957 |
+
|
| 958 |
+
let mut tg_json: Option<serde_json::Value> = None;
|
| 959 |
+
let mut last_tg_err: Option<String> = None;
|
| 960 |
+
|
| 961 |
+
for attempt in 1..=3u8 {
|
| 962 |
+
let part = reqwest::multipart::Part::bytes(dec.clone())
|
| 963 |
+
.file_name(filename.clone())
|
| 964 |
+
.mime_str(mime)
|
| 965 |
+
.unwrap();
|
| 966 |
+
let mut form = reqwest::multipart::Form::new()
|
| 967 |
+
.text("chat_id", q.chat_id.clone())
|
| 968 |
+
.part("audio", part);
|
| 969 |
+
if let Some(ref t) = q.title { form = form.text("title", t.clone()); }
|
| 970 |
+
if let Some(ref p) = q.performer { form = form.text("performer", p.clone()); }
|
| 971 |
+
if let Some(d) = q.duration { form = form.text("duration", d.to_string()); }
|
| 972 |
+
|
| 973 |
+
match tg_http.post(&tg_url).multipart(form).send().await {
|
| 974 |
+
Ok(resp) => {
|
| 975 |
+
let status = resp.status();
|
| 976 |
+
match resp.json::<serde_json::Value>().await {
|
| 977 |
+
Ok(j) => {
|
| 978 |
+
if status.is_success() && j.get("ok").and_then(|v| v.as_bool()) == Some(true) {
|
| 979 |
+
tg_json = Some(j);
|
| 980 |
+
break;
|
| 981 |
+
}
|
| 982 |
+
let desc = j
|
| 983 |
+
.get("description")
|
| 984 |
+
.and_then(|v| v.as_str())
|
| 985 |
+
.unwrap_or("unknown")
|
| 986 |
+
.to_string();
|
| 987 |
+
tracing::warn!("Telegram sendAudio attempt {} failed: status={} desc={}", attempt, status, desc);
|
| 988 |
+
last_tg_err = Some(format!("Telegram {}: {}", status, desc));
|
| 989 |
+
}
|
| 990 |
+
Err(e) => {
|
| 991 |
+
tracing::warn!("Telegram sendAudio attempt {} parse failed: {}", attempt, e);
|
| 992 |
+
last_tg_err = Some(format!("Telegram parse: {}", e));
|
| 993 |
+
}
|
| 994 |
+
}
|
| 995 |
+
}
|
| 996 |
+
Err(e) => {
|
| 997 |
+
tracing::warn!("Telegram sendAudio attempt {} upload failed: {}", attempt, e);
|
| 998 |
+
last_tg_err = Some(format!("Telegram upload: {}", e));
|
| 999 |
+
}
|
| 1000 |
+
}
|
| 1001 |
+
|
| 1002 |
+
if attempt < 3 {
|
| 1003 |
+
tokio::time::sleep(Duration::from_secs((attempt as u64) * 2)).await;
|
| 1004 |
+
}
|
| 1005 |
+
}
|
| 1006 |
+
|
| 1007 |
+
let tg_json = match tg_json {
|
| 1008 |
+
Some(j) => j,
|
| 1009 |
+
None => {
|
| 1010 |
+
let err = last_tg_err.unwrap_or_else(|| "Telegram upload failed".to_string());
|
| 1011 |
+
tracing::error!("Telegram sendAudio final failure: {}", err);
|
| 1012 |
+
return json_error(StatusCode::BAD_GATEWAY, err);
|
| 1013 |
+
}
|
| 1014 |
+
};
|
| 1015 |
|
| 1016 |
let file_id = tg_json.pointer("/result/audio/file_id")
|
| 1017 |
.and_then(|v| v.as_str())
|