use tokio::sync::mpsc;
use crate::sources::{
AurPackageVoteState, AurVoteContext, AurVoteError, AurVoteOutcome, VoteAction, aur_vote,
aur_vote_state,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AurVoteRequest {
pub pkgbase: String,
pub action: VoteAction,
pub dry_run: bool,
pub ssh_timeout_secs: u32,
pub ssh_command: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AurVoteResponse {
pub result: Result<AurVoteOutcome, AurVoteError>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AurVoteStateRequest {
pub pkgbase: String,
pub ssh_timeout_secs: u32,
pub ssh_command: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AurVoteStateResponse {
pub pkgbase: String,
pub result: Result<AurPackageVoteState, AurVoteError>,
}
fn process_vote_request(request: AurVoteRequest) -> AurVoteResponse {
let context = AurVoteContext {
dry_run: request.dry_run,
ssh_timeout_secs: request.ssh_timeout_secs,
ssh_command: request.ssh_command,
};
AurVoteResponse {
result: aur_vote(&request.pkgbase, request.action, &context),
}
}
fn process_vote_state_request(request: AurVoteStateRequest) -> AurVoteStateResponse {
let context = AurVoteContext {
dry_run: false,
ssh_timeout_secs: request.ssh_timeout_secs,
ssh_command: request.ssh_command,
};
AurVoteStateResponse {
pkgbase: request.pkgbase.clone(),
result: aur_vote_state(&request.pkgbase, &context),
}
}
pub fn spawn_aur_vote_worker(
mut aur_vote_req_rx: mpsc::UnboundedReceiver<AurVoteRequest>,
aur_vote_res_tx: mpsc::UnboundedSender<AurVoteResponse>,
) {
tokio::spawn(async move {
while let Some(request) = aur_vote_req_rx.recv().await {
let res_tx = aur_vote_res_tx.clone();
tokio::task::spawn_blocking(move || {
let response = process_vote_request(request);
let _ = res_tx.send(response);
});
}
});
}
pub fn spawn_aur_vote_state_worker(
mut aur_vote_state_req_rx: mpsc::UnboundedReceiver<AurVoteStateRequest>,
aur_vote_state_res_tx: mpsc::UnboundedSender<AurVoteStateResponse>,
) {
tokio::spawn(async move {
while let Some(request) = aur_vote_state_req_rx.recv().await {
let res_tx = aur_vote_state_res_tx.clone();
tokio::task::spawn_blocking(move || {
let response = process_vote_state_request(request);
let _ = res_tx.send(response);
});
}
});
}
#[cfg(test)]
mod tests {
use super::*;
fn test_request(dry_run: bool, ssh_command: &str) -> AurVoteRequest {
AurVoteRequest {
pkgbase: "pacsea-bin".to_string(),
action: VoteAction::Vote,
dry_run,
ssh_timeout_secs: 10,
ssh_command: ssh_command.to_string(),
}
}
#[test]
fn process_vote_request_dry_run_success() {
let response = process_vote_request(test_request(true, "ssh"));
let outcome = response
.result
.expect("dry-run vote request should succeed");
assert!(outcome.dry_run);
assert_eq!(outcome.pkgbase, "pacsea-bin");
assert_eq!(outcome.action, VoteAction::Vote);
}
#[test]
fn process_vote_request_missing_ssh_binary_error() {
let response = process_vote_request(test_request(false, "__pacsea_missing_ssh__"));
match response.result {
Err(AurVoteError::SshNotFound(cmd)) => {
assert_eq!(cmd, "__pacsea_missing_ssh__");
}
other => panic!("expected SshNotFound, got {other:?}"),
}
}
#[test]
fn process_vote_state_request_missing_ssh_binary_error() {
let response = process_vote_state_request(AurVoteStateRequest {
pkgbase: "pacsea-bin".to_string(),
ssh_timeout_secs: 10,
ssh_command: "__pacsea_missing_ssh__".to_string(),
});
assert_eq!(response.pkgbase, "pacsea-bin");
match response.result {
Err(AurVoteError::SshNotFound(cmd)) => {
assert_eq!(cmd, "__pacsea_missing_ssh__");
}
other => panic!("expected SshNotFound, got {other:?}"),
}
}
}