extern crate core; use std::borrow::{BorrowMut}; use std::fs::read_dir; use std::path::{Path, PathBuf}; use std::thread; use cwtch_imp::imp; use cwtch_imp::behaviour; use cwtch_imp::behaviour::BehaviourBuilder; use cwtch_imp::behaviour::Behaviour; use cwtch_imp::imp::Imp; use chrono::{DateTime, FixedOffset}; use libcwtch; use libcwtch::CwtchLib; use libcwtch::event::{ContactIdentity, ConversationID}; use libcwtch::structs::*; const DIST_DIR: &str = "cwtch_dist"; const BOT_HOME: &str = "~/.cwtch/bots/update_bot"; const PASSWORD: &str = "be gay do crime"; const BOT_NAME: &str = "Update Bot"; const LAST_OFFERED_KEY: &str = "profile.last_version_offered"; #[derive(Debug, Clone)] struct Version { major: u8, minor: u8, fix: u8, path: PathBuf, } struct UpdateBot { versions_dirs: Vec, latest_version: PathBuf, version: String, } impl Version { pub fn new(path: PathBuf) -> Self { let vs = path.to_str().unwrap().strip_prefix(DIST_DIR).unwrap().trim_start_matches("/v"); let parts: Vec<&str> = vs.split(".").collect(); if parts.len() != 3 { return Version{ major: 0, minor: 0, fix: 0, path: PathBuf::new()} } return Version{ major: parts[0].parse::().unwrap(), minor: parts[1].parse::().unwrap(), fix: parts[2].parse::().unwrap(), path: path} } } impl UpdateBot { pub fn new() -> Self { let mut versions_dirs: Vec = vec![]; for entry in read_dir(Path::new(DIST_DIR)).expect(&format!("could not open '{}' dir", DIST_DIR)) { let entry = entry.unwrap(); let path: PathBuf = entry.path(); if path.is_dir() { println!("version: {}", path.to_str().unwrap()); //versions_dirs.push(path.clone()); let v = Version::new(path); println!("{:?}", v); versions_dirs.push(v); } } if versions_dirs.len() == 0 { panic!("no cwtch versions detected in {}!", DIST_DIR) } versions_dirs.sort_unstable_by_key(|item| (item.major, item.minor, item.fix)); println!("sorted vd: {:?}", versions_dirs); let latest_version = versions_dirs[versions_dirs.len() - 1].clone(); let version: String = latest_version.path .strip_prefix(DIST_DIR) .unwrap() .to_str() .unwrap() .to_string(); let bot = UpdateBot { versions_dirs: versions_dirs, latest_version: latest_version.path, version: version, }; println!("versions: {:?}\n", bot.versions_dirs); return bot; } } fn main() { if !Path::new(DIST_DIR).exists() { panic!("no '{}' directory with versions to distribute", DIST_DIR) } let mut update_bot = UpdateBot::new(); let behaviour: Behaviour = BehaviourBuilder::new().name(BOT_NAME.to_string()).profile_pic_path("updatebot.png".to_string()).new_contact_policy(behaviour::NewContactPolicy::Accept).build(); let event_loop_handle = thread::spawn(move || { let mut bot = Imp::spawn(behaviour, PASSWORD.to_string(), BOT_HOME.to_string()); bot.event_loop::(update_bot.borrow_mut()); }); event_loop_handle.join().expect("Error running event loop"); } impl UpdateBot { pub fn greet(&self, cwtch: &dyn CwtchLib, profile: &Profile, convo_id: ConversationID) { let do_offer = match cwtch.get_conversation_attribute( &profile.profile_id, convo_id, &format!("local.{}", LAST_OFFERED_KEY), ) { Ok(ret) => match ret { Some(last_offered) => last_offered != self.version, None => true, }, Err(_) => false }; if do_offer { self.offer(cwtch, profile, convo_id); cwtch.set_conversation_attribute( &profile.profile_id, convo_id, LAST_OFFERED_KEY, &self.version, ); } } pub fn offer(&self, cwtch: &dyn CwtchLib, profile: &Profile, convo_id: ConversationID) { 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", self.version ); let response = MessageWrapper { o: MessageType::TextMessage, d: resp_message, }; cwtch.send_message(&profile.profile_id, convo_id, &response); } } impl imp::EventHandler for UpdateBot { fn on_contact_online(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: ConversationID) { self.greet(cwtch, profile, convo_id); } fn on_new_message_from_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, conversation_id: ConversationID, _handle: String, _timestamp_received: DateTime, message: MessageWrapper) { let mut body = message.d.clone(); body.make_ascii_lowercase(); match body.as_str() { "windows" => { let mut windows_path = self.latest_version.clone(); windows_path.push(format!("cwtch-installer-{}.exe", self.version)); cwtch.share_file(&profile.profile_id, conversation_id, windows_path.to_str().unwrap()); } "linux" => { let mut linux_path = self.latest_version.clone(); linux_path.push(format!("cwtch-{}.tar.gz", self.version)); cwtch.share_file(&profile.profile_id, conversation_id, linux_path.to_str().unwrap()); } "macos" => { let mut mac_path = self.latest_version.clone(); mac_path.push(format!("Cwtch-{}.dmg", self.version)); cwtch.share_file(&profile.profile_id, conversation_id, mac_path.to_str().unwrap()); } "android" => { let mut android_path = self.latest_version.clone(); android_path.push(format!("cwtch-{}.apk", self.version)); cwtch.share_file(&profile.profile_id, conversation_id, android_path.to_str().unwrap()); } _ => { self.offer(cwtch, profile, conversation_id); } } } }