Contractless/src/bin/contractless-submit-key.rs

87 lines
2.8 KiB
Rust
Raw Normal View History

2026-05-24 17:56:57 +00:00
#[cfg(windows)]
2026-07-12 22:01:00 +00:00
use contractless::common::cli_prompts::prompt_hidden_nonempty;
2026-05-24 17:56:57 +00:00
#[cfg(windows)]
2026-07-12 22:01:00 +00:00
use contractless::startup::unlock_pipe::pipe_name;
2026-05-24 17:56:57 +00:00
#[cfg(windows)]
2026-07-12 22:01:00 +00:00
use contractless::startup::unlock_structs::{UnlockPipeRequest, UnlockPipeResponse};
2026-05-24 17:56:57 +00:00
#[cfg(windows)]
2026-07-12 22:01:00 +00:00
use contractless::{env, from_slice, to_string};
2026-05-24 17:56:57 +00:00
#[cfg(windows)]
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[cfg(windows)]
use tokio::net::windows::named_pipe::ClientOptions;
#[cfg(windows)]
#[tokio::main]
async fn main() {
// Keep the Windows-only service helper small: run the pipe request and print any failure.
if let Err(err) = run().await {
eprintln!("{err}");
std::process::exit(1);
}
}
#[cfg(windows)]
async fn run() -> Result<(), Box<dyn std::error::Error>> {
// The helper supports simple service checks as well as submitting the wallet key.
let command = env::args().nth(1).unwrap_or_else(|| "submit".to_string());
let request = match command.as_str() {
"ping" => UnlockPipeRequest::Ping,
"status" => UnlockPipeRequest::Status,
"submit" => {
// Wallet keys are hidden at the terminal and rejected if the user enters nothing.
let wallet_key = prompt_hidden_nonempty(
"Please enter your wallet key: ",
"Wallet key cannot be empty. Please try again.",
)
.await;
UnlockPipeRequest::SubmitKey { wallet_key }
}
other => {
return Err(format!(
"Unsupported command '{other}'. Use 'submit', 'ping', or 'status'."
)
.into())
}
};
let pipe = pipe_name();
let payload = to_string(&request)?;
// The service unlock pipe uses a length-prefixed JSON payload.
let mut client = ClientOptions::new().open(&pipe)?;
client.write_u32_le(payload.len() as u32).await?;
client.write_all(payload.as_bytes()).await?;
// Read the length-prefixed service reply and decode the response enum.
let response_len = client.read_u32_le().await? as usize;
let mut response_bytes = vec![0u8; response_len];
client.read_exact(&mut response_bytes).await?;
let response: UnlockPipeResponse = from_slice(&response_bytes)?;
match response {
UnlockPipeResponse::Pong => {
println!("Pong");
}
UnlockPipeResponse::Status { state } => {
println!("Service state: {state:?}");
}
UnlockPipeResponse::KeyAccepted => {
println!("Wallet key accepted.");
}
UnlockPipeResponse::Error { message } => {
return Err(message.into());
}
}
Ok(())
}
#[cfg(not(windows))]
fn main() {
// Non-Windows builds keep the binary present but clearly report that the pipe does not exist.
eprintln!("contractless-submit-key is only supported on Windows.");
std::process::exit(1);
}