upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/client.rs108
1 files changed, 100 insertions, 8 deletions
diff --git a/src/lib/client.rs b/src/lib/client.rs
index 7933eaf..61a091d 100644
--- a/src/lib/client.rs
+++ b/src/lib/client.rs
@@ -2451,11 +2451,84 @@ pub async fn send_events(
2451 } 2451 }
2452 } 2452 }
2453 2453
2454 let m = if silent { 2454 let verbose = is_verbose();
2455 let is_test = std::env::var("NGITTEST").is_ok();
2456 let use_concise = !verbose && !is_test && !silent && animate;
2457
2458 // Set up the two-MultiProgress pattern (same as fetch_all):
2459 // 1. A spinner MultiProgress shown immediately (concise mode only)
2460 // 2. A detail MultiProgress that starts hidden and becomes visible after a
2461 // delay
2462 let spinner_multi = if use_concise {
2463 let sm = MultiProgress::new();
2464 let spinner = sm.add(
2465 ProgressBar::new_spinner()
2466 .with_style(
2467 ProgressStyle::with_template("{spinner} {msg}")
2468 .unwrap()
2469 .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈"),
2470 )
2471 .with_message("Publishing to nostr relays..."),
2472 );
2473 spinner.enable_steady_tick(Duration::from_millis(100));
2474 Some((sm, spinner))
2475 } else {
2476 None
2477 };
2478
2479 let m = if silent || is_test || use_concise {
2455 MultiProgress::with_draw_target(ProgressDrawTarget::hidden()) 2480 MultiProgress::with_draw_target(ProgressDrawTarget::hidden())
2456 } else { 2481 } else {
2457 MultiProgress::new() 2482 MultiProgress::new()
2458 }; 2483 };
2484
2485 // Pre-add a heading bar at position 0 so it has a reserved slot
2486 // before any relay bars are added.
2487 let heading_bar = if use_concise {
2488 let bar =
2489 m.add(ProgressBar::new(0).with_style(ProgressStyle::with_template("{msg}").unwrap()));
2490 Some(bar)
2491 } else {
2492 None
2493 };
2494
2495 let reveal_state: Option<Arc<BarRevealState>> = if use_concise {
2496 Some(Arc::new(BarRevealState {
2497 revealed: AtomicBool::new(false),
2498 deferred: Mutex::new(Vec::new()),
2499 }))
2500 } else {
2501 None
2502 };
2503
2504 // Spawn a background timer that transitions from spinner to detail view
2505 let detail_multi_for_timer = m.clone();
2506 let spinner_for_timer = spinner_multi.as_ref().map(|(_, s)| s.clone());
2507 let reveal_state_for_timer = reveal_state.clone();
2508 let heading_bar_for_timer = heading_bar.clone();
2509 let timer_handle = if use_concise {
2510 let handle = tokio::spawn(async move {
2511 tokio::time::sleep(Duration::from_millis(SPINNER_EXPAND_DELAY_MS)).await;
2512 if let Some(spinner) = spinner_for_timer {
2513 spinner.finish_and_clear();
2514 }
2515 detail_multi_for_timer.set_draw_target(ProgressDrawTarget::stderr());
2516 if let Some(heading) = heading_bar_for_timer {
2517 heading.finish_with_message("publishing to nostr relays...");
2518 }
2519 if let Some(state) = reveal_state_for_timer {
2520 let mut deferred = state.deferred.lock().unwrap();
2521 state.revealed.store(true, Ordering::Release);
2522 for df in deferred.drain(..) {
2523 df.bar.finish_with_message(df.message);
2524 }
2525 }
2526 });
2527 Some(handle)
2528 } else {
2529 None
2530 };
2531
2459 let pb_style = ProgressStyle::with_template(if animate { 2532 let pb_style = ProgressStyle::with_template(if animate {
2460 " {spinner} {prefix} {bar} {pos}/{len} {msg}" 2533 " {spinner} {prefix} {bar} {pos}/{len} {msg}"
2461 } else { 2534 } else {
@@ -2484,7 +2557,17 @@ pub async fn send_events(
2484 })?; 2557 })?;
2485 2558
2486 #[allow(clippy::borrow_deref_ref)] 2559 #[allow(clippy::borrow_deref_ref)]
2487 join_all(relays.iter().map(|&relay| async { 2560 join_all(relays.iter().map(|&relay| {
2561 let reveal_state_clone = reveal_state.clone();
2562 let my_write_relays = my_write_relays.clone();
2563 let repo_read_relays = repo_read_relays.clone();
2564 let fallback = fallback.clone();
2565 let m = m.clone();
2566 let events = events.clone();
2567 let pb_style = pb_style.clone();
2568 let pb_after_style_failed = pb_after_style_failed.clone();
2569 let pb_after_style_succeeded = pb_after_style_succeeded.clone();
2570 async move {
2488 let relay_clean = remove_trailing_slash(relay); 2571 let relay_clean = remove_trailing_slash(relay);
2489 let details = format!( 2572 let details = format!(
2490 "{}{}{} {}", 2573 "{}{}{} {}",
@@ -2532,8 +2615,7 @@ pub async fn send_events(
2532 Ok(_) => pb.inc(1), 2615 Ok(_) => pb.inc(1),
2533 Err(e) => { 2616 Err(e) => {
2534 pb.set_style(pb_after_style_failed.clone()); 2617 pb.set_style(pb_after_style_failed.clone());
2535 pb.finish_with_message( 2618 let msg = console::style(format!(
2536 console::style(format!(
2537 "error: {}", 2619 "error: {}",
2538 e.to_string() 2620 e.to_string()
2539 .replace("relay pool error:", "") 2621 .replace("relay pool error:", "")
@@ -2541,8 +2623,8 @@ pub async fn send_events(
2541 )) 2623 ))
2542 .for_stderr() 2624 .for_stderr()
2543 .red() 2625 .red()
2544 .to_string(), 2626 .to_string();
2545 ); 2627 finish_bar(&pb, msg, &reveal_state_clone);
2546 failed = true; 2628 failed = true;
2547 break; 2629 break;
2548 } 2630 }
@@ -2550,10 +2632,20 @@ pub async fn send_events(
2550 } 2632 }
2551 if !failed { 2633 if !failed {
2552 pb.set_style(pb_after_style_succeeded.clone()); 2634 pb.set_style(pb_after_style_succeeded.clone());
2553 pb.finish_with_message(""); 2635 finish_bar(&pb, String::new(), &reveal_state_clone);
2554 } 2636 }
2555 })) 2637 }}))
2556 .await; 2638 .await;
2639
2640 // Cancel the background timer if it hasn't fired yet, and clean up
2641 // the spinner. If the timer already fired, the abort is a no-op.
2642 if let Some(handle) = timer_handle {
2643 handle.abort();
2644 }
2645 if let Some((_, spinner)) = &spinner_multi {
2646 spinner.finish_and_clear();
2647 }
2648
2557 Ok(()) 2649 Ok(())
2558} 2650}
2559 2651