const SCHEDULE_MIN_INTERVAL_SECS: u64 = 60;
pub(crate) fn parse_schedule_interval(raw: &str) -> Option<u64> {
let s = raw.trim().to_ascii_lowercase();
if s.is_empty() {
return None;
}
let (num_part, mult) = match s.strip_suffix('s') {
Some(n) => (n, 1u64),
None => match s.strip_suffix('m') {
Some(n) => (n, 60u64),
None => match s.strip_suffix('h') {
Some(n) => (n, 3600u64),
None => (s.as_str(), 1u64), },
},
};
let secs = num_part.parse::<u64>().ok()?.checked_mul(mult)?;
(secs >= SCHEDULE_MIN_INTERVAL_SECS).then_some(secs)
}
pub(crate) async fn submit_schedule_job(
target: &str,
task: &str,
interval_secs: u64,
budget_wei: u128,
max_runs: u32,
) -> Result<u64, String> {
super::sponsor_rate_guard()?;
let target_id = crate::app::registry::id_of_name(target).await?;
if target_id == 0 {
return Err("target agent not found".to_string());
}
let (signer, addr) = crate::app::chat::credit_signer()
.await
.ok_or_else(|| "no identity".to_string())?;
let from_hex = crate::encoding::bytes_to_hex_str(&addr);
let bridge_wei = crate::app::chat::escrow_bridge_wei(&from_hex, budget_wei).await?;
let fee_payer = crate::app::sponsor::signer()?;
crate::app::registry::schedule_job_sponsored_bridged(
&signer,
&fee_payer,
target_id,
task.as_bytes(),
interval_secs,
budget_wei,
max_runs,
crate::app::registry::ALPHA_USD_ADDRESS(),
bridge_wei,
)
.await?;
super::refresh_credits_pill().await;
let new_id = match crate::app::chat::credit_address_existing().await {
Some(addr) => crate::app::registry::jobs_of(&addr)
.await
.ok()
.and_then(|ids| ids.last().copied())
.unwrap_or(0),
None => 0,
};
Ok(new_id)
}
pub(crate) async fn cancel_schedule_job(job_id: u64) -> Result<String, String> {
super::sponsor_rate_guard()?;
let (signer, _addr) = crate::app::chat::credit_signer()
.await
.ok_or_else(|| "no identity".to_string())?;
let fee_payer = crate::app::sponsor::signer()?;
let tx = crate::app::registry::cancel_job_sponsored(
&signer,
&fee_payer,
job_id,
crate::app::registry::ALPHA_USD_ADDRESS(),
)
.await?;
super::refresh_credits_pill().await;
Ok(tx)
}