951a522
use std::time::Duration;
use kenshell::proto::v1 as pb;
use tokio::time::sleep;
use crate::share::errors::GitError;
pub(crate) fn rpc_error(status: tonic::Status) -> GitError {
match status.code() {
tonic::Code::NotFound => GitError::NotFound,
tonic::Code::PermissionDenied => GitError::Forbidden,
tonic::Code::Unauthenticated => GitError::Unauthorized,
tonic::Code::AlreadyExists | tonic::Code::Aborted | tonic::Code::FailedPrecondition => {
GitError::Conflict(status.message().to_string())
}
tonic::Code::InvalidArgument => GitError::InvalidArgument(status.message().to_string()),
tonic::Code::Unimplemented => {
GitError::Unimplemented("operation is not supported by KenShell")
}
_ => GitError::Internal(status.message().to_string()),
}
}
pub(crate) async fn wait_job(
ks: &kenshell::KenShellClient,
job_id: &str,
timeout: Duration,
) -> Result<pb::Job, GitError> {
let deadline = tokio::time::Instant::now() + timeout;
let mut client = ks.job();
loop {
let job = client
.get_job(pb::GetJobRequest {
id: job_id.to_string(),
})
.await
.map_err(rpc_error)?
.into_inner()
.job
.ok_or_else(|| GitError::Internal("job missing".into()))?;
match pb::JobState::try_from(job.state).unwrap_or(pb::JobState::Unspecified) {
pb::JobState::Succeeded => return Ok(job),
pb::JobState::Failed | pb::JobState::Canceled => {
return Err(GitError::Internal(if job.error_message.is_empty() {
"job failed".to_string()
} else {
job.error_message
}));
}
_ => {}
}
if tokio::time::Instant::now() >= deadline {
return Err(GitError::Internal("job timed out".into()));
}
sleep(Duration::from_millis(400)).await;
}
}
impl crate::service::GitService {
pub(crate) fn job_timeout(&self) -> Duration {
Duration::from_secs(self.state.config.git.git_command_timeout_secs.max(30))
}
}