diff --git a/Cargo.lock b/Cargo.lock index e42704e..4f2405d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,8 +124,6 @@ checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libcwtch" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a441fe0922d39eaa632dad730ad587c52d682e0a394c35be335e93a7f7ff557a" dependencies = [ "hex-literal", "libc", diff --git a/Cargo.toml b/Cargo.toml index 6163ce8..5e31d83 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.2.0" +libcwtch = {path = "../libcwtch-rs" } #"0.2.0" serde_json = "1.0" diff --git a/build_bot.png b/build_bot.png new file mode 100644 index 0000000..316ff5a Binary files /dev/null and b/build_bot.png differ diff --git a/src/event.rs b/src/event.rs index 812225d..a5c3e52 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,9 +1,13 @@ +#[derive(Debug)] pub enum Event { CwtchStarted, NewPeer, NewMessageFromPeer, AppError, + ContactCreated, + PeerStateChange, + UpdateGlobalSettings, ErrUnhandled(String), } @@ -15,6 +19,9 @@ impl Event { "NewPeer" => Event::NewPeer, "NewMessageFromPeer" => Event::NewMessageFromPeer, "AppError" => Event::AppError, + "ContactCreated" => Event::ContactCreated, + "PeerStateChange" => Event::PeerStateChange, + "UpdateGlobalSettings" => Event::UpdateGlobalSettings, _ => Event::ErrUnhandled(name.to_string()), } } diff --git a/src/main.rs b/src/main.rs index 647f264..7b6acfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ const BOT_HOME: &str = "~/.cwtch/bots/update_bot"; const PASSWORD: &str = "be gay do crime"; struct UpdateBot { + settings: Option, profile: Option, versions_dirs: Vec, } @@ -35,7 +36,7 @@ impl UpdateBot { version_dirs.push(path); } } - let bot = UpdateBot{ versions_dirs: version_dirs, profile: None}; + let bot = UpdateBot{ versions_dirs: version_dirs, profile: None, settings: None}; println!("versions: {:?}\n", bot.versions_dirs); return bot } @@ -58,7 +59,7 @@ fn main() { // approve all friends - // offer newst version if none or now newest (question about os followed by file strasfer) + // offer newest version if none or now newest (question about os followed by file strasfer) // for all friends, store offered version as attr // respond to simple commands, include links, help info @@ -86,6 +87,27 @@ fn main() { } } + Event::UpdateGlobalSettings => { + println!("Loading settings froms {}", &event.data["Data"]); + let mut settings: Settings = match serde_json::from_str(&event.data["Data"]) { + Ok(s) => s, + Err(e) => panic!("invalid json: {:?}", e), + }; + settings.ExperimentsEnabled = true; + settings.Experiments.insert(Experiments::FileSharingExperiment.to_key_string(),true); + settings.Experiments.insert(Experiments::ImagePreviewsExperiment.to_key_string(),true); + match settings.save(&cwtch) { + Ok(_) => (), + Err(e) => println!("ERROR: could not save settings: {}", e) + }; + match update_bot.profile.as_ref() { + Some(profile) => { + cwtch.share_file(&profile.onion, -1, "build_bot.png"); + }, + None => (), + }; + update_bot.settings = Some(settings); + } Event::NewPeer => { println!( "\n***** {} at {} *****\n", @@ -104,28 +126,137 @@ fn main() { Err(e) => panic!("error parsing profile: {}", e), }; print!("profile: {:?}", profile); + // Share profile image + match update_bot.settings.as_ref() { + Some(_settings) => { + cwtch.share_file(&profile.onion, -1, "build_bot.png"); + }, + None => (), + }; + + for (_id, contact) in &profile.contacts { + if contact.accepted != true { + cwtch.accept_conversation(profile.onion.as_str(), contact.identifier) + } + } update_bot.profile = Some(profile); } Event::AppError => { if initialized && event.data["Error"] == "Loaded 0 profiles" { - cwtch.create_profile("Echobot", PASSWORD); + cwtch.create_profile("Upgrade Bot", PASSWORD); + } + } + Event::ContactCreated => { + if event.data["ConnectionState"] == "Authenticated" { + let profile_onion = event.data["RemotePeer"].to_string(); + let convo_id = event.data["ConversationID"].parse::().unwrap(); + + let contact = Contact{ + onion: profile_onion.clone(), + identifier: event.data["ConversationID"].parse::().unwrap(), + name: event.data["nick"].to_string(), + status: ConnectionState::new(&event.data["status"]), + blocked: event.data["blocked"] == "true", + accepted: event.data["accepted"] == "true", + is_group: false, // by definition + }; + + if contact.accepted != true { + cwtch.accept_conversation(&contact.onion.clone(), convo_id) + } + + match update_bot.profile.as_mut() { + Some(profile) => { + profile.contacts.insert(event.data["RemotePeer"].to_string(), contact); + } + None => () + }; + + update_bot.greet(&cwtch, convo_id); + } + } + + Event::PeerStateChange => { + if event.data["ConnectionState"] == "Authenticated" { + match update_bot.profile.as_ref() { + Some(profile) => { + let contact = &profile.contacts[&event.data["RemotePeer"]]; + if contact.accepted != true { + cwtch.accept_conversation(profile.onion.as_str(), contact.identifier) + } + println!("Sending greeting as peer came online"); + update_bot.greet(&cwtch, contact.identifier); + } + None => () + }; } } Event::NewMessageFromPeer => { let to = &event.data["ProfileOnion"]; let conversation_id = event.data["ConversationID"].parse::().unwrap(); - let message: Message = + let message_wrapper: Message = serde_json::from_str(&event.data["Data"]).expect("Error parsing message"); - let response = Message { o: 1, d: message.d }; - let response_json = - serde_json::to_string(&response).expect("Error parsing json response"); - cwtch.send_message(&to, conversation_id, &response_json); + let latest_version = &update_bot.versions_dirs[update_bot.versions_dirs.len()-1]; + let version = latest_version.strip_prefix(DIST_DIR).unwrap().to_str().unwrap(); + + + let mut message = message_wrapper.d.clone(); + message.make_ascii_lowercase(); + + match message.as_str() { + "windows" => { + let mut windows_path = latest_version.clone(); + windows_path.push("cwtch-installer.exe"); + cwtch.share_file(&to, conversation_id, windows_path.to_str().unwrap()); + }, + "linux" => { + let mut linux_path = latest_version.clone(); + linux_path.push(format!("cwtch-{}.tar.gz", version)); + cwtch.share_file(&to, conversation_id, linux_path.to_str().unwrap()); + }, + "macos" => { + let mut mac_path = latest_version.clone(); + mac_path.push("Cwtch.dmg"); + cwtch.share_file(&to, conversation_id, mac_path.to_str().unwrap()); + }, + "android" => { + let mut android_path = latest_version.clone(); + android_path.push("app-release.apk"); + cwtch.share_file(&to, conversation_id, android_path.to_str().unwrap()); + } + _ => { + let resp_message = format!("Currently offering Cwtch {}\nPlease respond with the OS you would like a package for:\n- Windows\n- Android\n- MacOS\n- Linux", version); + let response = Message { o: 1, d: resp_message }; + let response_json = + serde_json::to_string(&response).expect("Error parsing json response"); + cwtch.send_message(&to, conversation_id, &response_json); + } + + } } Event::ErrUnhandled(err) => eprintln!("unhandled event: {}!", err), + _ => print!("unhandled event: {:?}!", event_type) }; } }); event_loop_handle.join().expect("Error running event loop"); } + +impl UpdateBot { + pub fn greet(&self, cwtch: &dyn CwtchLib, convo_id: i32) { + match self.profile.as_ref() { + Some(profile) => { + // TODO throttle as we seem to be able to get a bunch of Authenticated messages + // TODO getAttribute what was the last version we offered, if there is a newer, make the offer, update attr + println!("Sending greeting as peer came online"); + let greeting = Message { o: 1, d: "Hello".to_string() }; + let greeting_json = + serde_json::to_string(&greeting).expect("Error parsing json response"); + cwtch.send_message(profile.onion.as_ref(), convo_id, &greeting_json); + } + None => () + }; + } +}