1use anyhow::Context;
2use comfy_table::{Table, presets::UTF8_FULL};
3use core_types::{EventKind, ProfileId, SecurityLevel, TrustProfileName};
4use owo_colors::OwoColorize;
5
6use crate::ipc::{connect, rpc};
7
8pub(crate) async fn cmd_profile_list() -> anyhow::Result<()> {
9 let client = connect().await?;
10
11 match rpc(&client, EventKind::ProfileList, SecurityLevel::Internal).await? {
12 EventKind::ProfileListResponse { profiles } => {
13 if profiles.is_empty() {
14 println!("{}", "No profiles configured.".dimmed());
15 return Ok(());
16 }
17
18 let mut table = Table::new();
19 table.load_preset(UTF8_FULL);
20 table.set_header(vec!["Name", "Active", "Default"]);
21
22 for p in &profiles {
23 let active = if p.is_active {
24 "yes".green().to_string()
25 } else {
26 "no".dimmed().to_string()
27 };
28 let default = if p.is_default {
29 "yes".green().to_string()
30 } else {
31 "".to_string()
32 };
33 let name_str = p.name.to_string();
34 table.add_row(vec![&name_str, &active, &default]);
35 }
36
37 println!("{table}");
38 }
39 other => anyhow::bail!("unexpected response: {other:?}"),
40 }
41
42 Ok(())
43}
44
45pub(crate) async fn cmd_profile_activate(name: &str) -> anyhow::Result<()> {
46 let client = connect().await?;
47 let profile_name = TrustProfileName::try_from(name).map_err(|e| anyhow::anyhow!("{e}"))?;
48
49 let event = EventKind::ProfileActivate {
50 target: ProfileId::new(),
51 profile_name,
52 };
53
54 match rpc(&client, event, SecurityLevel::Internal).await? {
55 EventKind::ProfileActivateResponse { success: true } => {
56 println!("Profile '{}' activated.", name.green());
57 }
58 EventKind::ProfileActivateResponse { success: false } => {
59 anyhow::bail!("failed to activate profile '{name}'");
60 }
61 other => anyhow::bail!("unexpected response: {other:?}"),
62 }
63
64 Ok(())
65}
66
67pub(crate) async fn cmd_profile_deactivate(name: &str) -> anyhow::Result<()> {
68 let client = connect().await?;
69 let profile_name = TrustProfileName::try_from(name).map_err(|e| anyhow::anyhow!("{e}"))?;
70
71 let event = EventKind::ProfileDeactivate {
72 target: ProfileId::new(),
73 profile_name,
74 };
75
76 match rpc(&client, event, SecurityLevel::Internal).await? {
77 EventKind::ProfileDeactivateResponse { success: true } => {
78 println!("Profile '{}' deactivated.", name.green());
79 }
80 EventKind::ProfileDeactivateResponse { success: false } => {
81 anyhow::bail!("failed to deactivate profile '{name}' — not active?");
82 }
83 other => anyhow::bail!("unexpected response: {other:?}"),
84 }
85
86 Ok(())
87}
88
89pub(crate) async fn cmd_profile_default(name: &str) -> anyhow::Result<()> {
90 let client = connect().await?;
91 let profile_name = TrustProfileName::try_from(name).map_err(|e| anyhow::anyhow!("{e}"))?;
92
93 let event = EventKind::SetDefaultProfile { profile_name };
94
95 match rpc(&client, event, SecurityLevel::Internal).await? {
96 EventKind::SetDefaultProfileResponse { success: true } => {
97 println!("Default profile set to '{}'.", name.green());
98 }
99 EventKind::SetDefaultProfileResponse { success: false } => {
100 anyhow::bail!("failed to set default profile to '{name}'");
101 }
102 other => anyhow::bail!("unexpected response: {other:?}"),
103 }
104
105 Ok(())
106}
107
108pub(crate) fn cmd_profile_show(name: &str) -> anyhow::Result<()> {
109 let config = core_config::load_config(None).context("failed to load config")?;
110
111 let profile = config
112 .profiles
113 .get(name)
114 .ok_or_else(|| anyhow::anyhow!("profile '{name}' not found in config"))?;
115
116 let toml_str = toml::to_string_pretty(profile).context("failed to serialize profile config")?;
117
118 println!("Profile: {}", name.bold());
119 if name == config.global.default_profile.as_ref() {
120 println!("(default profile)");
121 }
122 println!();
123 println!("{toml_str}");
124
125 Ok(())
126}