1use anyhow::{Context, Result};
2use std::sync::Arc;
3use tokio::sync::Semaphore;
4
5use crate::config::Config;
6
7pub fn alias_or_thing_to_uri(thing: &str, config: &Config) -> Result<String> {
8 if let Some(alias_target) = config.aliases.get(thing) {
10 if let Some(uri) = config.things.get(alias_target) {
12 return Ok(uri.clone());
13 }
14 }
15
16 if let Some(uri) = config.things.get(thing) {
18 return Ok(uri.clone());
19 }
20
21 anyhow::bail!("'{}' not found in [things] or [aliases]", thing)
22}
23
24fn open_it(thing: &str) -> Result<()> {
25 open::that(thing).with_context(|| format!("failed to open {}", thing))?;
26 println!("opening {}...", thing);
27 Ok(())
28}
29
30pub async fn open_things(
31 things: Vec<String>,
32 max_workers: usize,
33 config: Arc<Config>,
34) -> Result<()> {
35 let num_cpus = num_cpus::get();
36 let max_workers = if max_workers == 0 || max_workers > num_cpus {
37 num_cpus
38 } else {
39 max_workers
40 };
41
42 let semaphore = Arc::new(Semaphore::new(max_workers));
43 let mut handles = vec![];
44
45 for thing in things {
46 let permit = semaphore.clone().acquire_owned().await?;
47 let config = config.clone();
48
49 let handle = tokio::spawn(async move {
50 let _permit = permit;
51
52 match alias_or_thing_to_uri(&thing, &config) {
53 Ok(uri) => {
54 if let Err(e) = open_it(&uri) {
55 eprintln!("[dkdc] failed to open {}: {}", thing, e);
56 }
57 }
58 Err(e) => {
59 eprintln!("[dkdc] skipping {}: {}", thing, e);
60 }
61 }
62 });
63
64 handles.push(handle);
65 }
66
67 for handle in handles {
69 handle.await?;
70 }
71
72 Ok(())
73}