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 " ;
2022-04-09 17:51:55 +00:00
const BOT_NAME : & str = " Update Bot " ;
const LAST_OFFERED_KEY : & str = " profile.last_version_offered " ;
2022-02-24 04:57:20 +00:00
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 > ,
2022-04-09 17:51:55 +00:00
latest_version : PathBuf ,
version : String ,
2022-02-24 04:57:20 +00:00
}
impl UpdateBot {
pub fn new ( ) -> Self {
2022-04-09 17:51:55 +00:00
let mut versions_dirs = vec! [ ] ;
2022-02-24 04:57:20 +00:00
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 ( ) ) ;
2022-04-09 17:51:55 +00:00
versions_dirs . push ( path ) ;
2022-02-24 04:57:20 +00:00
}
}
2022-04-09 17:51:55 +00:00
versions_dirs . sort ( ) ;
println! ( " sorted vd: {:?} " , versions_dirs ) ;
let latest_version = versions_dirs [ versions_dirs . len ( ) - 1 ] . clone ( ) ;
let version : String = latest_version . strip_prefix ( DIST_DIR ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
let bot = UpdateBot { versions_dirs : versions_dirs , profile : None , settings : None , latest_version : latest_version , version : version } ;
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 ) ;
2022-04-09 17:51:55 +00:00
// TODO delete
settings . Experiments . insert ( Experiments ::ImagePreviewsExperiment . to_key_string ( ) , false ) ;
2022-04-05 01:12:51 +00:00
match settings . save ( & cwtch ) {
Ok ( _ ) = > ( ) ,
Err ( e ) = > println! ( " ERROR: could not save settings: {} " , e )
} ;
match update_bot . profile . as_ref ( ) {
Some ( profile ) = > {
2022-04-09 17:51:55 +00:00
cwtch . share_file ( & profile . handle , - 1 , " build_bot.png " ) ;
2022-04-05 01:12:51 +00:00
} ,
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 " ]
) ;
2022-04-09 17:51:55 +00:00
// process json for profile, conversations and servers...else {
2022-02-24 04:57:20 +00:00
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 ) = > {
2022-04-09 17:51:55 +00:00
cwtch . share_file ( & profile . handle , - 1 , " build_bot.png " ) ;
2022-04-05 01:12:51 +00:00
} ,
None = > ( ) ,
} ;
2022-04-09 17:51:55 +00:00
cwtch . set_profile_attribute ( & profile . handle , " profile.name " , BOT_NAME ) ;
for ( _id , conversation ) in & profile . conversations {
if conversation . accepted ! = true {
cwtch . accept_conversation ( profile . handle . as_str ( ) , conversation . identifier )
2022-04-05 01:12:51 +00:00
}
}
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-09 17:51:55 +00:00
cwtch . create_profile ( BOT_NAME , PASSWORD ) ;
2022-04-05 01:12:51 +00:00
}
}
Event ::ContactCreated = > {
if event . data [ " ConnectionState " ] = = " Authenticated " {
let profile_onion = event . data [ " RemotePeer " ] . to_string ( ) ;
let convo_id = event . data [ " ConversationID " ] . parse ::< i32 > ( ) . unwrap ( ) ;
2022-04-09 17:51:55 +00:00
let acl : ACL = serde_json ::from_str ( & event . data [ " accessControlList " ] ) . expect ( " Error parsing conversation " ) ;
let conversation = Conversation {
handle : profile_onion . clone ( ) ,
2022-04-05 01:12:51 +00:00
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 " ,
2022-04-09 17:51:55 +00:00
access_control_list : acl ,
2022-04-05 01:12:51 +00:00
is_group : false , // by definition
} ;
2022-04-09 17:51:55 +00:00
if conversation . accepted ! = true {
cwtch . accept_conversation ( & conversation . handle . clone ( ) , convo_id )
2022-04-05 01:12:51 +00:00
}
match update_bot . profile . as_mut ( ) {
Some ( profile ) = > {
2022-04-09 17:51:55 +00:00
profile . conversations . insert ( event . data [ " RemotePeer " ] . to_string ( ) , conversation ) ;
2022-04-05 01:12:51 +00:00
}
None = > ( )
} ;
update_bot . greet ( & cwtch , convo_id ) ;
}
}
Event ::PeerStateChange = > {
if event . data [ " ConnectionState " ] = = " Authenticated " {
match update_bot . profile . as_ref ( ) {
Some ( profile ) = > {
2022-04-09 17:51:55 +00:00
let conversation = & profile . conversations [ & event . data [ " RemotePeer " ] ] ;
if conversation . accepted ! = true {
cwtch . accept_conversation ( profile . handle . as_str ( ) , conversation . identifier )
2022-04-05 01:12:51 +00:00
}
2022-04-09 17:51:55 +00:00
update_bot . greet ( & cwtch , conversation . identifier ) ;
2022-04-05 01:12:51 +00:00
}
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 mut message = message_wrapper . d . clone ( ) ;
message . make_ascii_lowercase ( ) ;
match message . as_str ( ) {
" windows " = > {
2022-04-09 17:51:55 +00:00
let mut windows_path = update_bot . latest_version . clone ( ) ;
2022-04-05 01:12:51 +00:00
windows_path . push ( " cwtch-installer.exe " ) ;
cwtch . share_file ( & to , conversation_id , windows_path . to_str ( ) . unwrap ( ) ) ;
} ,
" linux " = > {
2022-04-09 17:51:55 +00:00
let mut linux_path = update_bot . latest_version . clone ( ) ;
linux_path . push ( format! ( " cwtch- {} .tar.gz " , update_bot . version ) ) ;
2022-04-05 01:12:51 +00:00
cwtch . share_file ( & to , conversation_id , linux_path . to_str ( ) . unwrap ( ) ) ;
} ,
" macos " = > {
2022-04-09 17:51:55 +00:00
let mut mac_path = update_bot . latest_version . clone ( ) ;
2022-04-05 01:12:51 +00:00
mac_path . push ( " Cwtch.dmg " ) ;
cwtch . share_file ( & to , conversation_id , mac_path . to_str ( ) . unwrap ( ) ) ;
} ,
" android " = > {
2022-04-09 17:51:55 +00:00
let mut android_path = update_bot . latest_version . clone ( ) ;
2022-04-05 01:12:51 +00:00
android_path . push ( " app-release.apk " ) ;
cwtch . share_file ( & to , conversation_id , android_path . to_str ( ) . unwrap ( ) ) ;
}
_ = > {
2022-04-09 17:51:55 +00:00
update_bot . offer ( & cwtch , conversation_id ) ;
2022-04-05 01:12:51 +00:00
}
}
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 ) = > {
2022-04-09 17:51:55 +00:00
let do_offer = match cwtch . get_conversation_attribute ( & profile . handle , convo_id , & format! ( " local. {} " , LAST_OFFERED_KEY ) ) {
Ok ( ret ) = > match ret {
Some ( last_offered ) = > last_offered ! = self . version ,
None = > true ,
} ,
Err ( e ) = > {
println! ( " Error parsing attribute: {} " , e ) ;
false
}
} ;
if do_offer {
self . offer ( cwtch , convo_id ) ;
cwtch . set_conversation_attribute ( & profile . handle , convo_id , LAST_OFFERED_KEY , & self . version ) ;
}
}
None = > ( )
} ;
}
pub fn offer ( & self , cwtch : & dyn CwtchLib , convo_id : i32 ) {
match self . profile . as_ref ( ) {
Some ( profile ) = > {
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 " , self . 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 ( & profile . handle , convo_id , & response_json ) ;
2022-04-05 01:12:51 +00:00
}
None = > ( )
} ;
}
}