update_bot/src/main.rs

263 lines
11 KiB
Rust
Raw Normal View History

mod event;
extern crate core;
use event::Event;
use std::fs::read_dir;
use std::path::{Path, PathBuf};
use std::thread;
use serde_json;
use libcwtch;
use libcwtch::structs::*;
use libcwtch::CwtchLib;
const DIST_DIR: &str = "cwtch_dist";
const BOT_HOME: &str = "~/.cwtch/bots/update_bot";
const PASSWORD: &str = "be gay do crime";
struct UpdateBot {
settings: Option<Settings>,
profile: Option<Profile>,
versions_dirs: Vec<PathBuf>,
}
impl UpdateBot {
pub fn new() -> Self {
let mut version_dirs = 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());
version_dirs.push(path);
}
}
let bot = UpdateBot{ versions_dirs: version_dirs, profile: None, settings: None};
println!("versions: {:?}\n", bot.versions_dirs);
return bot
}
}
fn main() {
// load file, parse version
if !Path::new(DIST_DIR).exists() {
panic!("no '{}' directory with versions to distribute", DIST_DIR)
}
let mut update_bot = UpdateBot::new();
// make cwtch bot
let cwtch = libcwtch::new_cwtchlib_go();
println!("start_cwtch");
let ret = cwtch.start_cwtch(BOT_HOME, "");
println!("start_cwtch returned {}", ret);
// approve all friends
// 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
let event_loop_handle = thread::spawn(move || {
let mut initialized: bool = false;
loop {
let event_str = cwtch.get_appbus_event();
println!("event: {}", event_str);
let event: CwtchEvent =
serde_json::from_str(&event_str).expect("Error parsing Cwtch event");
let event_type = Event::new(event.event_type.as_str());
match event_type {
Event::CwtchStarted => {
println!("event CwtchStarted!");
initialized = true;
match update_bot.profile {
None => {
println!("Creating bot");
cwtch.load_profiles(PASSWORD);
},
Some(_) => (),
}
}
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",
event.data["name"], event.data["Identity"]
);
// process json for profile, contacts and servers...else {
let profile = match Profile::new(
&event.data["Identity"],
&event.data["name"],
&event.data["picture"],
&event.data["ContactsJson"],
&event.data["ServerList"],
) {
Ok(p) => p,
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("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::<i32>().unwrap();
let contact = Contact{
onion: profile_onion.clone(),
identifier: event.data["ConversationID"].parse::<i32>().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::<i32>().unwrap();
let message_wrapper: Message =
serde_json::from_str(&event.data["Data"]).expect("Error parsing message");
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 => ()
};
}
}