2022-02-24 04:57:20 +00:00
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 {
2022-04-05 01:12:51 +00:00
settings : Option < Settings > ,
2022-02-24 04:57:20 +00:00
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 ) ;
}
}
2022-04-05 01:12:51 +00:00
let bot = UpdateBot { versions_dirs : version_dirs , profile : None , settings : None } ;
2022-02-24 04:57:20 +00:00
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
2022-04-05 01:12:51 +00:00
// offer newest version if none or now newest (question about os followed by file strasfer)
2022-02-24 04:57:20 +00:00
// 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 ( _ ) = > ( ) ,
}
}
2022-04-05 01:12:51 +00:00
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 ) ;
}
2022-02-24 04:57:20 +00:00
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 ) ;
2022-04-05 01:12:51 +00:00
// 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 )
}
}
2022-02-24 04:57:20 +00:00
update_bot . profile = Some ( profile ) ;
}
Event ::AppError = > {
if initialized & & event . data [ " Error " ] = = " Loaded 0 profiles " {
2022-04-05 01:12:51 +00:00
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 = > ( )
} ;
2022-02-24 04:57:20 +00:00
}
}
Event ::NewMessageFromPeer = > {
let to = & event . data [ " ProfileOnion " ] ;
let conversation_id = event . data [ " ConversationID " ] . parse ::< i32 > ( ) . unwrap ( ) ;
2022-04-05 01:12:51 +00:00
let message_wrapper : Message =
2022-02-24 04:57:20 +00:00
serde_json ::from_str ( & event . data [ " Data " ] ) . expect ( " Error parsing message " ) ;
2022-04-05 01:12:51 +00:00
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 {} \n Please 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 ) ;
}
}
2022-02-24 04:57:20 +00:00
}
Event ::ErrUnhandled ( err ) = > eprintln! ( " unhandled event: {} ! " , err ) ,
2022-04-05 01:12:51 +00:00
_ = > print! ( " unhandled event: {:?} ! " , event_type )
2022-02-24 04:57:20 +00:00
} ;
}
} ) ;
event_loop_handle . join ( ) . expect ( " Error running event loop " ) ;
}
2022-04-05 01:12:51 +00:00
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 = > ( )
} ;
}
}