First cut of canonical events
This commit is contained in:
parent
d61c4086d4
commit
bd03cd9d83
|
@ -8,3 +8,4 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libcwtch = "0.3.0"
|
libcwtch = "0.3.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
chrono = "0.4.19"
|
|
@ -0,0 +1,78 @@
|
||||||
|
max_width = 200
|
||||||
|
hard_tabs = false
|
||||||
|
tab_spaces = 4
|
||||||
|
newline_style = "Auto"
|
||||||
|
indent_style = "Block"
|
||||||
|
use_small_heuristics = "Default"
|
||||||
|
fn_call_width = 60
|
||||||
|
attr_fn_like_width = 70
|
||||||
|
struct_lit_width = 18
|
||||||
|
struct_variant_width = 35
|
||||||
|
array_width = 60
|
||||||
|
chain_width = 60
|
||||||
|
single_line_if_else_max_width = 50
|
||||||
|
wrap_comments = false
|
||||||
|
format_code_in_doc_comments = false
|
||||||
|
comment_width = 80
|
||||||
|
normalize_comments = false
|
||||||
|
normalize_doc_attributes = false
|
||||||
|
license_template_path = ""
|
||||||
|
format_strings = false
|
||||||
|
format_macro_matchers = false
|
||||||
|
format_macro_bodies = true
|
||||||
|
hex_literal_case = "Preserve"
|
||||||
|
empty_item_single_line = true
|
||||||
|
struct_lit_single_line = true
|
||||||
|
fn_single_line = false
|
||||||
|
where_single_line = false
|
||||||
|
imports_indent = "Block"
|
||||||
|
imports_layout = "Mixed"
|
||||||
|
imports_granularity = "Preserve"
|
||||||
|
group_imports = "Preserve"
|
||||||
|
reorder_imports = true
|
||||||
|
reorder_modules = true
|
||||||
|
reorder_impl_items = false
|
||||||
|
type_punctuation_density = "Wide"
|
||||||
|
space_before_colon = false
|
||||||
|
space_after_colon = true
|
||||||
|
spaces_around_ranges = false
|
||||||
|
binop_separator = "Front"
|
||||||
|
remove_nested_parens = true
|
||||||
|
combine_control_expr = true
|
||||||
|
short_array_element_width_threshold = 10
|
||||||
|
overflow_delimited_expr = false
|
||||||
|
struct_field_align_threshold = 0
|
||||||
|
enum_discrim_align_threshold = 0
|
||||||
|
match_arm_blocks = true
|
||||||
|
match_arm_leading_pipes = "Never"
|
||||||
|
force_multiline_blocks = false
|
||||||
|
fn_args_layout = "Tall"
|
||||||
|
brace_style = "SameLineWhere"
|
||||||
|
control_brace_style = "AlwaysSameLine"
|
||||||
|
trailing_semicolon = true
|
||||||
|
trailing_comma = "Vertical"
|
||||||
|
match_block_trailing_comma = false
|
||||||
|
blank_lines_upper_bound = 1
|
||||||
|
blank_lines_lower_bound = 0
|
||||||
|
edition = "2015"
|
||||||
|
version = "One"
|
||||||
|
inline_attribute_width = 0
|
||||||
|
format_generated_files = true
|
||||||
|
merge_derives = true
|
||||||
|
use_try_shorthand = false
|
||||||
|
use_field_init_shorthand = false
|
||||||
|
force_explicit_abi = true
|
||||||
|
condense_wildcard_suffixes = false
|
||||||
|
color = "Auto"
|
||||||
|
required_version = "1.4.38"
|
||||||
|
unstable_features = false
|
||||||
|
disable_all_formatting = false
|
||||||
|
skip_children = false
|
||||||
|
hide_parse_errors = false
|
||||||
|
error_on_line_overflow = false
|
||||||
|
error_on_unformatted = false
|
||||||
|
report_todo = "Never"
|
||||||
|
report_fixme = "Never"
|
||||||
|
ignore = []
|
||||||
|
emit_mode = "Files"
|
||||||
|
make_backup = false
|
81
src/event.rs
81
src/event.rs
|
@ -1,27 +1,70 @@
|
||||||
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
use libcwtch::structs::CwtchEvent;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
CwtchStarted,
|
CwtchStarted {
|
||||||
NewPeer,
|
data: HashMap<String, String>,
|
||||||
NewMessageFromPeer,
|
},
|
||||||
AppError,
|
NewPeer {
|
||||||
ContactCreated,
|
data: HashMap<String, String>,
|
||||||
PeerStateChange,
|
},
|
||||||
UpdateGlobalSettings,
|
|
||||||
|
|
||||||
ErrUnhandled(String),
|
NewMessageFromPeer {
|
||||||
|
handle: String,
|
||||||
|
timestamp_received: DateTime<FixedOffset>,
|
||||||
|
message: String,
|
||||||
|
},
|
||||||
|
AppError {
|
||||||
|
data: HashMap<String, String>,
|
||||||
|
},
|
||||||
|
ContactCreated {
|
||||||
|
data: HashMap<String, String>,
|
||||||
|
},
|
||||||
|
PeerStateChange {
|
||||||
|
data: HashMap<String, String>,
|
||||||
|
},
|
||||||
|
UpdateGlobalSettings {
|
||||||
|
data: HashMap<String, String>,
|
||||||
|
},
|
||||||
|
|
||||||
|
ErrUnhandled {
|
||||||
|
name: String,
|
||||||
|
data: HashMap<String, String>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Event {
|
impl From<&CwtchEvent> for Event {
|
||||||
fn from(name: &str) -> Self {
|
fn from(cwtch_event: &CwtchEvent) -> Self {
|
||||||
match name {
|
match cwtch_event.event_type.as_str() {
|
||||||
"CwtchStarted" => Event::CwtchStarted,
|
"CwtchStarted" => Event::CwtchStarted {
|
||||||
"NewPeer" => Event::NewPeer,
|
data: cwtch_event.data.clone(),
|
||||||
"NewMessageFromPeer" => Event::NewMessageFromPeer,
|
},
|
||||||
"AppError" => Event::AppError,
|
"NewPeer" => Event::NewPeer {
|
||||||
"ContactCreated" => Event::ContactCreated,
|
data: cwtch_event.data.clone(),
|
||||||
"PeerStateChange" => Event::PeerStateChange,
|
},
|
||||||
"UpdateGlobalSettings" => Event::UpdateGlobalSettings,
|
"NewMessageFromPeer" => Event::NewMessageFromPeer {
|
||||||
_ => Event::ErrUnhandled(name.to_string()),
|
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(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
127
src/imp.rs
127
src/imp.rs
|
@ -1,6 +1,6 @@
|
||||||
|
use crate::event::Event;
|
||||||
use libcwtch::structs::*;
|
use libcwtch::structs::*;
|
||||||
use libcwtch::CwtchLib;
|
use libcwtch::CwtchLib;
|
||||||
use crate::event::Event;
|
|
||||||
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
|
@ -31,18 +31,20 @@ pub struct Behaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BehaviourBuilder {
|
pub struct BehaviourBuilder {
|
||||||
behaviour: Behaviour
|
behaviour: Behaviour,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BehaviourBuilder {
|
impl BehaviourBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
return BehaviourBuilder{ behaviour: Behaviour {
|
return BehaviourBuilder {
|
||||||
proto_experiments: false,
|
behaviour: Behaviour {
|
||||||
proto_experiment_fileshare: false,
|
proto_experiments: false,
|
||||||
new_contant_policy: NewContactPolicy::Ignore,
|
proto_experiment_fileshare: false,
|
||||||
profile_name: "".to_string(),
|
new_contant_policy: NewContactPolicy::Ignore,
|
||||||
profile_pic_path: None,
|
profile_name: "".to_string(),
|
||||||
}}
|
profile_pic_path: None,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Behaviour {
|
pub fn build(self) -> Behaviour {
|
||||||
|
@ -75,7 +77,7 @@ impl BehaviourBuilder {
|
||||||
/// Trait to be used by implementors of imp bots to supply their custom event handling
|
/// 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
|
/// the handle function is called after the default imp automatic event handling has run on each new event
|
||||||
pub trait EventHandler {
|
pub trait EventHandler {
|
||||||
fn handle(&mut self, cwtch: &dyn CwtchLib, profile: Option<&Profile>, event: CwtchEvent);
|
fn handle(&mut self, cwtch: &dyn CwtchLib, profile: Option<&Profile>, event: Event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cwtch bot
|
/// Cwtch bot
|
||||||
|
@ -98,22 +100,31 @@ impl Imp {
|
||||||
let ret = cwtch.start_cwtch(&home_dir, "");
|
let ret = cwtch.start_cwtch(&home_dir, "");
|
||||||
println!("start_cwtch returned {}", ret);
|
println!("start_cwtch returned {}", ret);
|
||||||
|
|
||||||
return Imp {behaviour, cwtch: Box::new(cwtch), password, home_dir, profile: None, settings: None}
|
return Imp {
|
||||||
|
behaviour,
|
||||||
|
cwtch: Box::new(cwtch),
|
||||||
|
password,
|
||||||
|
home_dir,
|
||||||
|
profile: None,
|
||||||
|
settings: None,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
/// 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
|
||||||
pub fn event_loop<T>(&mut self, handler: &mut T) where T : EventHandler {
|
pub fn event_loop<T>(&mut self, handler: &mut T)
|
||||||
|
where
|
||||||
|
T: EventHandler,
|
||||||
|
{
|
||||||
let mut initialized: bool = false;
|
let mut initialized: bool = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let event_str = self.cwtch.get_appbus_event();
|
let event_str = self.cwtch.get_appbus_event();
|
||||||
println!("bot: event: {}", event_str);
|
println!("bot: event: {}", event_str);
|
||||||
|
|
||||||
let event: CwtchEvent =
|
let event: CwtchEvent = serde_json::from_str(&event_str).expect("Error parsing Cwtch event");
|
||||||
serde_json::from_str(&event_str).expect("Error parsing Cwtch event");
|
let event = Event::from(&event);
|
||||||
let event_type = Event::from(event.event_type.as_str()) ;
|
match &event {
|
||||||
match event_type {
|
Event::CwtchStarted { data } => {
|
||||||
Event::CwtchStarted => {
|
|
||||||
println!("event CwtchStarted!");
|
println!("event CwtchStarted!");
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
|
@ -125,9 +136,9 @@ impl Imp {
|
||||||
Some(_) => (),
|
Some(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::UpdateGlobalSettings => {
|
Event::UpdateGlobalSettings { data } => {
|
||||||
println!("Loading settings froms {}", &event.data["Data"]);
|
println!("Loading settings froms {}", &data["Data"]);
|
||||||
let mut settings: Settings = match serde_json::from_str(&event.data["Data"]) {
|
let mut settings: Settings = match serde_json::from_str(&data["Data"]) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => panic!("invalid json: {:?}", e),
|
Err(e) => panic!("invalid json: {:?}", e),
|
||||||
};
|
};
|
||||||
|
@ -156,19 +167,16 @@ impl Imp {
|
||||||
|
|
||||||
self.settings = Some(settings);
|
self.settings = Some(settings);
|
||||||
}
|
}
|
||||||
Event::NewPeer => {
|
Event::NewPeer { data } => {
|
||||||
println!(
|
println!("\n***** {} at {} *****\n", data["name"], data["Identity"]);
|
||||||
"\n***** {} at {} *****\n",
|
|
||||||
event.data["name"], event.data["Identity"]
|
|
||||||
);
|
|
||||||
|
|
||||||
// process json for profile, conversations and servers...else {
|
// process json for profile, conversations and servers...else {
|
||||||
let profile = match Profile::new(
|
let profile = match Profile::new(
|
||||||
&event.data["Identity"],
|
&data["Identity"],
|
||||||
&event.data["name"],
|
&data["name"],
|
||||||
&event.data["picture"],
|
&data["picture"],
|
||||||
&event.data["ContactsJson"],
|
&data["ContactsJson"],
|
||||||
&event.data["ServerList"],
|
&data["ServerList"],
|
||||||
) {
|
) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => panic!("error parsing profile: {}", e),
|
Err(e) => panic!("error parsing profile: {}", e),
|
||||||
|
@ -181,41 +189,47 @@ impl Imp {
|
||||||
None => (),
|
None => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cwtch.set_profile_attribute(&profile.handle, "profile.name", &self.behaviour.profile_name);
|
self.cwtch.set_profile_attribute(
|
||||||
|
&profile.handle,
|
||||||
|
"profile.name",
|
||||||
|
&self.behaviour.profile_name,
|
||||||
|
);
|
||||||
|
|
||||||
for (_id, conversation) in &profile.conversations {
|
for (_id, conversation) in &profile.conversations {
|
||||||
match self.behaviour.new_contant_policy {
|
match self.behaviour.new_contant_policy {
|
||||||
NewContactPolicy::Accept => {
|
NewContactPolicy::Accept => {
|
||||||
self.cwtch.accept_conversation(&profile.handle.clone(), conversation.identifier);
|
self.cwtch
|
||||||
},
|
.accept_conversation(&profile.handle.clone(), conversation.identifier);
|
||||||
NewContactPolicy::Block =>
|
}
|
||||||
self.cwtch.block_contact(&profile.handle.clone(), conversation.identifier),
|
NewContactPolicy::Block => self
|
||||||
|
.cwtch
|
||||||
|
.block_contact(&profile.handle.clone(), conversation.identifier),
|
||||||
NewContactPolicy::Ignore => (),
|
NewContactPolicy::Ignore => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.profile = Some(profile);
|
self.profile = Some(profile);
|
||||||
}
|
}
|
||||||
Event::AppError => {
|
Event::AppError { data } => {
|
||||||
if initialized && event.data["Error"] == "Loaded 0 profiles" {
|
if initialized && data["Error"] == "Loaded 0 profiles" {
|
||||||
self.cwtch.create_profile(&self.behaviour.profile_name, &self.password);
|
self.cwtch
|
||||||
|
.create_profile(&self.behaviour.profile_name, &self.password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::ContactCreated => {
|
Event::ContactCreated { data } => {
|
||||||
println!("Contact Created");
|
println!("Contact Created");
|
||||||
let convo_handle = event.data["RemotePeer"].to_string();
|
let convo_handle = data["RemotePeer"].to_string();
|
||||||
let convo_id = event.data["ConversationID"].parse::<i32>().unwrap();
|
let convo_id = data["ConversationID"].parse::<i32>().unwrap();
|
||||||
|
|
||||||
let acl: ACL = serde_json::from_str(&event.data["accessControlList"])
|
let acl: ACL = serde_json::from_str(&data["accessControlList"]).expect("Error parsing conversation");
|
||||||
.expect("Error parsing conversation");
|
|
||||||
|
|
||||||
let conversation = Conversation {
|
let conversation = Conversation {
|
||||||
handle: convo_handle.clone(),
|
handle: convo_handle.clone(),
|
||||||
identifier: event.data["ConversationID"].parse::<i32>().unwrap(),
|
identifier: data["ConversationID"].parse::<i32>().unwrap(),
|
||||||
name: event.data["nick"].to_string(),
|
name: data["nick"].to_string(),
|
||||||
status: ConnectionState::new(&event.data["status"]),
|
status: ConnectionState::new(&data["status"]),
|
||||||
blocked: event.data["blocked"] == "true",
|
blocked: data["blocked"] == "true",
|
||||||
accepted: event.data["accepted"] == "true",
|
accepted: data["accepted"] == "true",
|
||||||
access_control_list: acl,
|
access_control_list: acl,
|
||||||
is_group: false, // by definition
|
is_group: false, // by definition
|
||||||
};
|
};
|
||||||
|
@ -224,27 +238,26 @@ impl Imp {
|
||||||
Some(profile) => {
|
Some(profile) => {
|
||||||
profile
|
profile
|
||||||
.conversations
|
.conversations
|
||||||
.insert(event.data["RemotePeer"].to_string(), conversation);
|
.insert(data["RemotePeer"].to_string(), conversation);
|
||||||
|
|
||||||
match self.behaviour.new_contant_policy {
|
match self.behaviour.new_contant_policy {
|
||||||
NewContactPolicy::Accept => {
|
NewContactPolicy::Accept => {
|
||||||
self.cwtch.accept_conversation(&profile.handle.clone(), convo_id);
|
self.cwtch
|
||||||
},
|
.accept_conversation(&profile.handle.clone(), convo_id);
|
||||||
NewContactPolicy::Block =>
|
}
|
||||||
self.cwtch.block_contact(&profile.handle.clone(), convo_id),
|
NewContactPolicy::Block => self.cwtch.block_contact(&profile.handle.clone(), convo_id),
|
||||||
NewContactPolicy::Ignore => (),
|
NewContactPolicy::Ignore => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => (),
|
None => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Event::PeerStateChange => {
|
Event::PeerStateChange { data } => {}
|
||||||
}
|
Event::ErrUnhandled { name, data } => eprintln!("unhandled event: {}!", name),
|
||||||
Event::ErrUnhandled(err) => eprintln!("unhandled event: {}!", err),
|
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
handler.handle(self.cwtch.as_ref(), self.profile.as_ref(), event);
|
handler.handle(self.cwtch.as_ref(), self.profile.as_ref(), event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
|
pub mod event;
|
||||||
pub mod imp;
|
pub mod imp;
|
||||||
pub mod event;
|
|
Loading…
Reference in New Issue