use crate::{chain::quantus_subxt, error::Result, log_print, log_success};
use clap::Subcommand;
#[derive(Subcommand, Debug)]
pub enum SchedulerCommands {
GetLastProcessedTimestamp,
Agenda {
#[arg(long)]
range: String,
},
ScheduleRemark {
#[arg(long)]
after: u32,
#[arg(long)]
from: String,
},
}
pub async fn get_last_processed_timestamp(
quantus_client: &crate::chain::client::QuantusClient,
) -> Result<Option<u64>> {
use quantus_subxt::api;
log_print!("🕒 Getting last processed timestamp from the scheduler");
let storage_addr = api::storage().scheduler().last_processed_timestamp();
let latest_block_hash = quantus_client.get_latest_block().await?;
let storage_at = quantus_client.client().storage().at(latest_block_hash);
let timestamp = storage_at.fetch(&storage_addr).await.map_err(|e| {
crate::error::QuantusError::NetworkError(format!(
"Failed to fetch last processed timestamp: {e:?}"
))
})?;
Ok(timestamp)
}
async fn list_agenda_range(
quantus_client: &crate::chain::client::QuantusClient,
range: &str,
) -> Result<()> {
use quantus_subxt::api;
let parts: Vec<&str> = range.split("..").collect();
if parts.len() != 2 {
return Err(crate::error::QuantusError::Generic(
"Invalid range format. Use --range <from>..<to>".to_string(),
));
}
let start: u32 = parts[0].trim().parse().map_err(|_| {
crate::error::QuantusError::Generic("Invalid start block in range".to_string())
})?;
let end: u32 = parts[1].trim().parse().map_err(|_| {
crate::error::QuantusError::Generic("Invalid end block in range".to_string())
})?;
if start > end {
return Err(crate::error::QuantusError::Generic("Range start must be <= end".to_string()));
}
let latest_block_hash = quantus_client.get_latest_block().await?;
let storage_at = quantus_client.client().storage().at(latest_block_hash);
log_print!("🗓️ Scheduler::Agenda entries for blocks {}..={} (inclusive)", start, end);
for bn in start..=end {
let addr = api::storage().scheduler().agenda(
quantus_subxt::api::runtime_types::qp_scheduler::BlockNumberOrTimestamp::BlockNumber(
bn,
),
);
match storage_at.fetch(&addr).await {
Ok(Some(agenda)) => {
log_print!("#{}: {:?}", bn, agenda);
},
Ok(None) => {
log_print!("#{}: <empty>", bn);
},
Err(e) => {
log_print!("#{}: error fetching agenda: {:?}", bn, e);
},
}
}
log_success!("Finished scanning Scheduler::Agenda");
Ok(())
}
async fn schedule_remark(
quantus_client: &crate::chain::client::QuantusClient,
after: u32,
from: &str,
execution_mode: crate::cli::common::ExecutionMode,
) -> Result<()> {
use quantus_subxt::api;
log_print!("🗓️ Scheduling System::remark after {} blocks", after);
let system_remark = quantus_subxt::api::runtime_types::frame_system::pallet::Call::remark {
remark: Vec::new(),
};
let runtime_call =
quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall::System(system_remark);
let when_u32: u32 = after;
let priority: u8 = 0;
let keypair = crate::wallet::load_keypair_from_wallet(from, None, None)?;
let schedule_tx = api::tx().scheduler().schedule(when_u32, priority, runtime_call);
let tx_hash = crate::cli::common::submit_transaction(
quantus_client,
&keypair,
schedule_tx,
None,
execution_mode,
)
.await?;
log_success!("📩 Schedule extrinsic submitted: {:?}", tx_hash);
Ok(())
}
pub async fn handle_scheduler_command(
command: SchedulerCommands,
node_url: &str,
execution_mode: crate::cli::common::ExecutionMode,
) -> Result<()> {
log_print!("🗓️ Scheduler");
let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
match command {
SchedulerCommands::GetLastProcessedTimestamp => {
match get_last_processed_timestamp(&quantus_client).await? {
Some(timestamp) => {
log_success!("🎉 Last processed timestamp: {}", timestamp);
},
None => {
log_print!(
"🤷 No last processed timestamp found. The scheduler may not have run yet."
);
},
}
Ok(())
},
SchedulerCommands::Agenda { range } => list_agenda_range(&quantus_client, &range).await,
SchedulerCommands::ScheduleRemark { after, from } =>
schedule_remark(&quantus_client, after, &from, execution_mode).await,
}
}