mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-05 08:10:39 +00:00
Merge remote-tracking branch 'origin/main' into merge-origin-main-20260420b
# Conflicts: # lib/crates/fabro-cli/src/commands/doctor.rs # lib/crates/fabro-cli/src/commands/model.rs # lib/crates/fabro-cli/src/commands/provider/login.rs # lib/crates/fabro-cli/src/commands/repo/init.rs # lib/crates/fabro-cli/src/commands/secret/list.rs # lib/crates/fabro-cli/src/commands/secret/rm.rs # lib/crates/fabro-cli/src/commands/secret/set.rs # lib/crates/fabro-cli/src/commands/system/df.rs # lib/crates/fabro-cli/src/commands/system/events.rs # lib/crates/fabro-cli/src/commands/system/info.rs # lib/crates/fabro-cli/src/commands/system/prune.rs # lib/crates/fabro-cli/src/commands/version.rs # lib/crates/fabro-cli/src/server_client.rs # lib/crates/fabro-server/src/csp.rs
This commit is contained in:
commit
42aeffeb6b
30 changed files with 312 additions and 320 deletions
|
|
@ -13,4 +13,4 @@
|
|||
mod generated {
|
||||
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
|
||||
}
|
||||
pub use generated::{Client, types};
|
||||
pub use generated::{Client as ApiClient, types};
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use fabro_util::printer::Printer;
|
|||
use tokio::sync::OnceCell;
|
||||
|
||||
use crate::args::{ServerConnectionArgs, ServerTargetArgs};
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::{server_client, user_config};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -35,7 +35,7 @@ pub(crate) struct CommandContext {
|
|||
machine_settings: SettingsLayer,
|
||||
cli_settings: CliSettings,
|
||||
server_mode: ServerMode,
|
||||
server: OnceCell<Arc<ServerStoreClient>>,
|
||||
server: OnceCell<Arc<Client>>,
|
||||
}
|
||||
|
||||
impl CommandContext {
|
||||
|
|
@ -135,7 +135,7 @@ impl CommandContext {
|
|||
&self.cli_settings
|
||||
}
|
||||
|
||||
pub(crate) async fn server(&self) -> Result<Arc<ServerStoreClient>> {
|
||||
pub(crate) async fn server(&self) -> Result<Arc<Client>> {
|
||||
let server_mode = self.server_mode.clone();
|
||||
let base_config_path = self.base_config_path.clone();
|
||||
let machine_settings = self.machine_settings.clone();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use fabro_types::settings::cli::{CliLayer, OutputFormat};
|
|||
use fabro_util::printer::Printer;
|
||||
|
||||
use crate::args::ArtifactCpArgs;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::shared::{print_json_pretty, split_run_path};
|
||||
|
||||
pub(super) async fn cp_command(
|
||||
|
|
@ -140,7 +140,7 @@ pub(super) async fn cp_command(
|
|||
}
|
||||
|
||||
async fn write_artifact_file(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
entry: &super::ArtifactEntry,
|
||||
dest_file: &Path,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use fabro_util::printer::Printer;
|
|||
|
||||
use crate::args::{ArtifactCommand, ArtifactNamespace, ServerTargetArgs};
|
||||
use crate::command_context::CommandContext;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize)]
|
||||
pub(super) struct ArtifactEntry {
|
||||
|
|
@ -29,7 +29,7 @@ pub(super) async fn resolve_artifacts(
|
|||
cli: &CliSettings,
|
||||
cli_layer: &CliLayer,
|
||||
printer: Printer,
|
||||
) -> Result<(RunId, ServerStoreClient, Vec<ArtifactEntry>)> {
|
||||
) -> Result<(RunId, Client, Vec<ArtifactEntry>)> {
|
||||
let ctx = CommandContext::for_target(server, printer, cli.clone(), cli_layer)?;
|
||||
let client = ctx.server().await?;
|
||||
let run_id = client.resolve_run(run_selector).await?.run_id;
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ pub(super) async fn login_command(
|
|||
#[cfg(unix)]
|
||||
async fn fetch_cli_auth_config(target: &ServerTarget) -> Result<types::CliAuthConfig> {
|
||||
let (http_client, base_url) = user_config::build_public_http_client(target)?;
|
||||
let client = fabro_api::Client::new_with_client(&base_url, http_client);
|
||||
let client = fabro_api::ApiClient::new_with_client(&base_url, http_client);
|
||||
client
|
||||
.get_cli_auth_config()
|
||||
.send()
|
||||
|
|
|
|||
|
|
@ -312,10 +312,7 @@ pub(crate) async fn run_doctor(
|
|||
}
|
||||
};
|
||||
|
||||
if let Err(err) = server
|
||||
.send_api(|client| async move { client.get_health().send().await })
|
||||
.await
|
||||
{
|
||||
if let Err(err) = server.get_health().await {
|
||||
report.sections.push(CheckSection {
|
||||
title: "Server".to_string(),
|
||||
checks: vec![CheckResult {
|
||||
|
|
@ -352,12 +349,8 @@ pub(crate) async fn run_doctor(
|
|||
}],
|
||||
});
|
||||
|
||||
match server
|
||||
.send_api(|client| async move { client.run_diagnostics().send().await })
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let diagnostics = response.into_inner();
|
||||
match server.run_diagnostics().await {
|
||||
Ok(diagnostics) => {
|
||||
report.sections[0]
|
||||
.checks
|
||||
.push(check_version_parity(&diagnostics.version));
|
||||
|
|
|
|||
|
|
@ -1094,19 +1094,17 @@ async fn setup_github_app(
|
|||
}
|
||||
|
||||
async fn persist_vault_secrets_via_server(
|
||||
client: &fabro_api::Client,
|
||||
client: &server_client::Client,
|
||||
secrets: &[CreateSecretRequest],
|
||||
) -> Result<()> {
|
||||
for secret in secrets {
|
||||
client
|
||||
.create_secret()
|
||||
.body(CreateSecretRequest {
|
||||
.create_secret(CreateSecretRequest {
|
||||
name: secret.name.clone(),
|
||||
value: secret.value.clone(),
|
||||
type_: secret.type_,
|
||||
description: secret.description.clone(),
|
||||
})
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
|
||||
|
|
@ -1117,14 +1115,14 @@ async fn persist_vault_secrets_with(
|
|||
storage_dir: &Path,
|
||||
secrets: &[CreateSecretRequest],
|
||||
server_was_running: bool,
|
||||
connect_api_client: impl for<'a> Fn(&'a Path) -> BoxFuture<'a, Result<fabro_api::Client>>,
|
||||
connect_server: impl for<'a> Fn(&'a Path) -> BoxFuture<'a, Result<server_client::Client>>,
|
||||
stop_server: impl for<'a> Fn(&'a Path, Duration) -> BoxFuture<'a, bool>,
|
||||
) -> Result<()> {
|
||||
if secrets.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let client = match connect_api_client(storage_dir).await {
|
||||
let client = match connect_server(storage_dir).await {
|
||||
Ok(client) => client,
|
||||
Err(err) => {
|
||||
if !server_was_running {
|
||||
|
|
@ -1173,7 +1171,7 @@ async fn persist_install_outputs(
|
|||
vault_secrets,
|
||||
settings_write,
|
||||
server_was_running,
|
||||
|path| Box::pin(server_client::connect_api_client(path)),
|
||||
|path| Box::pin(server_client::connect_server(path)),
|
||||
|path, timeout| {
|
||||
Box::pin(async move { stop::stop_server(path, timeout).await.unwrap_or(false) })
|
||||
},
|
||||
|
|
@ -1303,7 +1301,7 @@ async fn persist_install_outputs_with_settings(
|
|||
vault_secrets: &[CreateSecretRequest],
|
||||
settings_write: Option<PendingSettingsWrite<'_>>,
|
||||
server_was_running: bool,
|
||||
connect_api_client: impl for<'a> Fn(&'a Path) -> BoxFuture<'a, Result<fabro_api::Client>>,
|
||||
connect_server: impl for<'a> Fn(&'a Path) -> BoxFuture<'a, Result<server_client::Client>>,
|
||||
stop_server: impl for<'a> Fn(&'a Path, Duration) -> BoxFuture<'a, bool>,
|
||||
) -> Result<()> {
|
||||
persist_server_env_secrets(storage_dir, server_env_secrets)?;
|
||||
|
|
@ -1317,7 +1315,7 @@ async fn persist_install_outputs_with_settings(
|
|||
storage_dir,
|
||||
vault_secrets,
|
||||
server_was_running,
|
||||
connect_api_client,
|
||||
connect_server,
|
||||
stop_server,
|
||||
)
|
||||
.await;
|
||||
|
|
@ -2486,10 +2484,7 @@ client_id = "client-id"
|
|||
&vault_secrets,
|
||||
false,
|
||||
|_| {
|
||||
let client = fabro_api::Client::new_with_client(
|
||||
&server.base_url(),
|
||||
fabro_test::test_http_client(),
|
||||
);
|
||||
let client = server_client::Client::new_no_proxy(&server.base_url()).unwrap();
|
||||
Box::pin(async move { Ok(client) })
|
||||
},
|
||||
{
|
||||
|
|
@ -2548,10 +2543,7 @@ client_id = "client-id"
|
|||
&vault_secrets,
|
||||
true,
|
||||
|_| {
|
||||
let client = fabro_api::Client::new_with_client(
|
||||
&server.base_url(),
|
||||
fabro_test::test_http_client(),
|
||||
);
|
||||
let client = server_client::Client::new_no_proxy(&server.base_url()).unwrap();
|
||||
Box::pin(async move { Ok(client) })
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
use anyhow::{Context, Result, bail};
|
||||
use cli_table::format::{Border, Justify, Separator};
|
||||
use cli_table::{Cell, CellStruct, Color, Style, Table};
|
||||
use fabro_api::{self, types as api_types};
|
||||
use fabro_api::types as api_types;
|
||||
use fabro_model::{Catalog, Model, Provider};
|
||||
use fabro_types::settings::CliSettings;
|
||||
use fabro_types::settings::cli::{CliLayer, OutputFormat};
|
||||
use fabro_util::printer::Printer;
|
||||
use fabro_util::terminal::Styles;
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::args::{ModelListArgs, ModelTestArgs, ModelsCommand};
|
||||
use crate::command_context::CommandContext;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
|
@ -193,71 +192,13 @@ fn model_test_row_from_status(model: &Model, status: &str, result_color: Color)
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_type<TInput, TOutput>(value: TInput) -> Result<TOutput>
|
||||
where
|
||||
TInput: serde::Serialize,
|
||||
TOutput: DeserializeOwned,
|
||||
{
|
||||
serde_json::from_value(serde_json::to_value(value)?).map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn fetch_models_from_server(
|
||||
client: &ServerStoreClient,
|
||||
provider: Option<&str>,
|
||||
query: Option<&str>,
|
||||
) -> Result<Vec<Model>> {
|
||||
let mut offset = 0u64;
|
||||
let mut models = Vec::new();
|
||||
|
||||
loop {
|
||||
let response = client
|
||||
.send_api(|api| async move {
|
||||
let mut request = api.list_models().page_limit(100u64).page_offset(offset);
|
||||
if let Some(provider) = provider {
|
||||
request = request.provider(provider.to_string());
|
||||
}
|
||||
if let Some(query) = query {
|
||||
request = request.query(query.to_string());
|
||||
}
|
||||
request.send().await
|
||||
})
|
||||
.await?;
|
||||
let parsed = response.into_inner();
|
||||
let count = parsed.data.len() as u64;
|
||||
models.extend(convert_type::<_, Vec<Model>>(parsed.data)?);
|
||||
if !parsed.meta.has_more {
|
||||
break;
|
||||
}
|
||||
offset += count;
|
||||
}
|
||||
|
||||
Ok(models)
|
||||
}
|
||||
|
||||
async fn test_model_via_server(
|
||||
client: &ServerStoreClient,
|
||||
model_id: &str,
|
||||
mode: Option<api_types::ModelTestMode>,
|
||||
) -> Result<api_types::ModelTestResult> {
|
||||
let response = client
|
||||
.send_api(|api| async move {
|
||||
let mut request = api.test_model().id(model_id.to_string());
|
||||
if let Some(mode) = mode {
|
||||
request = request.mode(mode);
|
||||
}
|
||||
request.send().await
|
||||
})
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
#[allow(
|
||||
clippy::print_stdout,
|
||||
clippy::print_stderr,
|
||||
reason = "Progress goes to stderr while tables or JSON results go to stdout."
|
||||
)]
|
||||
async fn test_models_via_server(
|
||||
client: &ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
provider: Option<&str>,
|
||||
model: Option<&str>,
|
||||
deep: bool,
|
||||
|
|
@ -279,7 +220,7 @@ async fn test_models_via_server(
|
|||
if !json_output {
|
||||
eprint!("Testing {model_id}...");
|
||||
}
|
||||
let result = test_model_via_server(client, model_id, request_mode).await;
|
||||
let result = client.test_model(model_id, request_mode).await;
|
||||
if !json_output {
|
||||
eprintln!(" done");
|
||||
}
|
||||
|
|
@ -329,7 +270,7 @@ async fn test_models_via_server(
|
|||
rows.push(row);
|
||||
json_rows.push(model_test_row_from_status(&info, &status, result_color));
|
||||
} else {
|
||||
let models_to_test = fetch_models_from_server(client, provider, None).await?;
|
||||
let models_to_test = client.list_models(provider, None).await?;
|
||||
if models_to_test.is_empty() {
|
||||
bail!("No models found");
|
||||
}
|
||||
|
|
@ -338,7 +279,7 @@ async fn test_models_via_server(
|
|||
if !json_output {
|
||||
eprint!("Testing {}...", info.id);
|
||||
}
|
||||
let result = test_model_via_server(client, &info.id, request_mode).await;
|
||||
let result = client.test_model(&info.id, request_mode).await;
|
||||
if !json_output {
|
||||
eprintln!(" done");
|
||||
}
|
||||
|
|
@ -434,7 +375,7 @@ async fn test_models_via_server(
|
|||
)]
|
||||
async fn run_models(
|
||||
command: ModelsCommand,
|
||||
client: &ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
json_output: bool,
|
||||
) -> Result<()> {
|
||||
let styles = Styles::detect_stdout();
|
||||
|
|
@ -443,8 +384,9 @@ async fn run_models(
|
|||
ModelsCommand::List(ModelListArgs {
|
||||
provider, query, ..
|
||||
}) => {
|
||||
let models =
|
||||
fetch_models_from_server(client, provider.as_deref(), query.as_deref()).await?;
|
||||
let models = client
|
||||
.list_models(provider.as_deref(), query.as_deref())
|
||||
.await?;
|
||||
|
||||
if json_output {
|
||||
println!("{}", serde_json::to_string_pretty(&models)?);
|
||||
|
|
@ -485,8 +427,8 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
|
||||
fn test_api_client(api_url: &str) -> ServerStoreClient {
|
||||
ServerStoreClient::new_no_proxy(api_url).expect("test API client should build")
|
||||
fn test_client(api_url: &str) -> server_client::Client {
|
||||
server_client::Client::new_no_proxy(api_url).unwrap()
|
||||
}
|
||||
|
||||
fn test_model_json(id: &str, provider: Provider) -> serde_json::Value {
|
||||
|
|
@ -592,10 +534,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let response = test_model_via_server(&client, "test-model", None)
|
||||
.await
|
||||
.unwrap();
|
||||
let client = test_client(&server.url(""));
|
||||
let response = client.test_model("test-model", None).await.unwrap();
|
||||
|
||||
assert_eq!(response.status, api_types::ModelTestResultStatus::Ok);
|
||||
assert!(response.error_message.is_none());
|
||||
|
|
@ -622,11 +562,11 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let response =
|
||||
test_model_via_server(&client, "test-model", Some(api_types::ModelTestMode::Deep))
|
||||
.await
|
||||
.unwrap();
|
||||
let client = test_client(&server.url(""));
|
||||
let response = client
|
||||
.test_model("test-model", Some(api_types::ModelTestMode::Deep))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status, api_types::ModelTestResultStatus::Error);
|
||||
assert_eq!(response.error_message.as_deref(), Some("timeout"));
|
||||
|
|
@ -650,10 +590,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let response = test_model_via_server(&client, "kimi-k2.5", None)
|
||||
.await
|
||||
.unwrap();
|
||||
let client = test_client(&server.url(""));
|
||||
let response = client.test_model("kimi-k2.5", None).await.unwrap();
|
||||
|
||||
assert_eq!(response.status, api_types::ModelTestResultStatus::Skip);
|
||||
assert!(response.error_message.is_none());
|
||||
|
|
@ -676,8 +614,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let result = test_model_via_server(&client, "bad-model", None).await;
|
||||
let client = test_client(&server.url(""));
|
||||
let result = client.test_model("bad-model", None).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().to_string().contains("Model not found"));
|
||||
}
|
||||
|
|
@ -703,8 +641,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let models = fetch_models_from_server(&client, None, None).await.unwrap();
|
||||
let client = test_client(&server.url(""));
|
||||
let models = client.list_models(None, None).await.unwrap();
|
||||
|
||||
mock.assert_async().await;
|
||||
assert_eq!(models.len(), 1);
|
||||
|
|
@ -734,10 +672,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let models = fetch_models_from_server(&client, Some("anthropic"), None)
|
||||
.await
|
||||
.unwrap();
|
||||
let client = test_client(&server.url(""));
|
||||
let models = client.list_models(Some("anthropic"), None).await.unwrap();
|
||||
|
||||
assert_eq!(models.len(), 1);
|
||||
assert_eq!(models[0].id, "model-a");
|
||||
|
|
@ -765,10 +701,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let models = fetch_models_from_server(&client, None, Some("sonnet"))
|
||||
.await
|
||||
.unwrap();
|
||||
let client = test_client(&server.url(""));
|
||||
let models = client.list_models(None, Some("sonnet")).await.unwrap();
|
||||
|
||||
mock.assert_async().await;
|
||||
assert_eq!(models.len(), 1);
|
||||
|
|
@ -813,8 +747,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let models = fetch_models_from_server(&client, None, None).await.unwrap();
|
||||
let client = test_client(&server.url(""));
|
||||
let models = client.list_models(None, None).await.unwrap();
|
||||
|
||||
first_page.assert_async().await;
|
||||
second_page.assert_async().await;
|
||||
|
|
@ -836,8 +770,8 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = test_api_client(&server.url(""));
|
||||
let result = fetch_models_from_server(&client, None, None).await;
|
||||
let client = test_client(&server.url(""));
|
||||
let result = client.list_models(None, None).await;
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,21 +34,13 @@ pub(super) async fn login_command(
|
|||
};
|
||||
let credential_id = credential_id_for(&credential).map_err(anyhow::Error::msg)?;
|
||||
let value = serde_json::to_string(&credential)?;
|
||||
let request_credential_id = credential_id.clone();
|
||||
let request_value = value.clone();
|
||||
|
||||
server
|
||||
.send_api(|client| async move {
|
||||
client
|
||||
.create_secret()
|
||||
.body(types::CreateSecretRequest {
|
||||
name: request_credential_id.clone(),
|
||||
value: request_value.clone(),
|
||||
type_: types::SecretType::Credential,
|
||||
description: None,
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
.create_secret(types::CreateSecretRequest {
|
||||
name: credential_id.clone(),
|
||||
value,
|
||||
type_: types::SecretType::Credential,
|
||||
description: None,
|
||||
})
|
||||
.await?;
|
||||
fabro_util::printerr!(
|
||||
|
|
|
|||
|
|
@ -222,20 +222,8 @@ async fn check_github_app_installation(
|
|||
}
|
||||
};
|
||||
|
||||
let check_owner = owner.clone();
|
||||
let check_repo = repo.clone();
|
||||
let check = match server
|
||||
.send_api(|client| async move {
|
||||
client
|
||||
.get_github_repo()
|
||||
.owner(check_owner.clone())
|
||||
.name(check_repo.clone())
|
||||
.send()
|
||||
.await
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(response) => response.into_inner(),
|
||||
let check = match server.get_github_repo(&owner, &repo).await {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
fabro_util::printerr!(printer, "\n Warning: could not check GitHub access: {err}");
|
||||
return;
|
||||
|
|
@ -275,21 +263,8 @@ async fn check_github_app_installation(
|
|||
})
|
||||
.await;
|
||||
|
||||
let recheck_owner = owner.clone();
|
||||
let recheck_repo = repo.clone();
|
||||
match server
|
||||
.send_api(|client| async move {
|
||||
client
|
||||
.get_github_repo()
|
||||
.owner(recheck_owner.clone())
|
||||
.name(recheck_repo.clone())
|
||||
.send()
|
||||
.await
|
||||
})
|
||||
.await
|
||||
{
|
||||
match server.get_github_repo(&owner, &repo).await {
|
||||
Ok(response) => {
|
||||
let response = response.into_inner();
|
||||
if response.accessible {
|
||||
let green = console::Style::new().green();
|
||||
fabro_util::printerr!(
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ pub(crate) async fn attach_run(
|
|||
}
|
||||
|
||||
pub(crate) async fn attach_run_with_client(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
kill_on_detach: bool,
|
||||
styles: &'static Styles,
|
||||
|
|
@ -152,7 +152,7 @@ fn replay_run_with_client(
|
|||
}
|
||||
|
||||
async fn attach_live_run_with_client(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
existing_events: Vec<EventEnvelope>,
|
||||
mut stream: server_client::RunAttachEventStream,
|
||||
|
|
@ -226,7 +226,7 @@ async fn attach_live_run_with_client(
|
|||
}
|
||||
|
||||
async fn handle_pending_server_interview(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
auto_approve: bool,
|
||||
progress_ui: &mut run_progress::ProgressUI,
|
||||
|
|
@ -262,7 +262,7 @@ async fn handle_pending_server_interview(
|
|||
}
|
||||
|
||||
async fn handle_detach_signal(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
kill_on_detach: bool,
|
||||
printer: Printer,
|
||||
|
|
@ -316,7 +316,7 @@ fn api_question_to_question(question: &types::ApiQuestion) -> Question {
|
|||
}
|
||||
|
||||
async fn submit_server_interview_answer(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
qid: &str,
|
||||
answer: &fabro_interview::Answer,
|
||||
|
|
@ -625,7 +625,7 @@ mod tests {
|
|||
.header("Content-Type", "application/json")
|
||||
.body(terminal_run_state_response().to_string());
|
||||
});
|
||||
let client = server_client::ServerStoreClient::new_no_proxy(&server.base_url()).unwrap();
|
||||
let client = server_client::Client::new_no_proxy(&server.base_url()).unwrap();
|
||||
|
||||
handle_detach_signal(&client, &run_id, true, Printer::Default).await;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use tracing::{debug, info};
|
|||
|
||||
use crate::args::{CpArgs, ServerTargetArgs};
|
||||
use crate::command_context::CommandContext;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::shared::{print_json_pretty, split_run_path};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -131,7 +131,7 @@ async fn resolve_client_and_run_id(
|
|||
cli: &CliSettings,
|
||||
cli_layer: &CliLayer,
|
||||
printer: Printer,
|
||||
) -> Result<(ServerStoreClient, fabro_types::RunId)> {
|
||||
) -> Result<(Client, fabro_types::RunId)> {
|
||||
let ctx = CommandContext::for_target(server, printer, cli.clone(), cli_layer)?;
|
||||
let client = ctx.server().await?;
|
||||
let run_id = client.resolve_run(run_prefix).await?.run_id;
|
||||
|
|
@ -139,7 +139,7 @@ async fn resolve_client_and_run_id(
|
|||
}
|
||||
|
||||
async fn write_sandbox_file(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
remote_path: &str,
|
||||
local_path: &Path,
|
||||
|
|
@ -157,7 +157,7 @@ async fn write_sandbox_file(
|
|||
}
|
||||
|
||||
async fn upload_sandbox_file(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
local_path: &Path,
|
||||
remote_path: &str,
|
||||
|
|
@ -169,7 +169,7 @@ async fn upload_sandbox_file(
|
|||
}
|
||||
|
||||
async fn download_recursive(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
remote_path: &str,
|
||||
local_path: &Path,
|
||||
|
|
@ -194,7 +194,7 @@ async fn download_recursive(
|
|||
}
|
||||
|
||||
async fn upload_recursive(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
local_path: &Path,
|
||||
remote_path: &str,
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ fn try_parse_relative_duration(s: &str) -> Option<chrono::Duration> {
|
|||
}
|
||||
|
||||
async fn follow_store_logs(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
seq: u32,
|
||||
pretty: bool,
|
||||
|
|
@ -225,7 +225,7 @@ async fn follow_store_logs(
|
|||
}
|
||||
|
||||
async fn run_concluded(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
) -> Result<bool> {
|
||||
let state = client
|
||||
|
|
@ -239,7 +239,7 @@ async fn run_concluded(
|
|||
}
|
||||
|
||||
async fn flush_remaining_store_events(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
next_seq: u32,
|
||||
pretty: bool,
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ pub(crate) fn api_check_report_to_local(report: &types::PreflightCheckReport) ->
|
|||
}
|
||||
|
||||
pub(crate) async fn print_run_summary_with_client(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
local_run_dir: Option<&Path>,
|
||||
styles: &Styles,
|
||||
|
|
@ -292,7 +292,7 @@ pub(crate) fn print_final_output(output: Option<&str>, styles: &Styles, printer:
|
|||
}
|
||||
|
||||
async fn resolve_final_output_with_client(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
checkpoint: Option<&fabro_types::Checkpoint>,
|
||||
) -> Result<Option<String>> {
|
||||
|
|
@ -317,7 +317,7 @@ async fn resolve_final_output_with_client(
|
|||
}
|
||||
|
||||
async fn resolve_response_string(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
response: &str,
|
||||
) -> Result<Option<String>> {
|
||||
|
|
@ -342,7 +342,7 @@ fn blob_id_from_response(response: &str) -> Option<RunBlobId> {
|
|||
}
|
||||
|
||||
async fn list_artifact_display_entries_with_client(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
) -> Result<Vec<(String, u32, String)>> {
|
||||
let mut entries = Vec::new();
|
||||
|
|
@ -356,7 +356,7 @@ async fn list_artifact_display_entries_with_client(
|
|||
}
|
||||
|
||||
async fn print_assets_with_client(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
styles: &Styles,
|
||||
printer: Printer,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use serde::Serialize;
|
|||
use crate::args::RewindArgs;
|
||||
use crate::command_context::CommandContext;
|
||||
use crate::commands::store::rebuild::rebuild_run_store;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::shared::repo::ensure_matching_repo_origin;
|
||||
use crate::shared::{color_if, print_json_pretty};
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ pub(crate) fn timeline_entries_json(timeline: &RunTimeline) -> Vec<TimelineEntry
|
|||
}
|
||||
|
||||
async fn reset_rewound_run_state(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
git_store: &Store,
|
||||
run_id: &fabro_types::RunId,
|
||||
entry: &TimelineEntry,
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ async fn apply_worker_control_line(
|
|||
|
||||
fn build_artifact_uploader(
|
||||
run_id: RunId,
|
||||
client: server_client::ServerStoreClient,
|
||||
client: server_client::Client,
|
||||
artifact_upload_token: Option<String>,
|
||||
) -> Arc<dyn StageArtifactUploader> {
|
||||
match artifact_upload_token {
|
||||
|
|
@ -254,7 +254,7 @@ fn build_artifact_uploader(
|
|||
|
||||
struct HttpArtifactUploader {
|
||||
run_id: RunId,
|
||||
client: server_client::ServerStoreClient,
|
||||
client: server_client::Client,
|
||||
bearer_token: String,
|
||||
}
|
||||
|
||||
|
|
@ -318,16 +318,13 @@ impl StageArtifactUploader for MissingArtifactUploadTokenUploader {
|
|||
#[derive(Clone)]
|
||||
struct HttpRunStore {
|
||||
run_id: RunId,
|
||||
client: server_client::ServerStoreClient,
|
||||
client: server_client::Client,
|
||||
state: Arc<Mutex<RunProjection>>,
|
||||
events: Arc<Mutex<Option<Vec<EventEnvelope>>>>,
|
||||
}
|
||||
|
||||
impl HttpRunStore {
|
||||
async fn connect(
|
||||
run_id: RunId,
|
||||
client: server_client::ServerStoreClient,
|
||||
) -> Result<RunStoreHandle> {
|
||||
async fn connect(run_id: RunId, client: server_client::Client) -> Result<RunStoreHandle> {
|
||||
let state = client
|
||||
.get_run_state(&run_id)
|
||||
.await
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use fabro_types::RunId;
|
|||
use crate::server_client;
|
||||
|
||||
pub(crate) async fn start_run_with_client(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &RunId,
|
||||
resume: bool,
|
||||
) -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ impl Action {
|
|||
async fn run_bulk(
|
||||
action: Action,
|
||||
identifiers: &[String],
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
cli: &CliSettings,
|
||||
printer: Printer,
|
||||
) -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ pub(crate) async fn remove_command(
|
|||
|
||||
async fn remove_from(
|
||||
args: &RunsRemoveArgs,
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
cli: &CliSettings,
|
||||
printer: Printer,
|
||||
) -> Result<()> {
|
||||
|
|
@ -83,7 +83,7 @@ async fn remove_from(
|
|||
}
|
||||
|
||||
async fn delete_server_run(
|
||||
client: &server_client::ServerStoreClient,
|
||||
client: &server_client::Client,
|
||||
run_id: &fabro_types::RunId,
|
||||
force: bool,
|
||||
) -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use fabro_util::printer::Printer;
|
|||
use fabro_util::terminal::Styles;
|
||||
|
||||
use crate::args::SecretListArgs;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::shared::print_json_pretty;
|
||||
|
||||
fn format_age(dt: DateTime<Utc>, now: DateTime<Utc>) -> String {
|
||||
|
|
@ -23,15 +23,12 @@ fn format_age(dt: DateTime<Utc>, now: DateTime<Utc>) -> String {
|
|||
}
|
||||
|
||||
pub(super) async fn list_command(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
_args: &SecretListArgs,
|
||||
cli: &CliSettings,
|
||||
printer: Printer,
|
||||
) -> Result<()> {
|
||||
let response = client
|
||||
.send_api(|api| async move { api.list_secrets().send().await })
|
||||
.await?;
|
||||
let secrets = response.into_inner().data;
|
||||
let secrets = client.list_secrets().await?;
|
||||
if cli.output.format == OutputFormat::Json {
|
||||
print_json_pretty(&secrets)?;
|
||||
return Ok(());
|
||||
|
|
|
|||
|
|
@ -1,29 +1,19 @@
|
|||
use anyhow::Result;
|
||||
use fabro_api::types;
|
||||
use fabro_types::settings::CliSettings;
|
||||
use fabro_types::settings::cli::OutputFormat;
|
||||
use fabro_util::printer::Printer;
|
||||
|
||||
use crate::args::SecretRmArgs;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::shared::print_json_pretty;
|
||||
|
||||
pub(super) async fn rm_command(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
args: &SecretRmArgs,
|
||||
cli: &CliSettings,
|
||||
printer: Printer,
|
||||
) -> Result<()> {
|
||||
client
|
||||
.send_api(|api| async move {
|
||||
api.delete_secret_by_name()
|
||||
.body(types::DeleteSecretRequest {
|
||||
name: args.key.clone(),
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
})
|
||||
.await?;
|
||||
client.delete_secret_by_name(&args.key).await?;
|
||||
if cli.output.format == OutputFormat::Json {
|
||||
print_json_pretty(&serde_json::json!({ "key": args.key }))?;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use fabro_util::printer::Printer;
|
|||
use tokio::task::spawn_blocking;
|
||||
|
||||
use crate::args::{SecretSetArgs, SecretTypeArg};
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::shared::print_json_pretty;
|
||||
use crate::shared::provider_auth::prompt_password;
|
||||
|
||||
|
|
@ -58,26 +58,20 @@ async fn resolve_value(args: &SecretSetArgs) -> Result<String> {
|
|||
}
|
||||
|
||||
pub(super) async fn set_command(
|
||||
client: &ServerStoreClient,
|
||||
client: &Client,
|
||||
args: &SecretSetArgs,
|
||||
cli: &CliSettings,
|
||||
printer: Printer,
|
||||
) -> Result<()> {
|
||||
let value = resolve_value(args).await?;
|
||||
let meta = client
|
||||
.send_api(|api| async move {
|
||||
api.create_secret()
|
||||
.body(types::CreateSecretRequest {
|
||||
name: args.key.clone(),
|
||||
value: value.clone(),
|
||||
type_: api_secret_type(args.r#type),
|
||||
description: args.description.clone(),
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
.create_secret(types::CreateSecretRequest {
|
||||
name: args.key.clone(),
|
||||
value,
|
||||
type_: api_secret_type(args.r#type),
|
||||
description: args.description.clone(),
|
||||
})
|
||||
.await?
|
||||
.into_inner();
|
||||
.await?;
|
||||
if cli.output.format == OutputFormat::Json {
|
||||
print_json_pretty(&meta)?;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use tokio::task::spawn_blocking;
|
|||
use super::run_export::StoreRunExport;
|
||||
use crate::args::StoreDumpArgs;
|
||||
use crate::command_context::CommandContext;
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
use crate::shared::{absolute_or_current, print_json_pretty};
|
||||
|
||||
pub(crate) async fn dump_command(
|
||||
|
|
@ -164,12 +164,12 @@ impl DumpDataSource for LocalDumpSource<'_> {
|
|||
}
|
||||
|
||||
struct ServerDumpSource<'a> {
|
||||
client: &'a ServerStoreClient,
|
||||
client: &'a Client,
|
||||
run_id: &'a RunId,
|
||||
}
|
||||
|
||||
impl<'a> ServerDumpSource<'a> {
|
||||
fn new(client: &'a ServerStoreClient, run_id: &'a RunId) -> Self {
|
||||
fn new(client: &'a Client, run_id: &'a RunId) -> Self {
|
||||
Self { client, run_id }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,26 +19,16 @@ pub(super) async fn df_command(
|
|||
) -> Result<()> {
|
||||
let ctx = CommandContext::for_connection(&args.connection, printer, cli.clone(), cli_layer)?;
|
||||
let server = ctx.server().await?;
|
||||
let output = server
|
||||
.send_api(|client| async move {
|
||||
client
|
||||
.get_system_disk_usage()
|
||||
.verbose(args.verbose)
|
||||
.send()
|
||||
.await
|
||||
})
|
||||
.await?
|
||||
.into_inner();
|
||||
|
||||
let json = cli.output.format == OutputFormat::Json;
|
||||
let storage_dir = if json {
|
||||
None
|
||||
|
||||
let (output, storage_dir) = if json {
|
||||
(server.get_system_disk_usage(args.verbose).await?, None)
|
||||
} else {
|
||||
server
|
||||
.send_api(|client| async move { client.get_system_info().send().await })
|
||||
.await?
|
||||
.into_inner()
|
||||
.storage_dir
|
||||
let (output, info) = tokio::try_join!(
|
||||
server.get_system_disk_usage(args.verbose),
|
||||
server.get_system_info(),
|
||||
)?;
|
||||
(output, info.storage_dir)
|
||||
};
|
||||
|
||||
df_from(&output, storage_dir.as_deref(), json)
|
||||
|
|
|
|||
|
|
@ -16,18 +16,7 @@ pub(super) async fn events_command(
|
|||
) -> Result<()> {
|
||||
let ctx = CommandContext::for_connection(&args.connection, printer, cli.clone(), cli_layer)?;
|
||||
let server = ctx.server().await?;
|
||||
|
||||
let run_ids = args.run_ids.join(",");
|
||||
let response = server
|
||||
.send_api(|client| async move {
|
||||
let mut request = client.attach_events();
|
||||
if !run_ids.is_empty() {
|
||||
request = request.run_id(run_ids.clone());
|
||||
}
|
||||
request.send().await
|
||||
})
|
||||
.await?;
|
||||
let mut stream = response.into_inner();
|
||||
let mut stream = server.attach_events(&args.run_ids).await?;
|
||||
let mut pending = Vec::new();
|
||||
|
||||
let json = cli.output.format == OutputFormat::Json;
|
||||
|
|
|
|||
|
|
@ -15,10 +15,7 @@ pub(super) async fn info_command(
|
|||
) -> Result<()> {
|
||||
let ctx = CommandContext::for_connection(&args.connection, printer, cli.clone(), cli_layer)?;
|
||||
let server = ctx.server().await?;
|
||||
let response = server
|
||||
.send_api(|client| async move { client.get_system_info().send().await })
|
||||
.await?
|
||||
.into_inner();
|
||||
let response = server.get_system_info().await?;
|
||||
|
||||
if cli.output.format == OutputFormat::Json {
|
||||
print_json_pretty(&response)?;
|
||||
|
|
|
|||
|
|
@ -20,22 +20,15 @@ pub(super) async fn prune_command(
|
|||
let ctx = CommandContext::for_connection(&args.connection, printer, cli.clone(), cli_layer)?;
|
||||
let server = ctx.server().await?;
|
||||
let response = server
|
||||
.send_api(|client| async move {
|
||||
client
|
||||
.prune_runs()
|
||||
.body(types::PruneRunsRequest {
|
||||
before: args.filter.before.clone(),
|
||||
dry_run: !args.yes,
|
||||
labels: parse_label_filters(&args.filter.label),
|
||||
older_than: args.older_than.map(format_duration),
|
||||
orphans: args.filter.orphans,
|
||||
workflow: args.filter.workflow.clone(),
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
.prune_runs(types::PruneRunsRequest {
|
||||
before: args.filter.before.clone(),
|
||||
dry_run: !args.yes,
|
||||
labels: parse_label_filters(&args.filter.label),
|
||||
older_than: args.older_than.map(format_duration),
|
||||
orphans: args.filter.orphans,
|
||||
workflow: args.filter.workflow.clone(),
|
||||
})
|
||||
.await?
|
||||
.into_inner();
|
||||
.await?;
|
||||
prune_from(&response, cli.output.format == OutputFormat::Json, printer)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,23 +27,17 @@ pub(crate) async fn version_command(
|
|||
let server_target = user_config::resolve_server_target(&args.target, ctx.machine_settings())?;
|
||||
let server_address = format_server_target(&server_target);
|
||||
let server_info = match ctx.server().await {
|
||||
Ok(server) => match server
|
||||
.send_api(|client| async move { client.get_system_info().send().await })
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let response = response.into_inner();
|
||||
ServerVersionInfo::Success {
|
||||
address: server_address,
|
||||
version: response.version,
|
||||
git_sha: response.git_sha,
|
||||
build_date: response.build_date,
|
||||
profile: response.profile,
|
||||
os: response.os,
|
||||
arch: response.arch,
|
||||
uptime_secs: response.uptime_secs,
|
||||
}
|
||||
}
|
||||
Ok(server) => match server.get_system_info().await {
|
||||
Ok(response) => ServerVersionInfo::Success {
|
||||
address: server_address,
|
||||
version: response.version,
|
||||
git_sha: response.git_sha,
|
||||
build_date: response.build_date,
|
||||
profile: response.profile,
|
||||
os: response.os,
|
||||
arch: response.arch,
|
||||
uptime_secs: response.uptime_secs,
|
||||
},
|
||||
Err(err) => ServerVersionInfo::Error {
|
||||
address: server_address,
|
||||
error: err.to_string(),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use fabro_api::types;
|
|||
use fabro_config::Storage;
|
||||
use fabro_http::header::{AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE};
|
||||
use fabro_http::multipart::{Form, Part};
|
||||
use fabro_model::Model;
|
||||
use fabro_server::bind::Bind;
|
||||
use fabro_store::{EventEnvelope, RunSummary, StageId};
|
||||
use fabro_types::settings::SettingsLayer;
|
||||
|
|
@ -40,9 +41,11 @@ pub(crate) struct ServerStoreClient {
|
|||
refresh_lock: Arc<Mutex<()>>,
|
||||
}
|
||||
|
||||
pub(crate) type Client = ServerStoreClient;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ClientBundle {
|
||||
client: fabro_api::Client,
|
||||
client: fabro_api::ApiClient,
|
||||
http_client: fabro_http::HttpClient,
|
||||
bearer_token: Option<String>,
|
||||
}
|
||||
|
|
@ -153,7 +156,7 @@ fn client_bundle(
|
|||
http_client: fabro_http::HttpClient,
|
||||
bearer_token: Option<String>,
|
||||
) -> ClientBundle {
|
||||
let client = fabro_api::Client::new_with_client(base_url, http_client.clone());
|
||||
let client = fabro_api::ApiClient::new_with_client(base_url, http_client.clone());
|
||||
ClientBundle {
|
||||
client,
|
||||
http_client,
|
||||
|
|
@ -175,7 +178,6 @@ fn refreshable_oauth(
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) async fn connect_server(storage_dir: &Path) -> Result<ServerStoreClient> {
|
||||
connect_api_client_bundle(storage_dir).await
|
||||
}
|
||||
|
|
@ -256,7 +258,11 @@ async fn connect_api_client_bundle(storage_dir: &Path) -> Result<ServerStoreClie
|
|||
connect_local_api_client_bundle(storage_dir, &user_config::active_settings_path(None)).await
|
||||
}
|
||||
|
||||
pub(crate) async fn connect_api_client(storage_dir: &Path) -> Result<fabro_api::Client> {
|
||||
#[allow(
|
||||
dead_code,
|
||||
reason = "Retained for pending storage-backed internal callers and referenced in existing design docs."
|
||||
)]
|
||||
pub(crate) async fn connect_api_client(storage_dir: &Path) -> Result<fabro_api::ApiClient> {
|
||||
connect_api_client_bundle(storage_dir)
|
||||
.await
|
||||
.map(|client| client.client_bundle().client)
|
||||
|
|
@ -576,7 +582,7 @@ impl ServerStoreClient {
|
|||
request: F,
|
||||
) -> Result<progenitor_client::ResponseValue<T>>
|
||||
where
|
||||
F: FnOnce(fabro_api::Client) -> Fut + Clone,
|
||||
F: FnOnce(fabro_api::ApiClient) -> Fut + Clone,
|
||||
Fut: std::future::Future<
|
||||
Output = std::result::Result<
|
||||
progenitor_client::ResponseValue<T>,
|
||||
|
|
@ -833,6 +839,165 @@ impl ServerStoreClient {
|
|||
.map_err(|err| anyhow!("invalid run ID from server: {err}"))
|
||||
}
|
||||
|
||||
pub(crate) async fn list_secrets(&self) -> Result<Vec<types::SecretMetadata>> {
|
||||
let response = self
|
||||
.send_api(|client| async move { client.list_secrets().send().await })
|
||||
.await?;
|
||||
Ok(response.into_inner().data)
|
||||
}
|
||||
|
||||
pub(crate) async fn create_secret(
|
||||
&self,
|
||||
body: types::CreateSecretRequest,
|
||||
) -> Result<types::SecretMetadata> {
|
||||
let response = self
|
||||
.send_api(
|
||||
|client| async move { client.create_secret().body(body.clone()).send().await },
|
||||
)
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_secret_by_name(&self, name: &str) -> Result<()> {
|
||||
self.send_api(|client| async move {
|
||||
client
|
||||
.delete_secret_by_name()
|
||||
.body(types::DeleteSecretRequest {
|
||||
name: name.to_string(),
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn list_models(
|
||||
&self,
|
||||
provider: Option<&str>,
|
||||
query: Option<&str>,
|
||||
) -> Result<Vec<Model>> {
|
||||
let mut offset = 0u64;
|
||||
let mut models = Vec::new();
|
||||
|
||||
loop {
|
||||
let response = self
|
||||
.send_api(|client| async move {
|
||||
let mut request = client.list_models().page_limit(100u64).page_offset(offset);
|
||||
if let Some(provider) = provider {
|
||||
request = request.provider(provider.to_string());
|
||||
}
|
||||
if let Some(query) = query {
|
||||
request = request.query(query.to_string());
|
||||
}
|
||||
request.send().await
|
||||
})
|
||||
.await?;
|
||||
let parsed = response.into_inner();
|
||||
let count = parsed.data.len() as u64;
|
||||
models.extend(convert_type::<_, Vec<Model>>(parsed.data)?);
|
||||
if !parsed.meta.has_more {
|
||||
break;
|
||||
}
|
||||
offset += count;
|
||||
}
|
||||
|
||||
Ok(models)
|
||||
}
|
||||
|
||||
pub(crate) async fn test_model(
|
||||
&self,
|
||||
id: &str,
|
||||
mode: Option<types::ModelTestMode>,
|
||||
) -> Result<types::ModelTestResult> {
|
||||
let response = self
|
||||
.send_api(|client| async move {
|
||||
let mut request = client.test_model().id(id.to_string());
|
||||
if let Some(mode) = mode {
|
||||
request = request.mode(mode);
|
||||
}
|
||||
request.send().await
|
||||
})
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn attach_events(
|
||||
&self,
|
||||
run_ids: &[String],
|
||||
) -> Result<progenitor_client::ByteStream> {
|
||||
let response = self
|
||||
.send_api(|client| async move {
|
||||
let mut request = client.attach_events();
|
||||
if !run_ids.is_empty() {
|
||||
request = request.run_id(run_ids.join(","));
|
||||
}
|
||||
request.send().await
|
||||
})
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_system_info(&self) -> Result<types::SystemInfoResponse> {
|
||||
let response = self
|
||||
.send_api(|client| async move { client.get_system_info().send().await })
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_system_disk_usage(
|
||||
&self,
|
||||
verbose: bool,
|
||||
) -> Result<types::DiskUsageResponse> {
|
||||
let response = self
|
||||
.send_api(|client| async move {
|
||||
client.get_system_disk_usage().verbose(verbose).send().await
|
||||
})
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_runs(
|
||||
&self,
|
||||
body: types::PruneRunsRequest,
|
||||
) -> Result<types::PruneRunsResponse> {
|
||||
let response = self
|
||||
.send_api(|client| async move { client.prune_runs().body(body.clone()).send().await })
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_health(&self) -> Result<()> {
|
||||
self.send_api(|client| async move { client.get_health().send().await })
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn run_diagnostics(&self) -> Result<types::DiagnosticsReport> {
|
||||
let response = self
|
||||
.send_api(|client| async move { client.run_diagnostics().send().await })
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_github_repo(
|
||||
&self,
|
||||
owner: &str,
|
||||
name: &str,
|
||||
) -> Result<types::RepoCheckResponse> {
|
||||
let response = self
|
||||
.send_api(|client| async move {
|
||||
client
|
||||
.get_github_repo()
|
||||
.owner(owner.to_string())
|
||||
.name(name.to_string())
|
||||
.send()
|
||||
.await
|
||||
})
|
||||
.await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub(crate) async fn run_preflight(
|
||||
&self,
|
||||
manifest: types::RunManifest,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use chrono::{DateTime, Utc};
|
|||
use fabro_store::RunSummary;
|
||||
use fabro_types::{RunId, RunStatus, StatusReason};
|
||||
|
||||
use crate::server_client::ServerStoreClient;
|
||||
use crate::server_client::Client;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ServerRunSummaryInfo {
|
||||
|
|
@ -75,12 +75,12 @@ impl ServerRunSummaryInfo {
|
|||
}
|
||||
|
||||
pub(crate) struct ServerSummaryLookup {
|
||||
client: Arc<ServerStoreClient>,
|
||||
client: Arc<Client>,
|
||||
runs: Vec<ServerRunSummaryInfo>,
|
||||
}
|
||||
|
||||
impl ServerSummaryLookup {
|
||||
pub(crate) async fn from_client(client: Arc<ServerStoreClient>) -> Result<Self> {
|
||||
pub(crate) async fn from_client(client: Arc<Client>) -> Result<Self> {
|
||||
let summaries = client.list_store_runs().await?;
|
||||
let mut runs = summaries
|
||||
.into_iter()
|
||||
|
|
@ -94,7 +94,7 @@ impl ServerSummaryLookup {
|
|||
Ok(Self { client, runs })
|
||||
}
|
||||
|
||||
pub(crate) fn client(&self) -> &ServerStoreClient {
|
||||
pub(crate) fn client(&self) -> &Client {
|
||||
self.client.as_ref()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue