⬆️ migration mdns →mddns-sd
- Remplacer la crate abandonnée `mdns` (3.0, non-UTF8) par activement maintenue et UTF‑compliant `mdns-sd` (0.19) - Supprimer les dépendances inutiles `async‑std`, `futures-util` (uniquement utilisées dans le thread mDNS) - Refactoriser `control_point.rs` : passer d’un bloc async bloquant à une boucle synchrone avec `ServiceDaemon.browse()` + récepteur blocant - Simplifier drastiquement le parsing dans `chromecast_discovery.rs` via l’API haut‑niveau de mdns-sd (`ServiceInfo`, `get_property_val_str`) → ~80 lignes remplacées par 52 - Ajouter index SQLite `idx_metadata_key_value` pour accélérer les requêtes par origin_url - Nettoyer exports inutiles dans `pmomediaserver::server_ext` - Supprimer filtre de bruit obsolète `mdns=error` dans les logs - Met à jour la version en 0.3.42
This commit is contained in:
306
Blackboard/Todo/mdns_sd_migration.md
Normal file
306
Blackboard/Todo/mdns_sd_migration.md
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
# Migration `mdns` → `mdns-sd`
|
||||||
|
|
||||||
|
## Contexte
|
||||||
|
|
||||||
|
La crate `mdns 3.0.0` (dernière version, 2021, abandonnée) s'appuie sur `dns-parser 0.8.0`
|
||||||
|
qui rejette les labels DNS non-ASCII avec `LabelIsNotAscii`. Les appareils Apple utilisent
|
||||||
|
U+2019 (RIGHT SINGLE QUOTATION MARK) dans leurs noms (ex : "Sophie's MacBook Air"), ce qui
|
||||||
|
spamme les logs en WARN à chaque paquet mDNS reçu.
|
||||||
|
|
||||||
|
`mdns-sd 0.19` (avril 2026, activement maintenu) gère l'UTF-8 correctement, fournit une API
|
||||||
|
de plus haut niveau (service pré-assemblé), et ne nécessite pas `async-std`.
|
||||||
|
|
||||||
|
## Périmètre
|
||||||
|
|
||||||
|
Deux fichiers à modifier, un fichier à nettoyer :
|
||||||
|
|
||||||
|
| Fichier | Rôle |
|
||||||
|
|---|---|
|
||||||
|
| `pmocontrol/Cargo.toml` | Dépendances |
|
||||||
|
| `pmocontrol/src/control_point.rs` | Thread de découverte mDNS (lignes 145–195) |
|
||||||
|
| `pmocontrol/src/discovery/chromecast_discovery.rs` | Parsing des réponses mDNS |
|
||||||
|
| `pmoserver/src/logs/mod.rs` | Filtre de bruit `mdns=error` devenu inutile |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 1 — `pmocontrol/Cargo.toml`
|
||||||
|
|
||||||
|
### Supprimer
|
||||||
|
```toml
|
||||||
|
mdns = "3.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier si `async-std` et `futures-util` sont utilisés **ailleurs** que dans le thread mDNS.
|
||||||
|
D'après l'analyse :
|
||||||
|
- `async_std` : uniquement `control_point.rs:161` → **supprimer**
|
||||||
|
- `futures-util` : uniquement `control_point.rs:150,167` → **supprimer**
|
||||||
|
|
||||||
|
### Ajouter
|
||||||
|
```toml
|
||||||
|
mdns-sd = "0.19"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 2 — `pmocontrol/src/control_point.rs`
|
||||||
|
|
||||||
|
### Code actuel (lignes 145–195) à remplacer intégralement
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Thread de découverte mDNS pour Chromecast
|
||||||
|
let registry_for_mdns = Arc::clone(®istry);
|
||||||
|
let udn_cache_for_mdns = Arc::clone(&udn_cache);
|
||||||
|
thread::spawn(move || {
|
||||||
|
use crate::discovery::ChromecastDiscoveryManager;
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
|
||||||
|
let mut discovery_manager =
|
||||||
|
ChromecastDiscoveryManager::new(registry_for_mdns, udn_cache_for_mdns);
|
||||||
|
|
||||||
|
debug!("Starting mDNS discovery thread for Chromecast devices");
|
||||||
|
|
||||||
|
const SERVICE_NAME: &str = "_googlecast._tcp.local";
|
||||||
|
|
||||||
|
async_std::task::block_on(async {
|
||||||
|
match mdns::discover::all(SERVICE_NAME, Duration::from_secs(15)) {
|
||||||
|
Ok(discovery) => {
|
||||||
|
let stream = discovery.listen();
|
||||||
|
futures_util::pin_mut!(stream);
|
||||||
|
debug!("mDNS discovery stream started for Chromecast devices");
|
||||||
|
while let Some(result) = stream.next().await {
|
||||||
|
match result {
|
||||||
|
Ok(response) => {
|
||||||
|
debug!("Received mDNS response with {} records", response.records().count());
|
||||||
|
discovery_manager.handle_mdns_response(response);
|
||||||
|
}
|
||||||
|
Err(e) => { warn!("mDNS discovery error: {}", e); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warn!("mDNS discovery stream ended unexpectedly");
|
||||||
|
}
|
||||||
|
Err(e) => { error!("Failed to start mDNS discovery: {}", e); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nouveau code
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Thread de découverte mDNS pour Chromecast
|
||||||
|
let registry_for_mdns = Arc::clone(®istry);
|
||||||
|
let udn_cache_for_mdns = Arc::clone(&udn_cache);
|
||||||
|
thread::spawn(move || {
|
||||||
|
use crate::discovery::ChromecastDiscoveryManager;
|
||||||
|
use mdns_sd::{ServiceDaemon, ServiceEvent};
|
||||||
|
|
||||||
|
let mut discovery_manager =
|
||||||
|
ChromecastDiscoveryManager::new(registry_for_mdns, udn_cache_for_mdns);
|
||||||
|
|
||||||
|
debug!("Starting mDNS discovery thread for Chromecast devices");
|
||||||
|
|
||||||
|
// Note: mdns-sd requires the trailing dot in the service type
|
||||||
|
const SERVICE_TYPE: &str = "_googlecast._tcp.local.";
|
||||||
|
|
||||||
|
let daemon = match ServiceDaemon::new() {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to create mDNS daemon: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let receiver = match daemon.browse(SERVICE_TYPE) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to start mDNS browse for {}: {}", SERVICE_TYPE, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("mDNS discovery started for Chromecast devices");
|
||||||
|
|
||||||
|
while let Ok(event) = receiver.recv() {
|
||||||
|
match event {
|
||||||
|
ServiceEvent::ServiceResolved(info) => {
|
||||||
|
debug!(
|
||||||
|
fullname = info.get_fullname(),
|
||||||
|
host = info.get_hostname(),
|
||||||
|
port = info.get_port(),
|
||||||
|
"mDNS Chromecast service resolved"
|
||||||
|
);
|
||||||
|
discovery_manager.handle_service_resolved(&info);
|
||||||
|
}
|
||||||
|
ServiceEvent::ServiceRemoved(_service_type, fullname) => {
|
||||||
|
debug!(fullname = %fullname, "mDNS Chromecast service removed");
|
||||||
|
// Pas de retrait actif du registre : le timeout habituel s'en charge
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!("mDNS discovery receiver closed");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Points d'attention
|
||||||
|
- Le point final `.` dans `"_googlecast._tcp.local."` est **obligatoire** pour `mdns-sd`.
|
||||||
|
- `receiver.recv()` est bloquant synchrone — pas besoin d'async runtime.
|
||||||
|
- `ServiceDaemon` gère son propre thread interne ; inutile de relancer manuellement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 3 — `pmocontrol/src/discovery/chromecast_discovery.rs`
|
||||||
|
|
||||||
|
### Supprimer l'import `mdns`
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Supprimer ces uses implicites via le type dans la signature
|
||||||
|
use std::collections::HashMap; // <- plus nécessaire si on passe par TxtProperties
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ajouter l'import `mdns-sd`
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use mdns_sd::ServiceInfo;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Remplacer `handle_mdns_response` par `handle_service_resolved`
|
||||||
|
|
||||||
|
#### Code actuel (lignes 39–179) — ~80 lignes de parsing manuel
|
||||||
|
|
||||||
|
Toute la logique d'extraction PTR / A / AAAA / SRV / TXT disparaît.
|
||||||
|
|
||||||
|
#### Nouveau code
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// Traite un service Chromecast résolu par mDNS-SD.
|
||||||
|
///
|
||||||
|
/// `ServiceInfo` arrive pré-assemblé : plus besoin de jointure manuelle
|
||||||
|
/// des enregistrements PTR / A / SRV / TXT.
|
||||||
|
pub fn handle_service_resolved(&mut self, info: &ServiceInfo) {
|
||||||
|
let fullname = info.get_fullname().to_string();
|
||||||
|
|
||||||
|
debug!("Processing resolved Chromecast service: {}", fullname);
|
||||||
|
|
||||||
|
// Adresse IP : préférer IPv4
|
||||||
|
let host = match info
|
||||||
|
.get_addresses()
|
||||||
|
.iter()
|
||||||
|
.find(|a| a.is_ipv4())
|
||||||
|
.or_else(|| info.get_addresses().iter().next())
|
||||||
|
{
|
||||||
|
Some(addr) => addr.to_string(),
|
||||||
|
None => {
|
||||||
|
warn!("No IP address for Chromecast service: {}", fullname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let port = info.get_port();
|
||||||
|
|
||||||
|
// TXT records — API directe par clé
|
||||||
|
let uuid = info
|
||||||
|
.get_property_val_str("id")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string();
|
||||||
|
let uuid = if uuid.is_empty() {
|
||||||
|
format!("chromecast-{}-{}", host, port)
|
||||||
|
} else {
|
||||||
|
uuid
|
||||||
|
};
|
||||||
|
|
||||||
|
let model = info.get_property_val_str("md").map(|s| s.to_string());
|
||||||
|
|
||||||
|
let friendly_name = info
|
||||||
|
.get_property_val_str("fn")
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
// Fallback : extraire depuis le fullname, supprimer le suffixe de service
|
||||||
|
fullname
|
||||||
|
.split("._googlecast._tcp.local")
|
||||||
|
.next()
|
||||||
|
.unwrap_or("Unknown Chromecast")
|
||||||
|
.split('-')
|
||||||
|
.take_while(|part| part.len() != 32)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("-")
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
});
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Discovered Chromecast: {} at {}:{} (UUID: {}, Model: {:?})",
|
||||||
|
friendly_name, host, port, uuid, model
|
||||||
|
);
|
||||||
|
|
||||||
|
let udn = format!("uuid:{}", uuid);
|
||||||
|
let default_max_age = 1800u64;
|
||||||
|
|
||||||
|
if !UDNRegistry::should_fetch(self.udn_cache.clone(), &udn, default_max_age) {
|
||||||
|
debug!("Chromecast {} recently seen, skipping", udn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let renderer_info = build_renderer_info(
|
||||||
|
&uuid,
|
||||||
|
&friendly_name,
|
||||||
|
&host,
|
||||||
|
port,
|
||||||
|
model.as_deref(),
|
||||||
|
Some("Google Inc."),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.device_registry
|
||||||
|
.write()
|
||||||
|
.expect("DeviceRegistry mutex lock failed")
|
||||||
|
.push_renderer(&renderer_info, default_max_age as u32);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Supprimer
|
||||||
|
- L'import `use std::collections::HashMap` (plus utilisé)
|
||||||
|
- Tout le bloc `handle_mdns_response` (lignes 39–179)
|
||||||
|
|
||||||
|
### Conserver sans modification
|
||||||
|
- `build_renderer_info` (lignes 182–234)
|
||||||
|
- `extract_host_from_location` / `extract_port_from_location` (lignes 239–258)
|
||||||
|
- Les tests (lignes 260–287)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 4 — `pmoserver/src/logs/mod.rs`
|
||||||
|
|
||||||
|
Le filtre de bruit `mdns=error` injecté dans `build_filter_with_noise_suppressions` n'est
|
||||||
|
plus nécessaire. Deux options :
|
||||||
|
|
||||||
|
**Option A (recommandée)** — Supprimer l'entrée du tableau :
|
||||||
|
```rust
|
||||||
|
const NOISE_FILTERS: &[(&str, &str)] = &[
|
||||||
|
// ("mdns", "mdns=error"), // supprimé : migration vers mdns-sd
|
||||||
|
];
|
||||||
|
```
|
||||||
|
Ou supprimer `build_filter_with_noise_suppressions` entièrement si aucun autre bruit n'est
|
||||||
|
à filtrer, et revenir à `EnvFilter::try_new(base)` direct.
|
||||||
|
|
||||||
|
**Option B** — Laisser en place. La directive `mdns=error` ne cause aucun dommage si la
|
||||||
|
crate `mdns` n'est plus dans le build (elle sera simplement ignorée).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Résumé des diffs
|
||||||
|
|
||||||
|
| Fichier | Lignes supprimées | Lignes ajoutées |
|
||||||
|
|---|---|---|
|
||||||
|
| `Cargo.toml` | `mdns`, `async-std`, `futures-util` | `mdns-sd` |
|
||||||
|
| `control_point.rs` | ~50 (async block) | ~35 (sync recv loop) |
|
||||||
|
| `chromecast_discovery.rs` | ~80 (parsing manuel) | ~50 (lecture ServiceInfo) |
|
||||||
|
| `logs/mod.rs` | ~5 (filtre bruit) | 0 |
|
||||||
|
|
||||||
|
## Vérification
|
||||||
|
|
||||||
|
Après implémentation :
|
||||||
|
1. `cargo check -p pmocontrol` sans erreurs ni `use of undeclared crate mdns`
|
||||||
|
2. `cargo check -p pmoserver` sans erreurs
|
||||||
|
3. Tester la découverte d'un Chromecast en réseau local
|
||||||
|
4. Vérifier l'absence de `LabelIsNotAscii` dans les logs avec des appareils Apple présents
|
||||||
373
Cargo.lock
generated
373
Cargo.lock
generated
@@ -4,7 +4,7 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "PMOMusic"
|
name = "PMOMusic"
|
||||||
version = "0.3.41"
|
version = "0.3.42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum 0.8.7",
|
"axum 0.8.7",
|
||||||
"console-subscriber",
|
"console-subscriber",
|
||||||
@@ -49,7 +49,7 @@ version = "0.8.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"cipher",
|
"cipher",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
]
|
]
|
||||||
@@ -100,7 +100,7 @@ checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"alsa-sys",
|
"alsa-sys",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -176,27 +176,6 @@ dependencies = [
|
|||||||
"syn 2.0.110",
|
"syn 2.0.110",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-attributes"
|
|
||||||
version = "1.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-channel"
|
|
||||||
version = "1.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
|
||||||
dependencies = [
|
|
||||||
"concurrent-queue",
|
|
||||||
"event-listener 2.5.3",
|
|
||||||
"futures-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -234,21 +213,6 @@ dependencies = [
|
|||||||
"futures-lite",
|
"futures-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-global-executor"
|
|
||||||
version = "2.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel 2.5.0",
|
|
||||||
"async-executor",
|
|
||||||
"async-io",
|
|
||||||
"async-lock",
|
|
||||||
"blocking",
|
|
||||||
"futures-lite",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-io"
|
name = "async-io"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@@ -256,7 +220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
@@ -273,7 +237,7 @@ version = "3.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
|
checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener 5.4.1",
|
"event-listener",
|
||||||
"event-listener-strategy",
|
"event-listener-strategy",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
@@ -295,14 +259,14 @@ version = "2.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
|
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 2.5.0",
|
"async-channel",
|
||||||
"async-io",
|
"async-io",
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"async-signal",
|
"async-signal",
|
||||||
"async-task",
|
"async-task",
|
||||||
"blocking",
|
"blocking",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"event-listener 5.4.1",
|
"event-listener",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.2",
|
||||||
]
|
]
|
||||||
@@ -327,7 +291,7 @@ dependencies = [
|
|||||||
"async-io",
|
"async-io",
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.2",
|
||||||
@@ -336,66 +300,17 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-std"
|
|
||||||
version = "1.13.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b"
|
|
||||||
dependencies = [
|
|
||||||
"async-attributes",
|
|
||||||
"async-channel 1.9.0",
|
|
||||||
"async-global-executor",
|
|
||||||
"async-io",
|
|
||||||
"async-lock",
|
|
||||||
"async-process",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"futures-lite",
|
|
||||||
"gloo-timers",
|
|
||||||
"kv-log-macro",
|
|
||||||
"log",
|
|
||||||
"memchr",
|
|
||||||
"once_cell",
|
|
||||||
"pin-project-lite",
|
|
||||||
"pin-utils",
|
|
||||||
"slab",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "22068c0c19514942eefcfd4daf8976ef1aad84e61539f95cd200c35202f80af5"
|
|
||||||
dependencies = [
|
|
||||||
"async-stream-impl 0.2.1",
|
|
||||||
"futures-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream"
|
name = "async-stream"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream-impl 0.3.6",
|
"async-stream-impl",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream-impl"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream-impl"
|
name = "async-stream-impl"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@@ -682,7 +597,7 @@ dependencies = [
|
|||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"portable-atomic-util",
|
"portable-atomic-util",
|
||||||
"serde",
|
"serde",
|
||||||
"spin",
|
"spin 0.10.0",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
]
|
]
|
||||||
@@ -815,7 +730,7 @@ version = "1.6.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
|
checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 2.5.0",
|
"async-channel",
|
||||||
"async-task",
|
"async-task",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
@@ -930,12 +845,6 @@ dependencies = [
|
|||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@@ -1030,7 +939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
|
checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"castaway",
|
"castaway",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
@@ -1202,7 +1111,7 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1458,16 +1367,6 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd"
|
checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dns-parser"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"quick-error 1.2.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "document-features"
|
name = "document-features"
|
||||||
version = "0.2.12"
|
version = "0.2.12"
|
||||||
@@ -1522,7 +1421,7 @@ version = "0.8.35"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1562,20 +1461,6 @@ dependencies = [
|
|||||||
"typeid",
|
"typeid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "err-derive"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"rustversion",
|
|
||||||
"syn 1.0.109",
|
|
||||||
"synstructure 0.12.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.14"
|
version = "0.3.14"
|
||||||
@@ -1586,12 +1471,6 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "event-listener"
|
|
||||||
version = "2.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "5.4.1"
|
version = "5.4.1"
|
||||||
@@ -1609,7 +1488,7 @@ version = "0.5.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener 5.4.1",
|
"event-listener",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1734,6 +1613,17 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flume"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"spin 0.9.8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -1966,7 +1856,7 @@ version = "0.2.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
@@ -1977,7 +1867,7 @@ version = "0.3.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi",
|
"r-efi",
|
||||||
"wasip2",
|
"wasip2",
|
||||||
@@ -2018,18 +1908,6 @@ version = "0.3.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gloo-timers"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
@@ -2055,7 +1933,7 @@ version = "2.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"crunchy",
|
"crunchy",
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
@@ -2452,6 +2330,16 @@ dependencies = [
|
|||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "if-addrs"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0a05c691e1fae256cf7013d99dad472dc52d5543322761f83ec8d47eab40d2b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.8"
|
version = "0.25.8"
|
||||||
@@ -2483,7 +2371,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
"quick-error 2.0.1",
|
"quick-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2599,7 +2487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cesu8",
|
"cesu8",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"combine",
|
"combine",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
@@ -2634,15 +2522,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kv-log-macro"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -2698,7 +2577,7 @@ version = "0.8.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2815,9 +2694,6 @@ name = "log"
|
|||||||
version = "0.4.28"
|
version = "0.4.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||||
dependencies = [
|
|
||||||
"value-bag",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loop9"
|
name = "loop9"
|
||||||
@@ -2904,7 +2780,7 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
|
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2914,24 +2790,23 @@ version = "0.10.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mdns"
|
name = "mdns-sd"
|
||||||
version = "3.0.0"
|
version = "0.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c769962ac75a6ea437f0922b27834bcccd4c013d591383a16ae5731e3ef0f3f3"
|
checksum = "451927183d65d600e52b4e877a1251e051576f84fa01e5b4a50b450dfaaa537c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"fastrand",
|
||||||
"async-stream 0.2.1",
|
"flume",
|
||||||
"dns-parser",
|
"if-addrs",
|
||||||
"err-derive",
|
|
||||||
"futures-core",
|
|
||||||
"futures-util",
|
|
||||||
"log",
|
"log",
|
||||||
"net2",
|
"mio 1.1.0",
|
||||||
|
"socket-pktinfo",
|
||||||
|
"socket2 0.6.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3011,6 +2886,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
|
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
@@ -3050,7 +2926,7 @@ dependencies = [
|
|||||||
"crossbeam-epoch",
|
"crossbeam-epoch",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"event-listener 5.4.1",
|
"event-listener",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
@@ -3116,17 +2992,6 @@ dependencies = [
|
|||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "net2"
|
|
||||||
version = "0.2.39"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 0.1.10",
|
|
||||||
"libc",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "netlink-packet-core"
|
name = "netlink-packet-core"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@@ -3207,7 +3072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -3573,7 +3438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
|
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -3664,7 +3529,7 @@ version = "0.9.12"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@@ -3927,15 +3792,13 @@ name = "pmocontrol"
|
|||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-std",
|
"async-stream",
|
||||||
"async-stream 0.3.6",
|
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum 0.8.7",
|
"axum 0.8.7",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"futures-util",
|
"mdns-sd",
|
||||||
"mdns",
|
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pmocovers",
|
"pmocovers",
|
||||||
"pmodidl",
|
"pmodidl",
|
||||||
@@ -4095,7 +3958,7 @@ name = "pmoparadise"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream 0.3.6",
|
"async-stream",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum 0.8.7",
|
"axum 0.8.7",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -4140,7 +4003,7 @@ name = "pmoplaylist"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream 0.3.6",
|
"async-stream",
|
||||||
"axum 0.8.7",
|
"axum 0.8.7",
|
||||||
"chrono",
|
"chrono",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -4234,7 +4097,7 @@ name = "pmoserver"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream 0.3.6",
|
"async-stream",
|
||||||
"axum 0.8.7",
|
"axum 0.8.7",
|
||||||
"axum-server",
|
"axum-server",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -4376,7 +4239,7 @@ version = "3.11.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
|
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -4390,7 +4253,7 @@ version = "0.6.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
"universal-hash",
|
"universal-hash",
|
||||||
@@ -4460,30 +4323,6 @@ dependencies = [
|
|||||||
"toml_edit 0.23.7",
|
"toml_edit 0.23.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.103"
|
version = "1.0.103"
|
||||||
@@ -4629,12 +4468,6 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-error"
|
|
||||||
version = "1.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@@ -4757,7 +4590,7 @@ dependencies = [
|
|||||||
"av1-grain",
|
"av1-grain",
|
||||||
"bitstream-io",
|
"bitstream-io",
|
||||||
"built",
|
"built",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"interpolate_name",
|
"interpolate_name",
|
||||||
"itertools 0.12.1",
|
"itertools 0.12.1",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -4789,7 +4622,7 @@ dependencies = [
|
|||||||
"avif-serialize",
|
"avif-serialize",
|
||||||
"imgref",
|
"imgref",
|
||||||
"loop9",
|
"loop9",
|
||||||
"quick-error 2.0.1",
|
"quick-error",
|
||||||
"rav1e",
|
"rav1e",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rgb",
|
"rgb",
|
||||||
@@ -4923,7 +4756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"getrandom 0.2.16",
|
"getrandom 0.2.16",
|
||||||
"libc",
|
"libc",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
@@ -5303,7 +5136,7 @@ version = "0.10.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
@@ -5314,7 +5147,7 @@ version = "0.10.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
@@ -5420,7 +5253,7 @@ version = "2.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f"
|
checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 2.5.0",
|
"async-channel",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
"async-fs",
|
"async-fs",
|
||||||
"async-io",
|
"async-io",
|
||||||
@@ -5440,6 +5273,17 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket-pktinfo"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "927136cc2ae6a1b0e66ac6b1210902b75c3f726db004a73bc18686dcd0dcd22f"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"socket2 0.6.1",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.10"
|
version = "0.5.10"
|
||||||
@@ -5471,6 +5315,15 @@ dependencies = [
|
|||||||
"libsoxr-sys",
|
"libsoxr-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@@ -5781,18 +5634,6 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "synstructure"
|
|
||||||
version = "0.12.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synstructure"
|
name = "synstructure"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
@@ -5810,7 +5651,7 @@ version = "0.30.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3"
|
checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"ntapi",
|
"ntapi",
|
||||||
@@ -5935,7 +5776,7 @@ version = "1.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5947,7 +5788,7 @@ dependencies = [
|
|||||||
"fax",
|
"fax",
|
||||||
"flate2",
|
"flate2",
|
||||||
"half",
|
"half",
|
||||||
"quick-error 2.0.1",
|
"quick-error",
|
||||||
"weezl",
|
"weezl",
|
||||||
"zune-jpeg",
|
"zune-jpeg",
|
||||||
]
|
]
|
||||||
@@ -6075,7 +5916,7 @@ version = "0.4.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
|
checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream 0.3.6",
|
"async-stream",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -6177,7 +6018,7 @@ version = "0.12.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
|
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream 0.3.6",
|
"async-stream",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum 0.7.9",
|
"axum 0.7.9",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -6426,12 +6267,6 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "universal-hash"
|
name = "universal-hash"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -6617,12 +6452,6 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "value-bag"
|
|
||||||
version = "1.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "variadics_please"
|
name = "variadics_please"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -6692,7 +6521,7 @@ version = "0.2.105"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
|
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
@@ -6705,7 +6534,7 @@ version = "0.4.55"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
|
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.4",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -7368,7 +7197,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.110",
|
"syn 2.0.110",
|
||||||
"synstructure 0.13.2",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7409,7 +7238,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.110",
|
"syn 2.0.110",
|
||||||
"synstructure 0.13.2",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "PMOMusic"
|
name = "PMOMusic"
|
||||||
version = "0.3.41"
|
version = "0.3.42"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -203,6 +203,14 @@ impl DB {
|
|||||||
[],
|
[],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Index sur metadata(key, value) pour rendre get_pk_by_origin_url efficace.
|
||||||
|
// Sans cet index, la requête WHERE key = 'origin_url' AND value = ? fait
|
||||||
|
// un full scan car la PRIMARY KEY est (pk, key).
|
||||||
|
conn.execute(
|
||||||
|
"CREATE INDEX IF NOT EXISTS idx_metadata_key_value ON metadata (key, value)",
|
||||||
|
[],
|
||||||
|
)?;
|
||||||
|
|
||||||
// LAZY PK SUPPORT: Index sur lazy_pk pour lookups rapides (lazy_pk → real pk)
|
// LAZY PK SUPPORT: Index sur lazy_pk pour lookups rapides (lazy_pk → real pk)
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"CREATE INDEX IF NOT EXISTS idx_asset_lazy_pk ON asset (lazy_pk)",
|
"CREATE INDEX IF NOT EXISTS idx_asset_lazy_pk ON asset (lazy_pk)",
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ ratatui = { version = "0.26", default-features = false, features = ["crossterm"]
|
|||||||
crossterm = "0.27"
|
crossterm = "0.27"
|
||||||
rust_cast = "0.19"
|
rust_cast = "0.19"
|
||||||
rustls = { version = "0.23", features = ["aws-lc-rs"] }
|
rustls = { version = "0.23", features = ["aws-lc-rs"] }
|
||||||
mdns = "3.0"
|
mdns-sd = "0.19"
|
||||||
async-std = "1.12"
|
|
||||||
futures-util = "0.3"
|
|
||||||
smol = "2.0"
|
smol = "2.0"
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use tracing::{debug, error, info, warn};
|
|||||||
use crate::discovery::manager::UDNRegistry;
|
use crate::discovery::manager::UDNRegistry;
|
||||||
use crate::errors::ControlPointError;
|
use crate::errors::ControlPointError;
|
||||||
use crate::events::{MediaServerEventBus, RendererEventBus};
|
use crate::events::{MediaServerEventBus, RendererEventBus};
|
||||||
use crate::media_server::{MediaBrowser, MusicServer, playback_item_from_entry};
|
use crate::media_server::{playback_item_from_entry, MediaBrowser, MusicServer};
|
||||||
use crate::media_server_events::spawn_media_server_event_runtime;
|
use crate::media_server_events::spawn_media_server_event_runtime;
|
||||||
use crate::model::{MediaServerEvent, RendererEvent};
|
use crate::model::{MediaServerEvent, RendererEvent};
|
||||||
use crate::model::{PlaybackState, TrackMetadata};
|
use crate::model::{PlaybackState, TrackMetadata};
|
||||||
@@ -147,51 +147,52 @@ impl ControlPoint {
|
|||||||
let udn_cache_for_mdns = Arc::clone(&udn_cache);
|
let udn_cache_for_mdns = Arc::clone(&udn_cache);
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
use crate::discovery::ChromecastDiscoveryManager;
|
use crate::discovery::ChromecastDiscoveryManager;
|
||||||
use futures_util::StreamExt;
|
use mdns_sd::{ServiceDaemon, ServiceEvent};
|
||||||
|
|
||||||
// Créer le gestionnaire de découverte UPNP
|
|
||||||
let mut discovery_manager =
|
let mut discovery_manager =
|
||||||
ChromecastDiscoveryManager::new(registry_for_mdns, udn_cache_for_mdns);
|
ChromecastDiscoveryManager::new(registry_for_mdns, udn_cache_for_mdns);
|
||||||
|
|
||||||
debug!("Starting mDNS discovery thread for Chromecast devices");
|
debug!("Starting mDNS discovery thread for Chromecast devices");
|
||||||
|
|
||||||
const SERVICE_NAME: &str = "_googlecast._tcp.local";
|
const SERVICE_TYPE: &str = "_googlecast._tcp.local.";
|
||||||
|
|
||||||
// Run async discovery in a blocking task
|
let daemon = match ServiceDaemon::new() {
|
||||||
async_std::task::block_on(async {
|
Ok(d) => d,
|
||||||
// Create mDNS discovery stream with 15 second query interval
|
Err(e) => {
|
||||||
// (shorter interval for faster initial discovery)
|
error!("Failed to create mDNS daemon: {}", e);
|
||||||
match mdns::discover::all(SERVICE_NAME, Duration::from_secs(15)) {
|
return;
|
||||||
Ok(discovery) => {
|
|
||||||
let stream = discovery.listen();
|
|
||||||
futures_util::pin_mut!(stream);
|
|
||||||
|
|
||||||
debug!("mDNS discovery stream started for Chromecast devices");
|
|
||||||
|
|
||||||
// Listen to mDNS responses
|
|
||||||
while let Some(result) = stream.next().await {
|
|
||||||
match result {
|
|
||||||
Ok(response) => {
|
|
||||||
debug!(
|
|
||||||
"Received mDNS response with {} records",
|
|
||||||
response.records().count()
|
|
||||||
);
|
|
||||||
|
|
||||||
discovery_manager.handle_mdns_response(response);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("mDNS discovery error: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
warn!("mDNS discovery stream ended unexpectedly");
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to start mDNS discovery: {}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
let receiver = match daemon.browse(SERVICE_TYPE) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to start mDNS browse for {}: {}", SERVICE_TYPE, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("mDNS discovery started for Chromecast devices");
|
||||||
|
|
||||||
|
while let Ok(event) = receiver.recv() {
|
||||||
|
match event {
|
||||||
|
ServiceEvent::ServiceResolved(info) => {
|
||||||
|
debug!(
|
||||||
|
fullname = info.get_fullname(),
|
||||||
|
host = info.get_hostname(),
|
||||||
|
port = info.get_port(),
|
||||||
|
"mDNS Chromecast service resolved"
|
||||||
|
);
|
||||||
|
discovery_manager.handle_service_resolved(&info);
|
||||||
|
}
|
||||||
|
ServiceEvent::ServiceRemoved(_service_type, fullname) => {
|
||||||
|
debug!(fullname = %fullname, "mDNS Chromecast service removed");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!("mDNS discovery receiver closed");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note: Renderer polling is now handled by each MusicRenderer's own watcher thread.
|
// Note: Renderer polling is now handled by each MusicRenderer's own watcher thread.
|
||||||
@@ -1169,24 +1170,21 @@ impl ControlPoint {
|
|||||||
binding.auto_play_on_refresh = auto_play;
|
binding.auto_play_on_refresh = auto_play;
|
||||||
renderer.set_playlist_binding(Some(binding));
|
renderer.set_playlist_binding(Some(binding));
|
||||||
|
|
||||||
let callback: Option<Box<dyn FnOnce(&DeviceId) -> Result<(), ControlPointError> + Send + 'static>> =
|
let callback: Option<
|
||||||
if auto_play {
|
Box<dyn FnOnce(&DeviceId) -> Result<(), ControlPointError> + Send + 'static>,
|
||||||
let reg = Arc::clone(&self.registry);
|
> = if auto_play {
|
||||||
Some(Box::new(move |rid: &DeviceId| {
|
let reg = Arc::clone(&self.registry);
|
||||||
let renderer = reg.read().unwrap().get_renderer(rid).ok_or_else(||
|
Some(Box::new(move |rid: &DeviceId| {
|
||||||
ControlPointError::ControlPoint(format!("Renderer {} not found", rid.0))
|
let renderer = reg.read().unwrap().get_renderer(rid).ok_or_else(|| {
|
||||||
)?;
|
ControlPointError::ControlPoint(format!("Renderer {} not found", rid.0))
|
||||||
renderer.play_current_from_queue()
|
})?;
|
||||||
}))
|
renderer.play_current_from_queue()
|
||||||
} else {
|
}))
|
||||||
None
|
} else {
|
||||||
};
|
None
|
||||||
let _ = schedule_queue_refresh_for(
|
};
|
||||||
&self.registry,
|
let _ =
|
||||||
renderer_id,
|
schedule_queue_refresh_for(&self.registry, renderer_id, &self.event_bus, callback);
|
||||||
&self.event_bus,
|
|
||||||
callback,
|
|
||||||
);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1240,22 +1238,23 @@ impl ControlPoint {
|
|||||||
// Note: BindingChanged event is emitted automatically by MusicRenderer::set_playlist_binding()
|
// Note: BindingChanged event is emitted automatically by MusicRenderer::set_playlist_binding()
|
||||||
|
|
||||||
// For initial attach with auto_play, force playback start (don't check if idle)
|
// For initial attach with auto_play, force playback start (don't check if idle)
|
||||||
let callback: Option<Box<dyn FnOnce(&DeviceId) -> Result<(), ControlPointError> + Send + 'static>> =
|
let callback: Option<
|
||||||
if auto_play {
|
Box<dyn FnOnce(&DeviceId) -> Result<(), ControlPointError> + Send + 'static>,
|
||||||
let reg = Arc::clone(&self.registry);
|
> = if auto_play {
|
||||||
Some(Box::new(move |rid: &DeviceId| {
|
let reg = Arc::clone(&self.registry);
|
||||||
debug!(
|
Some(Box::new(move |rid: &DeviceId| {
|
||||||
renderer = rid.0.as_str(),
|
debug!(
|
||||||
"Attach callback: forcing playback start (not checking if idle)"
|
renderer = rid.0.as_str(),
|
||||||
);
|
"Attach callback: forcing playback start (not checking if idle)"
|
||||||
let renderer = reg.read().unwrap().get_renderer(rid).ok_or_else(||
|
);
|
||||||
ControlPointError::ControlPoint(format!("Renderer {} not found", rid.0))
|
let renderer = reg.read().unwrap().get_renderer(rid).ok_or_else(|| {
|
||||||
)?;
|
ControlPointError::ControlPoint(format!("Renderer {} not found", rid.0))
|
||||||
renderer.play_current_from_queue()
|
})?;
|
||||||
}))
|
renderer.play_current_from_queue()
|
||||||
} else {
|
}))
|
||||||
None
|
} else {
|
||||||
};
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let _ = schedule_queue_refresh_for(&self.registry, renderer_id, &self.event_bus, callback);
|
let _ = schedule_queue_refresh_for(&self.registry, renderer_id, &self.event_bus, callback);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1806,7 +1805,9 @@ fn schedule_queue_refresh_for(
|
|||||||
registry: &Arc<RwLock<DeviceRegistry>>,
|
registry: &Arc<RwLock<DeviceRegistry>>,
|
||||||
renderer_id: &DeviceId,
|
renderer_id: &DeviceId,
|
||||||
event_bus: &RendererEventBus,
|
event_bus: &RendererEventBus,
|
||||||
after_refresh: Option<Box<dyn FnOnce(&DeviceId) -> Result<(), ControlPointError> + Send + 'static>>,
|
after_refresh: Option<
|
||||||
|
Box<dyn FnOnce(&DeviceId) -> Result<(), ControlPointError> + Send + 'static>,
|
||||||
|
>,
|
||||||
) -> SyncScheduleOutcome {
|
) -> SyncScheduleOutcome {
|
||||||
// Step 1: Get renderer from registry
|
// Step 1: Get renderer from registry
|
||||||
let renderer = {
|
let renderer = {
|
||||||
@@ -1895,7 +1896,9 @@ fn schedule_queue_refresh_for(
|
|||||||
};
|
};
|
||||||
match music_server {
|
match music_server {
|
||||||
Some(s) => fetch_queue_items_for(&s, &container_id_clone),
|
Some(s) => fetch_queue_items_for(&s, &container_id_clone),
|
||||||
None => Err(ControlPointError::MediaServerError("Server not found".to_string())),
|
None => Err(ControlPointError::MediaServerError(
|
||||||
|
"Server not found".to_string(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,15 @@
|
|||||||
//! This module handles the discovery of Chromecast devices and registers them
|
//! This module handles the discovery of Chromecast devices and registers them
|
||||||
//! directly into the `DeviceRegistry`.
|
//! directly into the `DeviceRegistry`.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::net::IpAddr;
|
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
use crate::DeviceId;
|
use mdns_sd::ResolvedService;
|
||||||
use crate::DeviceRegistry;
|
use mdns_sd::ServiceInfo;
|
||||||
|
|
||||||
use crate::discovery::manager::UDNRegistry;
|
use crate::discovery::manager::UDNRegistry;
|
||||||
use crate::model::{RendererCapabilities, RendererInfo, RendererProtocol};
|
use crate::model::{RendererCapabilities, RendererInfo, RendererProtocol};
|
||||||
|
use crate::DeviceId;
|
||||||
|
use crate::DeviceRegistry;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
/// Gestionnaire des événements mDNS pour Chromecast.
|
/// Gestionnaire des événements mDNS pour Chromecast.
|
||||||
@@ -32,146 +33,80 @@ impl ChromecastDiscoveryManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Traite une réponse mDNS pour un appareil Chromecast.
|
/// Traite un service Chromecast résolu par mDNS-SD.
|
||||||
///
|
///
|
||||||
/// Cette fonction parse les réponses de service discovery mDNS pour les appareils
|
/// `ServiceInfo` arrive pré-assemblé : plus besoin de jointure manuelle
|
||||||
/// Chromecast et les enregistre directement dans le registre.
|
/// des enregistrements PTR / A / SRV / TXT.
|
||||||
pub fn handle_mdns_response(&mut self, response: mdns::Response) {
|
pub fn handle_service_resolved(&mut self, info: &ResolvedService) {
|
||||||
// Extract basic information from the mDNS response
|
let fullname = info.get_fullname().to_string();
|
||||||
let service_name = match response.records().find_map(|r| {
|
|
||||||
if let mdns::RecordKind::PTR(ref name) = r.kind {
|
|
||||||
Some(name.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Some(name) => name,
|
|
||||||
None => {
|
|
||||||
warn!("No PTR record found in mDNS response");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("Processing mDNS response for service: {}", service_name);
|
debug!("Processing resolved Chromecast service: {}", fullname);
|
||||||
|
|
||||||
// Extract IP addresses
|
let host = match info
|
||||||
let addresses: Vec<IpAddr> = response
|
.get_addresses()
|
||||||
.records()
|
|
||||||
.filter_map(|r| match r.kind {
|
|
||||||
mdns::RecordKind::A(addr) => Some(IpAddr::V4(addr)),
|
|
||||||
mdns::RecordKind::AAAA(addr) => Some(IpAddr::V6(addr)),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if addresses.is_empty() {
|
|
||||||
warn!(
|
|
||||||
"No IP address found for Chromecast device: {}",
|
|
||||||
service_name
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefer IPv4 addresses
|
|
||||||
let host = match addresses
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|addr| matches!(addr, IpAddr::V4(_)))
|
.find(|a| a.is_ipv4())
|
||||||
.or_else(|| addresses.first())
|
.or_else(|| info.get_addresses().iter().next())
|
||||||
{
|
{
|
||||||
Some(addr) => addr.to_string(),
|
Some(addr) => addr.to_string(),
|
||||||
None => {
|
None => {
|
||||||
warn!("Could not extract host from addresses");
|
warn!("No IP address for Chromecast service: {}", fullname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract port from SRV record
|
let port = info.get_port();
|
||||||
let port = response
|
|
||||||
.records()
|
|
||||||
.find_map(|r| {
|
|
||||||
if let mdns::RecordKind::SRV { port, .. } = r.kind {
|
|
||||||
Some(port)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(8009); // Default Chromecast port
|
|
||||||
|
|
||||||
// Extract TXT records for additional metadata
|
let uuid = info
|
||||||
let txt_records: HashMap<String, String> = response
|
.get_property_val_str("id")
|
||||||
.records()
|
.unwrap_or_default()
|
||||||
.filter_map(|r| {
|
.to_string();
|
||||||
if let mdns::RecordKind::TXT(ref data) = r.kind {
|
let uuid = if uuid.is_empty() {
|
||||||
Some(data.clone())
|
format!("chromecast-{}-{}", host, port)
|
||||||
} else {
|
} else {
|
||||||
None
|
uuid
|
||||||
}
|
};
|
||||||
})
|
|
||||||
.flat_map(|data| {
|
|
||||||
// data is Vec<String>, each string is "key=value"
|
|
||||||
data.into_iter().filter_map(|s| {
|
|
||||||
let parts: Vec<&str> = s.splitn(2, '=').collect();
|
|
||||||
if parts.len() == 2 {
|
|
||||||
Some((parts[0].to_string(), parts[1].to_string()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Extract metadata from TXT records
|
let model = info.get_property_val_str("md").map(|s| s.to_string());
|
||||||
let model = txt_records.get("md").cloned();
|
|
||||||
let uuid = txt_records
|
|
||||||
.get("id")
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_else(|| format!("chromecast-{}-{}", host, port));
|
|
||||||
let manufacturer = Some("Google Inc.".to_string());
|
|
||||||
|
|
||||||
// Extract friendly name from TXT record "fn" if available
|
let friendly_name = info
|
||||||
// Otherwise, extract from service instance name (PTR record)
|
.get_property_val_str("fn")
|
||||||
let friendly_name = txt_records.get("fn").cloned().unwrap_or_else(|| {
|
.map(|s| s.to_string())
|
||||||
// Fallback: extract from service name, removing the UUID suffix if present
|
.unwrap_or_else(|| {
|
||||||
service_name
|
fullname
|
||||||
.split("._googlecast._tcp.local")
|
.split("._googlecast._tcp.local")
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or("Unknown Chromecast")
|
.unwrap_or("Unknown Chromecast")
|
||||||
.split('-')
|
.split('-')
|
||||||
.take_while(|part| part.len() != 32) // Skip 32-char hex UUID
|
.take_while(|part| part.len() != 32)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("-")
|
.join("-")
|
||||||
.trim()
|
.trim()
|
||||||
.to_string()
|
.to_string()
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Discovered Chromecast: {} at {}:{} (UUID: {}, Model: {:?})",
|
"Discovered Chromecast: {} at {}:{} (UUID: {}, Model: {:?})",
|
||||||
friendly_name, host, port, uuid, model
|
friendly_name, host, port, uuid, model
|
||||||
);
|
);
|
||||||
|
|
||||||
// Build UDN and check cache
|
|
||||||
let udn = format!("uuid:{}", uuid);
|
let udn = format!("uuid:{}", uuid);
|
||||||
|
let default_max_age = 1800u64;
|
||||||
|
|
||||||
// Pour Chromecast, on utilise un max_age par défaut car mDNS n'a pas ce concept
|
|
||||||
let default_max_age = 1800u64; // 30 minutes
|
|
||||||
|
|
||||||
// Check cache to avoid redundant updates
|
|
||||||
if !UDNRegistry::should_fetch(self.udn_cache.clone(), &udn, default_max_age) {
|
if !UDNRegistry::should_fetch(self.udn_cache.clone(), &udn, default_max_age) {
|
||||||
debug!("Chromecast {} recently seen, skipping", udn);
|
debug!("Chromecast {} recently seen, skipping", udn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create RendererInfo for the registry
|
|
||||||
let renderer_info = build_renderer_info(
|
let renderer_info = build_renderer_info(
|
||||||
&uuid,
|
&uuid,
|
||||||
&friendly_name,
|
&friendly_name,
|
||||||
&host,
|
&host,
|
||||||
port,
|
port,
|
||||||
model.as_deref(),
|
model.as_deref(),
|
||||||
manufacturer.as_deref(),
|
Some("Google Inc."),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register the renderer
|
|
||||||
self.device_registry
|
self.device_registry
|
||||||
.write()
|
.write()
|
||||||
.expect("DeviceRegistry mutex lock failed")
|
.expect("DeviceRegistry mutex lock failed")
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ unsafe fn setup_metadata(
|
|||||||
use libflac_sys::*;
|
use libflac_sys::*;
|
||||||
|
|
||||||
// Create a Vorbis Comment block
|
// Create a Vorbis Comment block
|
||||||
let meta = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
let meta = unsafe { FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT) };
|
||||||
if meta.is_null() {
|
if meta.is_null() {
|
||||||
return Err(FlacError::LibFlacInit(
|
return Err(FlacError::LibFlacInit(
|
||||||
"Failed to create metadata block".into(),
|
"Failed to create metadata block".into(),
|
||||||
@@ -420,12 +420,14 @@ unsafe fn setup_metadata(
|
|||||||
FlacError::LibFlacInit("Failed to create CString for field value".into())
|
FlacError::LibFlacInit("Failed to create CString for field value".into())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut entry: FLAC__StreamMetadata_VorbisComment_Entry = std::mem::zeroed();
|
let mut entry: FLAC__StreamMetadata_VorbisComment_Entry = unsafe { std::mem::zeroed() };
|
||||||
let success = FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(
|
let success = unsafe {
|
||||||
&mut entry as *mut _,
|
FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(
|
||||||
c_field_name.as_ptr(),
|
&mut entry as *mut _,
|
||||||
c_value.as_ptr(),
|
c_field_name.as_ptr(),
|
||||||
);
|
c_value.as_ptr(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
if success == 0 {
|
if success == 0 {
|
||||||
return Err(FlacError::LibFlacInit(format!(
|
return Err(FlacError::LibFlacInit(format!(
|
||||||
@@ -435,7 +437,7 @@ unsafe fn setup_metadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let append_success =
|
let append_success =
|
||||||
FLAC__metadata_object_vorbiscomment_append_comment(meta, entry, 0 /* copy */);
|
unsafe { FLAC__metadata_object_vorbiscomment_append_comment(meta, entry, 0 /* copy */) };
|
||||||
|
|
||||||
if append_success == 0 {
|
if append_success == 0 {
|
||||||
return Err(FlacError::LibFlacInit(format!(
|
return Err(FlacError::LibFlacInit(format!(
|
||||||
@@ -476,7 +478,7 @@ unsafe fn setup_metadata(
|
|||||||
|
|
||||||
// Set the metadata on the encoder
|
// Set the metadata on the encoder
|
||||||
let mut metadata_array = [meta];
|
let mut metadata_array = [meta];
|
||||||
let set_success = FLAC__stream_encoder_set_metadata(encoder, metadata_array.as_mut_ptr(), 1);
|
let set_success = unsafe { FLAC__stream_encoder_set_metadata(encoder, metadata_array.as_mut_ptr(), 1) };
|
||||||
|
|
||||||
if set_success == 0 {
|
if set_success == 0 {
|
||||||
return Err(FlacError::LibFlacInit(
|
return Err(FlacError::LibFlacInit(
|
||||||
@@ -666,8 +668,8 @@ unsafe extern "C" fn write_callback(
|
|||||||
_current_frame: u32,
|
_current_frame: u32,
|
||||||
client_data: *mut c_void,
|
client_data: *mut c_void,
|
||||||
) -> libflac_sys::FLAC__StreamEncoderWriteStatus {
|
) -> libflac_sys::FLAC__StreamEncoderWriteStatus {
|
||||||
let state = &mut *(client_data as *mut EncoderClientState);
|
let state = unsafe { &mut *(client_data as *mut EncoderClientState) };
|
||||||
let slice = std::slice::from_raw_parts(buffer, bytes);
|
let slice = unsafe { std::slice::from_raw_parts(buffer, bytes) };
|
||||||
match state.tx.blocking_send(Ok(slice.to_vec())) {
|
match state.tx.blocking_send(Ok(slice.to_vec())) {
|
||||||
Ok(_) => libflac_sys::FLAC__STREAM_ENCODER_WRITE_STATUS_OK,
|
Ok(_) => libflac_sys::FLAC__STREAM_ENCODER_WRITE_STATUS_OK,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ pub mod paradise_streaming;
|
|||||||
pub use content_handler::ContentHandler;
|
pub use content_handler::ContentHandler;
|
||||||
pub use device::MEDIA_SERVER;
|
pub use device::MEDIA_SERVER;
|
||||||
pub use device_ext::MediaServerDeviceExt;
|
pub use device_ext::MediaServerDeviceExt;
|
||||||
pub use server_ext::{MediaServerExt, MusicSourceExt, get_source_registry};
|
pub use server_ext::{MediaServerExt, MusicSourceExt};
|
||||||
pub use source_registry::SourceRegistry;
|
pub use source_registry::SourceRegistry;
|
||||||
pub use sources::{SourceInitError, SourcesExt};
|
pub use sources::{SourceInitError, SourcesExt};
|
||||||
|
|
||||||
|
|||||||
@@ -14,23 +14,6 @@ use std::sync::Arc;
|
|||||||
// Réexporter le trait de base de pmosource
|
// Réexporter le trait de base de pmosource
|
||||||
pub use pmosource::MusicSourceExt;
|
pub use pmosource::MusicSourceExt;
|
||||||
|
|
||||||
/// Récupère le registre global de sources (délègue à pmosource)
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// use pmomediaserver::server_ext::get_source_registry;
|
|
||||||
///
|
|
||||||
/// let sources = pmosource::api::list_all_sources().await;
|
|
||||||
/// ```
|
|
||||||
#[deprecated(
|
|
||||||
since = "0.2.0",
|
|
||||||
note = "Use pmosource::api::list_all_sources() directly"
|
|
||||||
)]
|
|
||||||
pub async fn get_source_registry() -> Vec<Arc<dyn MusicSource>> {
|
|
||||||
pmosource::api::list_all_sources().await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait d'extension pour le serveur MediaServer UPnP
|
/// Trait d'extension pour le serveur MediaServer UPnP
|
||||||
///
|
///
|
||||||
/// Ce trait ajoute des méthodes spécifiques au MediaServer UPnP.
|
/// Ce trait ajoute des méthodes spécifiques au MediaServer UPnP.
|
||||||
|
|||||||
@@ -273,13 +273,13 @@ pub fn init_logging() -> LogState {
|
|||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
let trimmed = value.trim();
|
let trimmed = value.trim();
|
||||||
if let Some(level) = string_to_level(trimmed) {
|
if let Some(level) = string_to_level(trimmed) {
|
||||||
let filter =
|
let filter = build_filter_with_noise_suppressions(trimmed);
|
||||||
EnvFilter::try_new(trimmed).unwrap_or_else(|_| EnvFilter::new("trace"));
|
|
||||||
(filter, level, format!("RUST_LOG ({})", trimmed))
|
(filter, level, format!("RUST_LOG ({})", trimmed))
|
||||||
} else {
|
} else {
|
||||||
|
let filter = build_filter_with_noise_suppressions(trimmed);
|
||||||
match EnvFilter::try_new(trimmed) {
|
match EnvFilter::try_new(trimmed) {
|
||||||
Ok(filter) => {
|
Ok(raw) => {
|
||||||
let level_hint = filter
|
let level_hint = raw
|
||||||
.max_level_hint()
|
.max_level_hint()
|
||||||
.and_then(levelfilter_to_level)
|
.and_then(levelfilter_to_level)
|
||||||
.unwrap_or(Level::TRACE);
|
.unwrap_or(Level::TRACE);
|
||||||
@@ -295,7 +295,7 @@ pub fn init_logging() -> LogState {
|
|||||||
.ok()
|
.ok()
|
||||||
.and_then(|cfg| string_to_level(cfg.trim()))
|
.and_then(|cfg| string_to_level(cfg.trim()))
|
||||||
.unwrap_or(Level::TRACE);
|
.unwrap_or(Level::TRACE);
|
||||||
let filter = EnvFilter::new(level_to_string(cfg_level));
|
let filter = build_filter_with_noise_suppressions(&level_to_string(cfg_level));
|
||||||
(filter, cfg_level, "config".to_string())
|
(filter, cfg_level, "config".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,7 +307,7 @@ pub fn init_logging() -> LogState {
|
|||||||
.ok()
|
.ok()
|
||||||
.and_then(|cfg| string_to_level(cfg.trim()))
|
.and_then(|cfg| string_to_level(cfg.trim()))
|
||||||
.unwrap_or(Level::TRACE);
|
.unwrap_or(Level::TRACE);
|
||||||
let filter = EnvFilter::new(level_to_string(cfg_level));
|
let filter = build_filter_with_noise_suppressions(&level_to_string(cfg_level));
|
||||||
(filter, cfg_level, "config".to_string())
|
(filter, cfg_level, "config".to_string())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -446,6 +446,27 @@ pub async fn log_setup_post(
|
|||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construit un `EnvFilter` en ajoutant les suppressions de bruit connues
|
||||||
|
/// si la directive correspondante n'est pas déjà présente dans `base`.
|
||||||
|
fn build_filter_with_noise_suppressions(base: &str) -> EnvFilter {
|
||||||
|
const NOISE_FILTERS: &[(&str, &str)] = &[];
|
||||||
|
|
||||||
|
let mut directives = base.to_string();
|
||||||
|
for (prefix, directive) in NOISE_FILTERS {
|
||||||
|
// N'ajouter que si l'utilisateur n'a pas déjà configuré cette cible
|
||||||
|
let already_set = base.split(',').any(|part| {
|
||||||
|
let part = part.trim();
|
||||||
|
part == *prefix || part.starts_with(&format!("{}=", prefix))
|
||||||
|
});
|
||||||
|
if !already_set {
|
||||||
|
directives.push(',');
|
||||||
|
directives.push_str(directive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EnvFilter::try_new(&directives).unwrap_or_else(|_| EnvFilter::new(base))
|
||||||
|
}
|
||||||
|
|
||||||
fn string_to_level(s: &str) -> Option<Level> {
|
fn string_to_level(s: &str) -> Option<Level> {
|
||||||
match s.to_uppercase().as_str() {
|
match s.to_uppercase().as_str() {
|
||||||
"ERROR" => Some(Level::ERROR),
|
"ERROR" => Some(Level::ERROR),
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.3.41
|
0.3.42
|
||||||
|
|||||||
Reference in New Issue
Block a user