Repository: meilisearch/meilisearch
File: crates/meilisearch/src/main.rs (Rust)

Code before:
        analytics::Analytics::new(&opt, index_scheduler.clone(), auth_controller.clone()).await;

    print_launch_resume(&opt, analytics.clone(), config_read_from);

    tokio::spawn(async move {
        tokio::signal::ctrl_c().await.unwrap();
        std::process::exit(130);
    });

    run_http(index_scheduler, auth_controller, opt, log_handle, Arc::new(analytics)).await?;

    Ok(())
}

/// Prompt the user about the contact email for support and news.
/// It only displays the prompt if the input is an interactive terminal.
async fn prompt_for_contact_email() -> anyhow::Result<Option<String>> {
    let stdin = tokio::io::stdin();

    if !stdin.is_terminal() {
        return Ok(None);
    }

    println!("Stay up to date! Get monthly updates about new features and tips to get the most out of Meilisearch.");
    println!("You can use the `--contact-email` parameter to disable this prompt.");
    print!("Enter your email or leave blank to skip> ");
    std::io::stdout().flush()?;

    let mut email = String::new();
    let mut stdin = BufReader::new(stdin);
    let _ = stdin.read_line(&mut email).await?;
    let email = email.trim();

    if email.is_empty() {
        Ok(None)
    } else {
        Ok(Some(email.to_string()))
    }
}

async fn register_contact_email(email: &str) -> anyhow::Result<()> {
    let url = format!(
        "https://api.hsforms.com/submissions/v3/integration/submit/{PORTAL_ID}/{FORM_GUID}"
    );

    let page_name = format!(
        "Meilisearch terminal prompt v{}.{}.{}",
        VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH
    );
    let response = reqwest::Client::new()
        .post(url)

Review comment (suggestion):
I would say that CLI communication should be very heavily skewed towards brevity and raw information. You don't usually fire up a console to have fun and browse around, you're there to accomplish a task.

Introducing the prompt will be an obstacle to that task, and asking for someone's email is particularly invasive and concerning, so a friendly tone is likely to make the experience even more aggravating.

I defer the final decision to you—I'm better at improving things for users, but in this case user experience is significantly less important than the company's needs.

Code after:
            if let Err(err) = register_contact_email(&email).await {
                eprintln!("Failed to register email: {}", err);
            }
        });
        drop(handle);
    }

    let analytics =
        analytics::Analytics::new(&opt, index_scheduler.clone(), auth_controller.clone()).await;

    print_launch_resume(&opt, analytics.clone(), config_read_from);

    tokio::spawn(async move {
        tokio::signal::ctrl_c().await.unwrap();
        std::process::exit(130);
    });

    run_http(index_scheduler, auth_controller, opt, log_handle, Arc::new(analytics)).await?;

    Ok(())
}

/// Prompt the user about the contact email for support and news.
/// It only displays the prompt if the input is an interactive terminal.
async fn prompt_for_contact_email() -> anyhow::Result<Option<String>> {
    let stdin = tokio::io::stdin();

    if !stdin.is_terminal() {
        return Ok(None);
    }

    println!("Get monthly updates about new features and tips to get the most out of Meilisearch.");
    println!("Use the --contact-email option to disable this prompt.");
    print!("Enter your email or leave blank to skip> ");
    std::io::stdout().flush()?;

    let mut email = String::new();
    let mut stdin = BufReader::new(stdin);
    let _ = stdin.read_line(&mut email).await?;
    let email = email.trim();

    if email.is_empty() {
        Ok(None)
    } else {
        Ok(Some(email.to_string()))
    }
}

async fn register_contact_email(email: &str) -> anyhow::Result<()> {
    let url = format!(
        "https://api.hsforms.com/submissions/v3/integration/submit/{PORTAL_ID}/{FORM_GUID}"