use chrono::{DateTime, FixedOffset};
use libcwtch::structs::*;
use libcwtch::CwtchLib;
use libcwtch::event::{ContactIdentity, ConversationID, Event};
use libcwtch::structs::MessageType::InviteGroup;
use crate::behaviour::{Behaviour, ContactInteractionPolicy, GroupInteractionPolicy, GroupInvitePolicy, NewContactPolicy};
use crate::behaviour::NewContactPolicy::AllowList;
pub trait EventHandler {
#[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(&mut self, cwtch: &dyn libcwtch::CwtchLib, behaviour: &mut Behaviour, profile: &Profile, conversation_id: ConversationID, handle: String, timestamp_received: DateTime<FixedOffset>, message: MessageWrapper) {}
#[allow(unused_variables)]
fn on_new_message_from_group(&mut self, cwtch: &dyn libcwtch::CwtchLib, behaviour: &mut Behaviour, profile: &Profile, conversation_id: ConversationID, contact: ContactIdentity, timestamp_sent: DateTime<FixedOffset>, message: MessageWrapper) {}
}
pub struct Imp {
cwtch: Box<dyn libcwtch::CwtchLib>,
behaviour: Behaviour,
password: String,
home_dir: String,
settings: Option<Settings>,
profile: Option<Profile>,
}
impl Imp {
pub fn spawn(behaviour: Behaviour, password: String, home_dir: String) -> Self {
let cwtch = libcwtch::new_cwtchlib_go();
println!("start_cwtch");
let ret = cwtch.start_cwtch(&home_dir, "");
println!("start_cwtch returned {}", ret);
return Imp {
behaviour,
cwtch: Box::new(cwtch),
password,
home_dir,
profile: None,
settings: None,
};
}
pub fn behaviour_mut(&self) -> &Behaviour {
&self.behaviour
}
pub fn behaviour_allowlist_add(&mut self, contact: ContactIdentity) {
self.behaviour.allow_list.peers.push(contact);
}
pub fn behaviour_allowlist_rm(&mut self, contact: ContactIdentity) {
if let Some(index) = self.behaviour.allow_list.peers.iter().position(|c| *c == contact) {
self.behaviour.allow_list.peers.remove(index);
}
}
#[allow(unused_variables, unused_mut)]
pub fn event_loop<T>(&mut self, handler: &mut T)
where
T: EventHandler,
{
let mut initialized: bool = false;
loop {
let event = self.cwtch.get_appbus_event();
match &event {
Event::CwtchStarted => {
println!("Cwtch Started");
initialized = true;
if self.profile.is_none() {
self.cwtch.load_profiles(&self.password);
}
}
Event::UpdateGlobalSettings { settings } => {
let mut local_settings = settings.clone();
println!("Loading settings froms {:?}", local_settings);
if self.behaviour.proto_experiments {
local_settings.ExperimentsEnabled = true;
}
if self.behaviour.proto_experiment_fileshare {
local_settings
.Experiments
.insert(Experiments::FileSharingExperiment.to_key_string(), true);
}
if self.behaviour.proto_experiment_groups {
local_settings
.Experiments
.insert(Experiments::GroupExperiment.to_key_string(), true);
}
match local_settings.save(self.cwtch.as_ref()) {
Ok(_) => (),
Err(e) => println!("ERROR: could not save settings: {}", e),
};
match self.profile.as_ref() {
Some(profile) => {
if let Some(profile_pic_path) = &self.behaviour.profile_pic_path {
self.cwtch.share_file(&profile.profile_id, ConversationID(-1), profile_pic_path);
}
}
None => (),
};
self.settings = Some(local_settings);
}
Event::NewPeer { profile_id, tag, created, name, default_picture, picture, online, profile_data} => {
if let Err(e) = profile_data {
panic!("error parsing profile: {}", e);
}
self.cwtch.set_profile_attribute(
&profile_id,
"profile.name",
&self.behaviour.profile_name,
);
if let Ok(ok_profile) = profile_data {
for (_id, conversation) in &ok_profile.conversations {
self.process_contact(conversation.identifier);
}
if let AllowList = &self.behaviour.new_contant_policy {
for contact_id in &self.behaviour.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(ok_profile.clone());
}
}
Event::AppError { error, data } => {
if initialized && error == "Loaded 0 profiles" {
if self.profile.is_none() {
self.cwtch
.create_profile(&self.behaviour.profile_name, &self.password, true);
}
}
}
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 {
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, };
self.process_contact(conversation.identifier);
match self.profile.as_mut() {
Some(profile) => {
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 { 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 } => {
if message.o == InviteGroup {
if let Some(profile) = self.profile.as_ref() {
match &self.behaviour.group_invite_policy {
GroupInvitePolicy::Ignore => (),
GroupInvitePolicy::Accept => self.cwtch.import_bundle(profile_id, message.d.as_str()),
GroupInvitePolicy::AcceptFromContact=> {
if profile.conversations[conversation_id].accepted {
self.cwtch.import_bundle(profile_id, message.d.as_str())
}
}
GroupInvitePolicy::AllowList => {
if let Some(conversation) = profile.conversations.get(&conversation_id) {
if self.behaviour.allow_list.peers.contains(&conversation.contact_id) {
self.cwtch.import_bundle(profile_id, message.d.as_str())
}
}
}
}
}
} else {
if let Some(profile) = self.profile.as_ref() {
match &self.behaviour.contact_interaction_policy {
ContactInteractionPolicy::Ignore => (),
ContactInteractionPolicy::Accept => handler.on_new_message_from_contact(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), nick.clone(), timestamp_received.clone(), message.clone()),
ContactInteractionPolicy::AcceptFromContact=> {
if profile.conversations[conversation_id].accepted {
handler.on_new_message_from_contact(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), nick.clone(), timestamp_received.clone(), message.clone());
}
},
ContactInteractionPolicy::AllowList => {
if let Some(conversation) = profile.conversations.get(&conversation_id) {
if self.behaviour.allow_list.peers.contains(&conversation.contact_id) {
handler.on_new_message_from_contact(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), nick.clone(), timestamp_received.clone(), message.clone());
}
}
}
}
}
}
}
Event::NewMessageFromGroup { profile_id, conversation_id, timestamp_sent, contact_id, index, message, content_hash, picture, notification, } => {
if let Some(profile) = self.profile.as_ref() {
match &self.behaviour.group_interaction_policy {
GroupInteractionPolicy::Ignore => (),
GroupInteractionPolicy::Accept => handler.on_new_message_from_group(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), contact_id.clone(), timestamp_sent.clone(), message.clone()),
GroupInteractionPolicy::AcceptFromContact=> {
if let Some(contact_convo_id) = profile.find_conversation_id_by_handle(contact_id.clone()) {
if profile.conversations[&contact_convo_id].accepted {
handler.on_new_message_from_group(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), contact_id.clone(), timestamp_sent.clone(), message.clone())
}
}
},
GroupInteractionPolicy::AllowList => {
if self.behaviour.allow_list.peers.contains(&contact_id) {
handler.on_new_message_from_group(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), contact_id.clone(), timestamp_sent.clone(), message.clone())
}
}
}
}
}
Event::ErrUnhandled { name, data } => eprintln!("unhandled event: {}!", name),
_ => (),
};
handler.handle(self.cwtch.as_ref(), self.profile.as_ref(), &event);
}
}
fn process_contact(&self, conversation_id: ConversationID) {
match &self.profile {
Some(profile) => {
let profile_handle = profile.profile_id.clone();
match &self.behaviour.new_contant_policy {
NewContactPolicy::Accept => {
self.cwtch
.accept_conversation(&profile.profile_id, conversation_id);
}
NewContactPolicy::Block => self.cwtch.block_conversation(&profile_handle.clone(), conversation_id),
NewContactPolicy::AllowList => {
match profile.conversations.get(&conversation_id) {
Some(conversation) => {
if self.behaviour.allow_list.peers.contains(&conversation.contact_id) {
self.cwtch
.accept_conversation(&profile_handle.clone(), conversation_id);
} else {
self.cwtch.block_conversation(&profile_handle.clone(), conversation_id);
}
},
None => {},
}
}
NewContactPolicy::Ignore => (),
}
},
None => {},
}
}
}