From b4788b72d75611d4ae8096d954f9c81a87db3166 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 19 May 2022 14:02:51 -0700 Subject: [PATCH 1/6] add a few common used on_event handlers --- src/imp.rs | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/imp.rs b/src/imp.rs index 8860191..87c430e 100644 --- a/src/imp.rs +++ b/src/imp.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, FixedOffset}; use crate::event::Event; use libcwtch::structs::*; use libcwtch::CwtchLib; @@ -9,7 +10,15 @@ use crate::behaviour::NewContactPolicy::AllowList; /// Trait to be used by implementors of imp bots to supply their custom event handling /// the handle function is called after the default imp automatic event handling has run on each new event pub trait EventHandler { - fn handle(&mut self, cwtch: &dyn libcwtch::CwtchLib, profile: Option<&Profile>, event: Event); + #[allow(unused_variables)] + fn handle(&mut self, cwtch: &dyn libcwtch::CwtchLib, profile: Option<&Profile>, event: Event) {} + + #[allow(unused_variables)] + fn on_contact_online(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: i32) {} + #[allow(unused_variables)] + fn on_new_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: i32) {} + #[allow(unused_variables)] + fn on_new_message_from_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, conversation_id: i32, handle: String, timestamp_received: DateTime, message: String) {} } /// Cwtch bot @@ -56,7 +65,7 @@ impl Imp { let event: CwtchEvent = serde_json::from_str(&event_str).expect("Error parsing Cwtch event"); let event = Event::from(&event); match &event { - Event::CwtchStarted { data } => { + Event::CwtchStarted {data} => { println!("event CwtchStarted!"); initialized = true; @@ -159,9 +168,10 @@ impl Imp { let acl: ACL = serde_json::from_str(&data["accessControlList"]).expect("Error parsing conversation"); + let conversatio_id: i32 = data["ConversationID"].parse::().unwrap(); let conversation = Conversation { handle: convo_handle.clone(), - identifier: data["ConversationID"].parse::().unwrap(), + identifier: conversatio_id, name: data["nick"].to_string(), status: ConnectionState::new(&data["status"]), blocked: data["blocked"] == "true", @@ -177,11 +187,31 @@ impl Imp { profile .conversations .insert(conversation.identifier, conversation); + handler.on_new_contact(self.cwtch.as_ref(), profile, conversatio_id); + handler.on_contact_online(self.cwtch.as_ref(), profile, conversatio_id); } None => (), }; } - Event::PeerStateChange { data } => {} + Event::PeerStateChange { data } => { + if data["ConnectionState"] == "Authenticated" { + match self.profile.as_ref() { + Some(profile) => { + match profile.find_conversation_id_by_handle(data["RemotePeer"].clone()) { + Some(conversation_id) => handler.on_contact_online(self.cwtch.as_ref(), profile,conversation_id), + None => {} + } + } + None => (), + }; + } + } + Event::NewMessageFromPeer { conversation_id, handle, timestamp_received, message } => { + match self.profile.as_ref() { + Some(profile) => handler.on_new_message_from_contact(self.cwtch.as_ref(), profile, *conversation_id, handle.clone(), *timestamp_received, message.clone()), + None => {}, + } + } Event::ErrUnhandled { name, data } => eprintln!("unhandled event: {}!", name), _ => (), }; From f9a9a6bad299c64e85887d9dcc7d17cab8cc7eeb Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 19 May 2022 16:11:49 -0700 Subject: [PATCH 2/6] typo --- src/imp.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/imp.rs b/src/imp.rs index 87c430e..ace6f4a 100644 --- a/src/imp.rs +++ b/src/imp.rs @@ -168,10 +168,10 @@ impl Imp { let acl: ACL = serde_json::from_str(&data["accessControlList"]).expect("Error parsing conversation"); - let conversatio_id: i32 = data["ConversationID"].parse::().unwrap(); + let conversation_id: i32 = data["ConversationID"].parse::().unwrap(); let conversation = Conversation { handle: convo_handle.clone(), - identifier: conversatio_id, + identifier: conversation_id, name: data["nick"].to_string(), status: ConnectionState::new(&data["status"]), blocked: data["blocked"] == "true", @@ -187,8 +187,8 @@ impl Imp { profile .conversations .insert(conversation.identifier, conversation); - handler.on_new_contact(self.cwtch.as_ref(), profile, conversatio_id); - handler.on_contact_online(self.cwtch.as_ref(), profile, conversatio_id); + handler.on_new_contact(self.cwtch.as_ref(), profile, conversation_id); + handler.on_contact_online(self.cwtch.as_ref(), profile, conversation_id); } None => (), }; From ee502998d855dfefc42c7f6ef03ee1394d7db38a Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 21 Jul 2022 01:04:47 -0700 Subject: [PATCH 3/6] migrate to new libcwtch-rs --- Cargo.toml | 2 +- src/behaviour.rs | 7 +-- src/event.rs | 72 ------------------------- src/imp.rs | 134 +++++++++++++++++++++-------------------------- src/lib.rs | 1 - 5 files changed, 64 insertions(+), 152 deletions(-) delete mode 100644 src/event.rs diff --git a/Cargo.toml b/Cargo.toml index 6d26f1e..a1bfc0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libcwtch = "0.3.2" +libcwtch = { path="./../libcwtch-rs"} #"0.3.2" serde_json = "1.0" chrono = "0.4.19" \ No newline at end of file diff --git a/src/behaviour.rs b/src/behaviour.rs index fdadd17..06fd1df 100644 --- a/src/behaviour.rs +++ b/src/behaviour.rs @@ -1,16 +1,17 @@ +use libcwtch::event::{ContactIdentity, GroupID}; /// defines a locked list of allowed peers and groups the bot may communicate with /// others will be blocked, and peers listed here will be peered with actively pub struct AllowListMembers { /// list of peers to allow by handle - pub peers: Vec, + pub peers: Vec, /// list of groups to join and listen for peers in peer list from - pub groups: Vec, + pub groups: Vec, } impl AllowListMembers { /// constructs a new AllowListMembers struct - pub fn new(peers: Vec, groups: Vec) -> Self { + pub fn new(peers: Vec, groups: Vec) -> Self { AllowListMembers {peers: peers, groups: groups} } } diff --git a/src/event.rs b/src/event.rs deleted file mode 100644 index 8487588..0000000 --- a/src/event.rs +++ /dev/null @@ -1,72 +0,0 @@ -use chrono::{DateTime, FixedOffset}; -use libcwtch::structs::CwtchEvent; -use std::collections::HashMap; - -#[derive(Debug)] -pub enum Event { - CwtchStarted { - data: HashMap, - }, - NewPeer { - data: HashMap, - }, - - NewMessageFromPeer { - conversation_id: i32, - handle: String, - timestamp_received: DateTime, - message: String, - }, - AppError { - data: HashMap, - }, - ContactCreated { - data: HashMap, - }, - PeerStateChange { - data: HashMap, - }, - UpdateGlobalSettings { - data: HashMap, - }, - - ErrUnhandled { - name: String, - data: HashMap, - }, -} - -impl From<&CwtchEvent> for Event { - fn from(cwtch_event: &CwtchEvent) -> Self { - match cwtch_event.event_type.as_str() { - "CwtchStarted" => Event::CwtchStarted { - data: cwtch_event.data.clone(), - }, - "NewPeer" => Event::NewPeer { - data: cwtch_event.data.clone(), - }, - "NewMessageFromPeer" => Event::NewMessageFromPeer { - conversation_id: cwtch_event.data["ConversationID"].parse().unwrap_or(-2), - handle: cwtch_event.data["RemotePeer"].clone(), - timestamp_received: DateTime::parse_from_rfc3339(cwtch_event.data["TimestampReceived"].as_str()).unwrap(), - message: cwtch_event.data["Data"].clone(), - }, - "AppError" => Event::AppError { - data: cwtch_event.data.clone(), - }, - "ContactCreated" => Event::ContactCreated { - data: cwtch_event.data.clone(), - }, - "PeerStateChange" => Event::PeerStateChange { - data: cwtch_event.data.clone(), - }, - "UpdateGlobalSettings" => Event::UpdateGlobalSettings { - data: cwtch_event.data.clone(), - }, - x => Event::ErrUnhandled { - name: x.to_string(), - data: cwtch_event.data.clone(), - }, - } - } -} diff --git a/src/imp.rs b/src/imp.rs index ace6f4a..c1887d9 100644 --- a/src/imp.rs +++ b/src/imp.rs @@ -1,7 +1,7 @@ use chrono::{DateTime, FixedOffset}; -use crate::event::Event; use libcwtch::structs::*; use libcwtch::CwtchLib; +use libcwtch::event::{ConversationID, Event}; use serde_json; use crate::behaviour::{Behaviour, NewContactPolicy}; @@ -11,14 +11,14 @@ use crate::behaviour::NewContactPolicy::AllowList; /// the handle function is called after the default imp automatic event handling has run on each new event pub trait EventHandler { #[allow(unused_variables)] - fn handle(&mut self, cwtch: &dyn libcwtch::CwtchLib, profile: Option<&Profile>, event: Event) {} + fn handle(&mut self, cwtch: &dyn libcwtch::CwtchLib, profile: Option<&Profile>, event: &Event) {} #[allow(unused_variables)] - fn on_contact_online(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: i32) {} + fn on_contact_online(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: ConversationID) {} #[allow(unused_variables)] - fn on_new_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: i32) {} + fn on_new_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: ConversationID) {} #[allow(unused_variables)] - fn on_new_message_from_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, conversation_id: i32, handle: String, timestamp_received: DateTime, message: String) {} + fn on_new_message_from_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, conversation_id: ConversationID, handle: String, timestamp_received: DateTime, message: Message) {} } /// Cwtch bot @@ -52,6 +52,7 @@ impl Imp { } /// The main event loop handler for the bot, supply your own customer handler to handle events after the imp's automatic handling has processed the event + #[allow(unused_variables, unused_mut)] pub fn event_loop(&mut self, handler: &mut T) where T: EventHandler, @@ -59,13 +60,10 @@ impl Imp { let mut initialized: bool = false; loop { - let event_str = self.cwtch.get_appbus_event(); - println!("bot: event: {}", event_str); + let event = self.cwtch.get_appbus_event(); - let event: CwtchEvent = serde_json::from_str(&event_str).expect("Error parsing Cwtch event"); - let event = Event::from(&event); match &event { - Event::CwtchStarted {data} => { + Event::CwtchStarted => { println!("event CwtchStarted!"); initialized = true; @@ -77,27 +75,24 @@ impl Imp { Some(_) => (), } } - Event::UpdateGlobalSettings { data } => { - println!("Loading settings froms {}", &data["Data"]); - let mut settings: Settings = match serde_json::from_str(&data["Data"]) { - Ok(s) => s, - Err(e) => panic!("invalid json: {:?}", e), - }; + Event::UpdateGlobalSettings { settings } => { + let mut local_settings = settings.clone(); + println!("Loading settings froms {:?}", local_settings); if self.behaviour.proto_experiments { - settings.ExperimentsEnabled = true; + local_settings.ExperimentsEnabled = true; } if self.behaviour.proto_experiment_fileshare { - settings + local_settings .Experiments .insert(Experiments::FileSharingExperiment.to_key_string(), true); } if self.behaviour.proto_experiment_groups { - settings + local_settings .Experiments .insert(Experiments::GroupExperiment.to_key_string(), true); } - match settings.save(self.cwtch.as_ref()) { + match local_settings.save(self.cwtch.as_ref()) { Ok(_) => (), Err(e) => println!("ERROR: could not save settings: {}", e), }; @@ -105,78 +100,67 @@ impl Imp { match self.profile.as_ref() { Some(profile) => { if let Some(profile_pic_path) = &self.behaviour.profile_pic_path { - self.cwtch.share_file(&profile.handle, -1, profile_pic_path); + self.cwtch.share_file(&profile.profile_id, ConversationID(-1), profile_pic_path); } } None => (), }; - self.settings = Some(settings); + self.settings = Some(local_settings); } - Event::NewPeer { data } => { - println!("\n***** {} at {} *****\n", data["name"], data["Identity"]); + Event::NewPeer { profile_id, tag, created, name, default_picture, picture, online, profile_data} => { + + if let Err(e) = profile_data { + panic!("error parsing profile: {}", e); + } - // process json for profile, conversations and servers...else { - let profile = match Profile::new( - &data["Identity"], - &data["name"], - &data["picture"], - &data["ContactsJson"], - &data["ServerList"], - ) { - Ok(p) => p, - Err(e) => panic!("error parsing profile: {}", e), - }; // Share profile image match self.settings.as_ref() { Some(_settings) => { - self.cwtch.share_file(&profile.handle, -1, "build_bot.png"); + self.cwtch.share_file(&profile_id, ConversationID(-1), "build_bot.png"); } None => (), }; self.cwtch.set_profile_attribute( - &profile.handle, + &profile_id, "profile.name", &self.behaviour.profile_name, ); - for (_id, conversation) in &profile.conversations { - self.process_contact(conversation.identifier); - } + if let Ok(ok_profile) = profile_data { + for (_id, conversation) in &ok_profile.conversations { + self.process_contact(conversation.identifier); + } - // Allow list should add all people in the list - if let AllowList(allow_list) = &self.behaviour.new_contant_policy { - for handle in &allow_list.peers { - if let None = profile.find_conversation_id_by_handle(handle.clone()) { - self.cwtch.import_bundle(&profile.handle.clone(), &handle.clone()); + // Allow list should add all people in the list + if let AllowList(allow_list) = &self.behaviour.new_contant_policy { + for contact_id in &allow_list.peers { + if let None = ok_profile.find_conversation_id_by_handle(contact_id.clone()) { + self.cwtch.import_bundle(&profile_id, contact_id.clone().as_str()); + } } } - } - self.profile = Some(profile); + + self.profile = Some(ok_profile.clone()); + } } - Event::AppError { data } => { - if initialized && data.contains_key("Error") && data["Error"] == "Loaded 0 profiles" { + Event::AppError { error } => { + if initialized && error == "Loaded 0 profiles" { self.cwtch .create_profile(&self.behaviour.profile_name, &self.password); } } - Event::ContactCreated { data } => { - println!("Contact Created"); - let convo_handle = data["RemotePeer"].to_string(); - - let acl: ACL = serde_json::from_str(&data["accessControlList"]).expect("Error parsing conversation"); - - let conversation_id: i32 = data["ConversationID"].parse::().unwrap(); + Event::ContactCreated {profile_id, conversation_id, contact_id, nick, status, unread, picture, default_picture, num_messages, accepted, access_control_list, blocked, loading, last_msg_time, .. } => { let conversation = Conversation { - handle: convo_handle.clone(), - identifier: conversation_id, - name: data["nick"].to_string(), - status: ConnectionState::new(&data["status"]), - blocked: data["blocked"] == "true", - accepted: data["accepted"] == "true", - access_control_list: acl, + contact_id: contact_id.clone(), + identifier: conversation_id.clone(), + name: nick.clone(), + status: status.clone(), + blocked: blocked.clone(), + accepted: accepted.clone(), + access_control_list: access_control_list.clone(), is_group: false, // by definition }; @@ -187,17 +171,17 @@ impl Imp { profile .conversations .insert(conversation.identifier, conversation); - handler.on_new_contact(self.cwtch.as_ref(), profile, conversation_id); - handler.on_contact_online(self.cwtch.as_ref(), profile, conversation_id); + handler.on_new_contact(self.cwtch.as_ref(), profile, conversation_id.clone()); + handler.on_contact_online(self.cwtch.as_ref(), profile, conversation_id.clone()); } None => (), }; } - Event::PeerStateChange { data } => { - if data["ConnectionState"] == "Authenticated" { + Event::PeerStateChange { profile_id, contact_id, connection_state } => { + if *connection_state == ConnectionState::Authenticated { match self.profile.as_ref() { Some(profile) => { - match profile.find_conversation_id_by_handle(data["RemotePeer"].clone()) { + match profile.find_conversation_id_by_handle(contact_id.clone()) { Some(conversation_id) => handler.on_contact_online(self.cwtch.as_ref(), profile,conversation_id), None => {} } @@ -206,9 +190,9 @@ impl Imp { }; } } - Event::NewMessageFromPeer { conversation_id, handle, timestamp_received, message } => { + Event::NewMessageFromPeer {profile_id, conversation_id,contact_id, nick, timestamp_received, message, notification, picture } => { match self.profile.as_ref() { - Some(profile) => handler.on_new_message_from_contact(self.cwtch.as_ref(), profile, *conversation_id, handle.clone(), *timestamp_received, message.clone()), + Some(profile) => handler.on_new_message_from_contact(self.cwtch.as_ref(), profile, conversation_id.clone(), nick.clone(), timestamp_received.clone(), message.clone()), None => {}, } } @@ -216,26 +200,26 @@ impl Imp { _ => (), }; - handler.handle(self.cwtch.as_ref(), self.profile.as_ref(), event); + handler.handle(self.cwtch.as_ref(), self.profile.as_ref(), &event); } } - fn process_contact(&self, conversation_id: i32) { + fn process_contact(&self, conversation_id: ConversationID) { match &self.profile { Some(profile) => { - let profile_handle = profile.handle.clone(); + let profile_handle = profile.profile_id.clone(); match &self.behaviour.new_contant_policy { NewContactPolicy::Accept => { self.cwtch - .accept_conversation(&profile_handle.clone(), conversation_id); + .accept_conversation(&profile.profile_id, conversation_id); } NewContactPolicy::Block => self.cwtch.block_contact(&profile_handle.clone(), conversation_id), NewContactPolicy::AllowList(allow_list) => { match profile.conversations.get(&conversation_id) { Some(conversation) => { - if allow_list.peers.contains(&conversation.handle) { + if allow_list.peers.contains(&conversation.contact_id) { self.cwtch .accept_conversation(&profile_handle.clone(), conversation_id); } else { diff --git a/src/lib.rs b/src/lib.rs index 0c2d3b6..994c8d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,2 @@ -pub mod event; pub mod imp; pub mod behaviour; From 1dc66709dd8756f72fd4c6d428a4a63b74ec739f Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 21 Jul 2022 16:09:20 -0700 Subject: [PATCH 4/6] version update --- Cargo.toml | 4 ++-- README.md | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a1bfc0d..7fefeb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "imp" -version = "0.1.0" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libcwtch = { path="./../libcwtch-rs"} #"0.3.2" +libcwtch = "0.4.0" serde_json = "1.0" chrono = "0.4.19" \ No newline at end of file diff --git a/README.md b/README.md index 6b18a6c..485c292 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,12 @@ It is in the very early prototype stage with one prototype use in the Cwtch [upd Start with creating a `Behaviour` struct and populating it with your desired set of bot behaviours, then `imp::spawn` your bot with the behaviour. -Define a struct fulfilling the `imp::EventHandler` trait with all your custom event handling code. +To handle Cwtch events you can either +- Define a struct fulfilling the `imp::EventHandler::event_loop` function which has the capacity to support all the events libCwtch can emit +- Override specific `on_x_event` functions in `imp::EventHandler` such as `on_new_message_from_contact` + - This is newer and more will be defined in later versions -Finally, run the imp `my_imp.event_loop(Box::new(custom_event_handler));` +Finally, run the imp `my_imp.event_loop::(update_bot.borrow_mut());` ## Examples From 63efec6655451e6b4fab42144f8b3d06d372929b Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 21 Jul 2022 16:57:06 -0700 Subject: [PATCH 5/6] package name change from imp to cwtch-imp since imp crate taken --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7fefeb3..49e5197 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "imp" +name = "cwtch-imp" version = "0.2.0" edition = "2021" From df81c9101b2fd8f41b2f3b5c6810fe925d120312 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 21 Jul 2022 17:04:57 -0700 Subject: [PATCH 6/6] drop serde dep --- Cargo.toml | 1 - src/imp.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 49e5197..83cd98a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,4 @@ edition = "2021" [dependencies] libcwtch = "0.4.0" -serde_json = "1.0" chrono = "0.4.19" \ No newline at end of file diff --git a/src/imp.rs b/src/imp.rs index c1887d9..4fa6d04 100644 --- a/src/imp.rs +++ b/src/imp.rs @@ -3,7 +3,6 @@ use libcwtch::structs::*; use libcwtch::CwtchLib; use libcwtch::event::{ConversationID, Event}; -use serde_json; use crate::behaviour::{Behaviour, NewContactPolicy}; use crate::behaviour::NewContactPolicy::AllowList;