@ -1,15 +1,23 @@
use crate ::event ::Event ;
use chrono ::{ DateTime , FixedOffset } ;
use libcwtch ::structs ::* ;
use libcwtch ::CwtchLib ;
use libcwtch ::event ::{ ConversationID , Event } ;
use serde_json ;
use crate ::behaviour ::{ Behaviour , NewContactPolicy } ;
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 : ConversationID ) { }
#[ allow(unused_variables) ]
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 : ConversationID , handle : String , timestamp_received : DateTime < FixedOffset > , message : Message ) { }
}
/// Cwtch bot
@ -43,6 +51,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 < T > ( & mut self , handler : & mut T )
where
T : EventHandler ,
@ -50,13 +59,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 ;
@ -68,27 +74,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 ) ,
} ;
@ -96,77 +99,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" ] ) ;
// 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 ) ,
} ;
Event ::NewPeer { profile_id , tag , created , name , default_picture , picture , online , profile_data } = > {
if let Err ( e ) = profile_data {
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_k ey( "E rror") & & 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" ) ;
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 : data[ "ConversationID" ] . parse ::< i32 > ( ) . unwrap ( ) ,
name : data[ "nick" ] . to_string ( ) ,
status : ConnectionState::new ( & data [ "status" ] ) ,
blocked : data[ "blocked" ] = = "true" ,
accepted : data[ "accepted" ] = = "true" ,
access_control_list : ac l,
contact_id : contact_id . clone ( ) ,
identifier : conversation_id . clone ( ) ,
name : nick . clone ( ) ,
status : status . clone ( ) ,
blocked : blocked. clone ( ) ,
accepted : accepted. clone ( ) ,
access_control_list : ac cess_contro l_list. clone ( ) ,
is_group : false , // by definition
} ;
@ -177,35 +170,55 @@ impl Imp {
profile
. conversations
. insert ( conversation . identifier , conversation ) ;
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 } = > { }
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 ( contact_id . clone ( ) ) {
Some ( conversation_id ) = > handler . on_contact_online ( self . cwtch . as_ref ( ) , profile , conversation_id ) ,
None = > { }
}
}
None = > ( ) ,
} ;
}
}
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 . clone ( ) , nick . clone ( ) , timestamp_received . clone ( ) , message . clone ( ) ) ,
None = > { } ,
}
}
Event ::ErrUnhandled { name , data } = > eprintln! ( "unhandled event: {}!" , name ) ,
_ = > ( ) ,
} ;
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 {