diff --git a/src/structs.rs b/src/structs.rs index 6634370..5f48f02 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,4 +1,5 @@ use crate::structs::ConnectionState::Disconnected; +use crate::CwtchLib; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DefaultOnError}; use std::collections::HashMap; @@ -28,6 +29,22 @@ impl Default for ConnectionState { } } +impl ConnectionState { + /// Creates a ConnectionState from a string sent from libcwtch-go + pub fn new(name: &str) -> Self { + match name { + "Disconnected" => ConnectionState::Disconnected, + "Connecting" => ConnectionState::Connecting, + "Connected" => ConnectionState::Connected, + "Authenticated" => ConnectionState::Authenticated, + "Synced" => ConnectionState::Synced, + "Failed" => ConnectionState::Failed, + "Killed" => ConnectionState::Killed, + _ => ConnectionState::Disconnected, + } + } +} + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "lowercase")] /// Defines the various authorization modes a contact can be in @@ -56,19 +73,25 @@ pub struct CwtchEvent { #[serde_as] #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] -/// Struct to serialize/deserialize contacts coming from libcwtch-go -pub struct Contact { - /// onion address / id of the contact - pub onion: String, - /// display name of the contact, as determined in libcwtch-go from name specified by contact +/// Struct to serialize/deserialize conversations coming from libcwtch-go +pub struct Conversation { + /// onion address / id of the conversation + #[serde(alias = "onion")] + pub handle: String, + /// unique identifier of the contact/conversation to be used in API access + pub identifier: i32, + /// display name of the conversation, as determined in libcwtch-go from name specified by contact pub name: String, #[serde_as(deserialize_as = "DefaultOnError")] - // cwtch loads profile/contacts from storage and leaves status blank, it's filled in "soon" by events... + // cwtch loads profile/conversation from storage and leaves status blank, it's filled in "soon" by events... /// contact connection status pub status: ConnectionState, - /// contact authorization state as set by profile - pub authorization: ContactAuthorization, - /// is this contact a group? if so "onion" will be a group ID + /// has the conversation been manually accpted + pub accepted: bool, + /// has the conversation been manually blocked + pub blocked: bool, + /// is this conversation a group? if so "onion" will be a group ID + /// FIXME: deprecate pub is_group: bool, //attr: HashMap, } @@ -93,14 +116,14 @@ pub struct Profile { pub image_path: String, /// all profile attributes pub attr: HashMap, - /// map of contacts [ onion => contact ] - pub contacts: HashMap, + /// map of conversation [ onion => conversation ] + pub conversations: HashMap, /// map of servers [ onion => server ] pub servers: HashMap, } #[derive(Debug, Serialize, Deserialize)] -/// Struct to serialize/deserialize messages sent over Cwtch between profiles / contacts +/// Struct to serialize/deserialize messages sent over Cwtch between profiles / conversation pub struct Message { /// overlay id that the message is targeting as defined in cwtch/model/overlay.go /// [ OverlayChat = 1, OverlayInviteContact = 100, OverlayInviteGroup = 101, OverlayFileSharing = 200 ] @@ -109,18 +132,115 @@ pub struct Message { pub d: String, } +#[derive(Debug, Serialize, Deserialize)] +/// Settings as defined in libcwtch-go/utils/settings.go and should be populated by handeling the UpdateGlobalSettings event emited during cwtch.start() +#[allow(non_snake_case)] +pub struct Settings { + /// locale for the UI to use + pub Locale: String, + /// theme of the UI + pub Theme: String, + /// Theme mode of the ui, light or dark + pub ThemeMode: String, + /// previous pid of the run, managed by libcwtch-go + pub PreviousPid: i64, + /// controls if subsequent experiments are enabled at all + pub ExperimentsEnabled: bool, + /// map of experiment names and their enabled status + pub Experiments: HashMap, + /// Should the app block unknown conversations + pub BlockUnknownConnections: bool, + // Notification policy of a UI app + //pub NotificationPolicy: String, //Todo: NotificationPolicy struct + // Notification content to show for a UI app + //pub NotificationContent: String, + /// Should the UI hide conversation IDs + pub StreamerMode: bool, + /// Unused? + pub StateRootPane: i32, + /// is this the first run + pub FirstTime: bool, + /// UI column mode + pub UIColumnModePortrait: String, + /// UI column mode + pub UIColumnModeLandscape: String, + /// Path to download files to + pub DownloadPath: String, + // Turn on advanced tor config in the UI + //pub AllowAdvancedTorConfig: bool, + // Custom torrc value + //pub CustomTorrc: String, + // Use the value of CustomTorrc with tor + //pub UseCustomTorrc: bool, + // Unused? delete + //pub UseExternalTor: bool, + // Tor socks port, if not default + //pub CustomSocksPort: i32, + // Tor control port if not default + //pub CustomControlPort: i32, + // Use tor cache for faster start + //pub UseTorCache: bool, + // Tor config dir + //pub TorCacheDir: String, +} + +/// Enum of experiment types that can be managed in Settings +pub enum Experiments { + /// experiment enabling in app management and running of Cwtch servers + ServersExperiment, + /// experiment enabling use of Cwtch groups + GroupExperiment, + /// experiment enabling filesharing + FileSharingExperiment, + /// experiment enabling auto downloading of image files to Settings::DownloadPath + ImagePreviewsExperiment, +} + +impl Experiments { + /// returns the experiment settings key + pub fn to_key_string(self) -> String { + match self { + Experiments::ServersExperiment => "servers-experiment".to_string(), + Experiments::GroupExperiment => "tapir-groups-experiment".to_string(), + Experiments::FileSharingExperiment => "filesharing".to_string(), + Experiments::ImagePreviewsExperiment => "filesharing-images".to_string(), + } + } +} + +impl Settings { + /// Given a CwtchLib, handles sending an event to it with updated settings represented by this struct for saving + pub fn save(&self, cwtch: &dyn CwtchLib) -> Result<(), String> { + let settings_json = match serde_json::to_string(&self) { + Ok(s) => s, + Err(e) => return Err(e.to_string()), + }; + let save_settings_event: CwtchEvent = CwtchEvent { + event_type: "UpdateGlobalSettings".to_string(), + event_ID: "0".to_string(), + data: HashMap::from([("Data".to_string(), settings_json)]), + }; + let event_json = match serde_json::to_string(&save_settings_event) { + Ok(s) => s, + Err(e) => return Err(e.to_string()), + }; + cwtch.send_app_event(&event_json); + return Ok(()); + } +} + impl Profile { /// Create a new profile populated from supplied data - /// contacts_json as supplied by libcwtch-go, a map of contacts + /// contacts_json as supplied by libcwtch-go, a map of conversations /// server_list as supplied by libcwtch-go, a map of servers pub fn new( identity: &str, name: &str, picture: &str, - contacts_json: &str, + conversations_json: &str, server_list: &str, ) -> Result { - let contacts = match Profile::process_contacts(contacts_json) { + let conversations = match Profile::process_conversations(conversations_json) { Ok(c) => c, Err(e) => return Err(e), }; @@ -133,25 +253,24 @@ impl Profile { nick: name.to_string(), image_path: picture.to_string(), attr: Default::default(), - contacts: contacts, + conversations, servers: servers, }) } - fn process_contacts(constacts_json: &str) -> Result, String> { - let mut contacts: HashMap = HashMap::new(); - if constacts_json == "null" { - return Ok(contacts); + fn process_conversations(conversations_json: &str) -> Result, String> { + let mut conversations: HashMap = HashMap::new(); + if conversations_json == "null" { + return Ok(conversations); } - println!("contacts_json: '{}'", constacts_json); - let contacts_map: Vec = match serde_json::from_str(constacts_json) { + let conversations_map: Vec = match serde_json::from_str(conversations_json) { Ok(cm) => cm, Err(e) => return Err(format!("invalid json: {:?}", e)), }; - for contact in contacts_map { - contacts.insert(contact.onion.clone(), contact); + for conversation in conversations_map { + conversations.insert(conversation.handle.clone(), conversation); } - Ok(contacts) + Ok(conversations) } fn process_servers(servers_json: &str) -> Result, String> {