diff --git a/deadcode/nodev2.rs b/deadcode/nodev2.rs new file mode 100644 index 0000000..ba36b0e --- /dev/null +++ b/deadcode/nodev2.rs @@ -0,0 +1,75 @@ +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::time::SystemTime; +use std::io::{prelude::*, BufReader}; +use std::net::TcpStream; +use std::str; +use std::thread; +use regex::Regex; + + +pub fn send_cmd(mut stream: &TcpStream, cmd: &str, msg: String) -> Result { + let mut cmd = cmd.to_string(); + cmd.push_str(" "); + cmd.push_str(&msg); + println!("sending: {}", cmd.trim()); + stream.write(cmd.as_bytes()) +} + + +pub fn write_log(log: &str, first_line: bool) -> Result<(), std::io::Error> { + if std::fs::File::open(crate::IRC_LOG).is_err() { + let _ = std::fs::write(crate::IRC_LOG, ""); + } + let mut f = OpenOptions::new() + .append(true) + .open(crate::IRC_LOG) + .unwrap(); + if first_line { + let _ = writeln!(f, "-------------writing to file-------------"); + } + if let Err(e) = writeln!(f, "{}", log.to_string()) { + eprintln!("[!] Failed to write to file: {}", e); + } + Ok(()) +} + +fn gen_name() -> String { + let secs = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); + return format!("wowboombox{}", secs); +} + +pub fn read_irc_log(active_channel: String) -> String { + let mut s: String = String::new(); + let f = std::fs::File::open(crate::IRC_LOG); // ("unable to open irc log"); + if f.is_err() { return "".to_owned() } + if active_channel.len() > 0 { + let re = Regex::new(format!(r".*PRIVMSG {} :.*", active_channel).as_str()).unwrap(); + let reader = BufReader::new(f.unwrap()); + for line in reader.lines() { + if line.is_err() { continue } + let msg = line.unwrap(); + if re.is_match(msg.as_str()) { + s = s + "\n" + msg.as_str(); + } + } + } else { + let _ = f.unwrap().read_to_string(&mut s); + } + return s; +} + + +pub fn send_tune(&self) -> std::io::Result<()> { + let stream = connect()?; + thread::spawn(move || send_cmd(&stream, "PRIVMSG", "#wownero-music :!tune\r\n".to_owned())); + Ok(()) +} + +pub fn run(&self) -> Result { + let send_stream = connect()?; + let recv_stream = send_stream.try_clone()?; + // https://doc.rust-lang.org/nightly/std/thread/ + thread::spawn(move || receive(&recv_stream).expect("error setting up recv_stream")); + Ok(send_stream) +} \ No newline at end of file diff --git a/src/stats.rs b/deadcode/stats.rs similarity index 100% rename from src/stats.rs rename to deadcode/stats.rs diff --git a/src/tor.rs b/deadcode/tor.rs similarity index 100% rename from src/tor.rs rename to deadcode/tor.rs diff --git a/src/app.rs b/src/app.rs index dcce9cd..465e8f9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,51 +1,23 @@ -use std::time::{Duration, SystemTime}; -use std::net::TcpStream; use eframe::egui; use egui::FontFamily::Proportional; use egui::FontId; use egui::TextStyle::*; -use crate::player::Player; -use crate::tor::GuiTor; -use crate::stats::Market; -use crate::irc::Client as IRCClient; -use libtor::Error as libtorError; +use crate::node::Node; pub struct App { - pub player: Player, - pub market: Market, - pub irc: IRCClient, - pub tor_required: bool, - pub tor_started: bool, - pub tor_connected: bool, - pub to_data: String, - pub show_irc: bool, - pub irc_message: String, - pub irc_connected: bool, - pub show_market_data: bool, - pub show_radio: bool, - pub irc_stream: Option, - pub irc_last_ping: SystemTime, - pub irc_active_channel: String + pub node: Node, + pub node_running: bool, + pub show_node_logs: bool, + pub node_log: String } impl Default for App { fn default() -> Self { Self { - player: Player::default(), - market: Market::new(), - irc: IRCClient::new(), - tor_started: false, - tor_required: true, - tor_connected: false, - show_market_data: false, - show_irc: false, - irc_connected: false, - to_data: "".to_owned(), - irc_message: "".to_owned(), - show_radio: true, - irc_stream: None, - irc_last_ping: SystemTime::now(), - irc_active_channel: "#wownero-music".to_owned() + node: Node::default(), + node_running: false, + show_node_logs: false, + node_log: "".to_owned() } } } @@ -70,221 +42,229 @@ impl eframe::App for App { ctx.set_visuals(egui::Visuals::dark()); egui::TopBottomPanel::top("top").show(ctx, |ui| { - ui.heading("Wownero Operations Center"); + ui.heading("Wownero Node Center"); ui.label("Made by ya boi, lza_menace"); ui.hyperlink("https://lzahq.tech"); }); - egui::CentralPanel::default().show(ctx, |ui| { - ui.horizontal(|ui| { - ui.checkbox(&mut self.tor_required, "Require Tor"); - if (self.tor_connected && self.tor_required) || (! self.tor_required) { - ui.checkbox(&mut self.show_market_data, "Show Market Data"); - ui.checkbox(&mut self.show_irc, "Show IRC"); - } - ui.checkbox(&mut self.show_radio, "Show Radio"); - - }); + // Tor - if self.tor_required { - if self.tor_started { - ui.label( - egui::RichText::new( - format!( - "Tor Started: {} Tor Connected: {} Proxy Up: {}", - show_boolmoji(self.tor_started), - show_boolmoji(self.tor_connected), - show_boolmoji(self.tor_connected) - ) + // if self.tor_required { + // if self.node_running { + // ui.label( + // egui::RichText::new( + // format!( + // "Tor Started: {} Tor Connected: {} Proxy Up: {}", + // show_boolmoji(self.node_running), + // show_boolmoji(self.tor_connected), + // show_boolmoji(self.tor_connected) + // ) + // ) + // ); + // } else { + + // } + // } + + // node + if self.node_running { + ui.label( + egui::RichText::new( + format!( + "Node Started: {}", + show_boolmoji(self.node_running) ) - ); - } else { - if ui.button("Connect to the Tor network").clicked() { - let _t: std::thread::JoinHandle> = GuiTor::start_tor(); - self.tor_started = true; - self.tor_connected = true; - } + ) + ); + ui.horizontal(|ui| { + ui.checkbox(&mut self.show_node_logs, "Show Node Logs"); + }); + if self.show_node_logs { + egui::ScrollArea::vertical().stick_to_bottom(true).show(ui, |ui| { + // ui.label(self.irc.read_irc_log(self.irc_active_channel.clone())); + ui.horizontal(|ui| { + ui.text_edit_singleline(&mut self.node_log); + }); + // if ui.button("Clear IRC Log").clicked() { + // let _ = std::fs::File::create(crate::IRC_LOG); + // } + // if self.irc_last_ping.elapsed().unwrap() > Duration::from_secs(60) { + // let _ = crate::nodev2::send_cmd(&self.irc_stream.as_ref().unwrap(), "PING", format!("")); + // self.irc_last_ping = SystemTime::now(); + // } + }); + } + } else { + if ui.button("Start the node").clicked() { + self.node.start(); + self.node_running = true; } + ui.separator(); } - ui.separator(); + + // WOW!Radio - if self.show_radio { - ui.heading(egui::RichText::new("WOW!Radio").color(egui::Color32::WHITE)); - ui.label(egui::RichText::new("Your home for the most diabolical playlist of the century, made by the skeevers, scallywags, chupacabras, snails, and whores of the Wownero community. Join da chat to peep da scoop.\n").color(egui::Color32::WHITE)); - ui.horizontal(|ui| { - if self.player.playing { - if ui.button("⏸").clicked() { - let _ = self.player.sink.pause(); - self.player.playing = false; - } - // if ui.button("⏹").clicked() { - // let _ = self.player.sink.stop(); - // self.player.playing = false; - // let _ = std::fs::remove_file(crate::RADIO_STREAM); - // } - ui.add(egui::Slider::new(&mut self.player.volume, 0.0..=100.0)); - self.player.sink.set_volume(&self.player.volume / 100.0); - if self.player.sink.len() != 1 { - let f = std::fs::File::open(crate::RADIO_STREAM); - if let Ok(fo) = f { - let file = std::io::BufReader::new(fo); - let source = rodio::Decoder::new(file); - if source.is_err() { - return () - } - let _ = self.player.sink.append(source.unwrap()); - let _ = self.player.sink.play(); - } else { - return () - } - } - } else { - if ! self.tor_connected && self.tor_required { - ui.label("Connect to the Tor network first."); - } else { - if ui.button("▶").clicked() { - if ! self.tor_connected && self.tor_required { - return (); - } - // If stream thread is done, start again - if self.player.stream_thread.is_finished() { - self.player.stream_thread = self.player.start_radio_stream(self.tor_required); - } - let _ = self.player.sink.play(); - self.player.playing = true; - } - } + // if self.show_radio { + // ui.heading(egui::RichText::new("WOW!Radio").color(egui::Color32::WHITE)); + // ui.label(egui::RichText::new("Your home for the most diabolical playlist of the century, made by the skeevers, scallywags, chupacabras, snails, and whores of the Wownero community. Join da chat to peep da scoop.\n").color(egui::Color32::WHITE)); + // ui.horizontal(|ui| { + // if self.player.playing { + // if ui.button("⏸").clicked() { + // let _ = self.player.sink.pause(); + // self.player.playing = false; + // } + // // if ui.button("⏹").clicked() { + // // let _ = self.player.sink.stop(); + // // self.player.playing = false; + // // let _ = std::fs::remove_file(crate::RADIO_STREAM); + // // } + // } else { + // if ! self.tor_connected && self.tor_required { + // ui.label("Connect to the Tor network first."); + // } else { + // if ui.button("▶").clicked() { + // if ! self.tor_connected && self.tor_required { + // return (); + // } + // // If stream thread is done, start again + // if self.player.stream_thread.is_finished() { + // self.player.stream_thread = self.player.start_radio_stream(self.tor_required); + // } + // let _ = self.player.sink.play(); + // self.player.playing = true; + // } + // } - } - }); + // } + // }); - // Show spinner when downloading, along with file size - if ! self.player.stream_thread.is_finished() { - ui.horizontal(|ui| { - ui.spinner(); - let size: u64 = self.player.get_radio_size(); - ui.label(format!( - "{:?} -> {} ({} bytes)", - self.player.stream_source, - crate::RADIO_STREAM, - size - )); - }); - } + // // Show spinner when downloading, along with file size + // // if ! self.player.stream_thread.is_finished() { + // // ui.horizontal(|ui| { + // // ui.spinner(); + // // let size: u64 = self.player.get_radio_size(); + // // ui.label(format!( + // // "{:?} -> {} ({} bytes)", + // // self.player.stream_source, + // // crate::RADIO_STREAM, + // // size + // // )); + // // }); + // // } - // Show exif metadata when radio file available to read - if self.player.playing && self.player.get_radio_size() > 0 { - let rt = egui::RichText::new( - format!("\n{:?}", self.player.stream_exif)) - .color(egui::Color32::WHITE) - .size(18.0); - ui.label(rt); - let dur = self.player.exif_date.elapsed().unwrap(); - if dur > Duration::from_secs(15) { - self.player.exif_date = SystemTime::now(); - self.player.stream_exif = self.player.get_song_meta().unwrap(); - } - if ui.button(" +1 ").clicked() { - let _ = self.irc.send_tune(); - } - } - ui.separator(); - } + // // Show exif metadata when radio file available to read + // // if self.player.playing && self.player.get_radio_size() > 0 { + // // let rt = egui::RichText::new( + // // format!("\n{:?}", self.player.stream_exif)) + // // .color(egui::Color32::WHITE) + // // .size(18.0); + // // ui.label(rt); + // // let dur = self.player.exif_date.elapsed().unwrap(); + // // if dur > Duration::from_secs(15) { + // // self.player.exif_date = SystemTime::now(); + // // self.player.stream_exif = self.player.get_song_meta().unwrap(); + // // } + // // if ui.button(" +1 ").clicked() { + // // let _ = self.irc.send_tune(); + // // } + // // } + // ui.separator(); + // } - // IRC - if self.show_irc && ! self.irc_connected { - let i = self.irc.run(); - if i.is_ok() { - self.irc_stream = Some(i.unwrap()); - self.irc_connected = true; - } + // // IRC + // if self.show_node_logs && ! self.irc_connected { + // let i = self.irc.run(); + // if i.is_ok() { + // self.irc_stream = Some(i.unwrap()); + // self.irc_connected = true; + // } - } else if self.show_irc { - egui::ScrollArea::vertical().stick_to_bottom(true).show(ui, |ui| { - ui.label(self.irc.read_irc_log(self.irc_active_channel.clone())); - ui.horizontal(|ui| { - egui::ComboBox::from_label("") - .selected_text(format!("{}", self.irc_active_channel)) - .show_ui(ui, |ui| { - ui.selectable_value(&mut self.irc_active_channel, "".to_owned(), "system"); - ui.selectable_value(&mut self.irc_active_channel, "#wownero-music".to_owned(), "#wownero-music"); - ui.selectable_value(&mut self.irc_active_channel, "#wownero".to_owned(), "#wownero"); - } - ); - ui.text_edit_singleline(&mut self.irc_message); - if ui.button("> Send <").clicked() { - let res = crate::irc::send_cmd(&self.irc_stream.as_ref().unwrap(), "PRIVMSG", format!("{} :{}\r\n", self.irc_active_channel, self.irc_message)); - if res.is_ok() { - println!("wrote {} bytes to IRC: {}", res.unwrap(), self.irc_message); - let _ = crate::irc::write_log(format!("PRIVMSG {} :{}\r\n", self.irc_active_channel, self.irc_message).as_str(), false); - } else { - eprintln!("error: {:?}", res.err()); - } - self.irc_message = "".to_owned(); - } - }); - if ui.button("Clear IRC Log").clicked() { - let _ = std::fs::File::create(crate::IRC_LOG); - } - if self.irc_last_ping.elapsed().unwrap() > Duration::from_secs(60) { - let _ = crate::irc::send_cmd(&self.irc_stream.as_ref().unwrap(), "PING", format!("")); - self.irc_last_ping = SystemTime::now(); - } - }); - } + // } else if self.show_node_logs { + // egui::ScrollArea::vertical().stick_to_bottom(true).show(ui, |ui| { + // ui.label(self.irc.read_irc_log(self.irc_active_channel.clone())); + // ui.horizontal(|ui| { + // egui::ComboBox::from_label("") + // .selected_text(format!("{}", self.irc_active_channel)) + // .show_ui(ui, |ui| { + // ui.selectable_value(&mut self.irc_active_channel, "".to_owned(), "system"); + // ui.selectable_value(&mut self.irc_active_channel, "#wownero-music".to_owned(), "#wownero-music"); + // ui.selectable_value(&mut self.irc_active_channel, "#wownero".to_owned(), "#wownero"); + // } + // ); + // ui.text_edit_singleline(&mut self.node_log); + // if ui.button("> Send <").clicked() { + // let res = crate::nodev2::send_cmd(&self.irc_stream.as_ref().unwrap(), "PRIVMSG", format!("{} :{}\r\n", self.irc_active_channel, self.node_log)); + // if res.is_ok() { + // println!("wrote {} bytes to IRC: {}", res.unwrap(), self.node_log); + // let _ = crate::nodev2::write_log(format!("PRIVMSG {} :{}\r\n", self.irc_active_channel, self.node_log).as_str(), false); + // } else { + // eprintln!("error: {:?}", res.err()); + // } + // self.node_log = "".to_owned(); + // } + // }); + // if ui.button("Clear IRC Log").clicked() { + // let _ = std::fs::File::create(crate::IRC_LOG); + // } + // if self.irc_last_ping.elapsed().unwrap() > Duration::from_secs(60) { + // let _ = crate::nodev2::send_cmd(&self.irc_stream.as_ref().unwrap(), "PING", format!("")); + // self.irc_last_ping = SystemTime::now(); + // } + // }); + // } - // Market - if self.show_market_data { - egui::ComboBox::from_label("Pick currency base.") - .selected_text(format!("{}", self.market.denomination)) - .show_ui(ui, |ui| { - ui.selectable_value(&mut self.market.denomination, "sats".to_owned(), "sats"); - ui.selectable_value(&mut self.market.denomination, "usd".to_owned(), "usd"); - ui.selectable_value(&mut self.market.denomination, "eth".to_owned(), "eth"); - } - ); - if self.market.last_check_time.elapsed().unwrap() > Duration::from_secs(120) { - println!("[+] Refreshing WOW market data."); - self.market.store_market_data(self.tor_required); - self.market.last_check_time = SystemTime::now(); - } - if self.market.last_check_time.elapsed().unwrap() < Duration::from_secs(30) && self.market.read_json_from_file().len() == 0 { - ui.horizontal(|ui| { - ui.spinner(); - ui.label("Fetching market data..."); - }); - } - self.market.last_cg_data = self.market.read_json_from_file(); - let m = &self.market.last_cg_data; - let md = &m["market_data"]; - ui.horizontal_wrapped(|ui| { - ui.vertical(|ui| { - ui.label("Current Price"); - ui.heading(egui::RichText::new(md["current_price"][&self.market.denomination].to_string()).strong()); - ui.label("All-Time High"); - ui.heading(egui::RichText::new(md["ath"][&self.market.denomination].to_string()).strong()); - ui.label("All-Time Low"); - ui.heading(egui::RichText::new(md["atl"][&self.market.denomination].to_string()).strong()); - ui.label("Total Volume"); - ui.heading(egui::RichText::new(md["total_volume"][&self.market.denomination].to_string()).strong()); - ui.label("Market Cap"); - ui.heading(egui::RichText::new(md["market_cap"][&self.market.denomination].to_string()).strong()); - }); - ui.vertical(|ui| { - ui.label("PriceChg% (~24hrs)"); - ui.heading(egui::RichText::new(md["price_change_percentage_24h_in_currency"][&self.market.denomination].to_string()).strong()); - ui.label("PriceChg% (~7d)"); - ui.heading(egui::RichText::new(md["price_change_percentage_7d_in_currency"][&self.market.denomination].to_string()).strong()); - ui.label("PriceChg% (~14d)"); - ui.heading(egui::RichText::new(md["price_change_percentage_14d_in_currency"][&self.market.denomination].to_string()).strong()); - ui.label("PriceChg% (~30d)"); - ui.heading(egui::RichText::new(md["price_change_percentage_30d_in_currency"][&self.market.denomination].to_string()).strong()); - }); - }); - } + // // Market + // if self.show_market_data { + // egui::ComboBox::from_label("Pick currency base.") + // .selected_text(format!("{}", self.market.denomination)) + // .show_ui(ui, |ui| { + // ui.selectable_value(&mut self.market.denomination, "sats".to_owned(), "sats"); + // ui.selectable_value(&mut self.market.denomination, "usd".to_owned(), "usd"); + // ui.selectable_value(&mut self.market.denomination, "eth".to_owned(), "eth"); + // } + // ); + // if self.market.last_check_time.elapsed().unwrap() > Duration::from_secs(120) { + // println!("[+] Refreshing WOW market data."); + // self.market.store_market_data(self.tor_required); + // self.market.last_check_time = SystemTime::now(); + // } + // if self.market.last_check_time.elapsed().unwrap() < Duration::from_secs(30) && self.market.read_json_from_file().len() == 0 { + // ui.horizontal(|ui| { + // ui.spinner(); + // ui.label("Fetching market data..."); + // }); + // } + // self.market.last_cg_data = self.market.read_json_from_file(); + // let m = &self.market.last_cg_data; + // let md = &m["market_data"]; + // ui.horizontal_wrapped(|ui| { + // ui.vertical(|ui| { + // ui.label("Current Price"); + // ui.heading(egui::RichText::new(md["current_price"][&self.market.denomination].to_string()).strong()); + // ui.label("All-Time High"); + // ui.heading(egui::RichText::new(md["ath"][&self.market.denomination].to_string()).strong()); + // ui.label("All-Time Low"); + // ui.heading(egui::RichText::new(md["atl"][&self.market.denomination].to_string()).strong()); + // ui.label("Total Volume"); + // ui.heading(egui::RichText::new(md["total_volume"][&self.market.denomination].to_string()).strong()); + // ui.label("Market Cap"); + // ui.heading(egui::RichText::new(md["market_cap"][&self.market.denomination].to_string()).strong()); + // }); + // ui.vertical(|ui| { + // ui.label("PriceChg% (~24hrs)"); + // ui.heading(egui::RichText::new(md["price_change_percentage_24h_in_currency"][&self.market.denomination].to_string()).strong()); + // ui.label("PriceChg% (~7d)"); + // ui.heading(egui::RichText::new(md["price_change_percentage_7d_in_currency"][&self.market.denomination].to_string()).strong()); + // ui.label("PriceChg% (~14d)"); + // ui.heading(egui::RichText::new(md["price_change_percentage_14d_in_currency"][&self.market.denomination].to_string()).strong()); + // ui.label("PriceChg% (~30d)"); + // ui.heading(egui::RichText::new(md["price_change_percentage_30d_in_currency"][&self.market.denomination].to_string()).strong()); + // }); + // }); + // } }); } diff --git a/src/irc.rs b/src/irc.rs deleted file mode 100644 index 485ef0a..0000000 --- a/src/irc.rs +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright © 2019 Matthew Geary -// [This program is licensed under the "MIT License"] -// Please see the file LICENSE in the source -// distribution of this software for license terms. - -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::time::SystemTime; -use std::io::{prelude::*, BufReader}; -use std::collections::HashMap; -use std::net::TcpStream; -use std::str; -use std::thread; -use regex::Regex; - -///! A simple IRC client written in Rust. - -/// Returns a TcpStream connected to the desired server, with the given nickname -/// -/// # Arguments -/// -/// * `nick` - A string that holds the desired user nickname. -/// -/// # Example -/// -/// `let stream = connect(nick.to_owned()).unwrap();` -/// -fn connect() -> std::io::Result { - let nick = gen_name(); - // https://doc.rust-lang.org/std/net/struct.TcpStream.html - let send_stream = TcpStream::connect("irc.oftc.net:6667")?; - // let send_stream = connector.connect("irc.oftc.net", send_stream).expect("could not connect via tls"); - - // https://tools.ietf.org/html/rfc1459#section-4.1.1 - // https://github.com/hoodie/concatenation_benchmarks-rs - let nick_string = format!("{}\r\n", &nick); - let user_string = format!("{} * * {}\n\r", &nick, &nick); - - send_cmd(&send_stream, "USER", user_string)?; - send_cmd(&send_stream, "NICK", nick_string)?; - send_cmd(&send_stream, "JOIN", format!("#wownero\r\n"))?; - send_cmd(&send_stream, "JOIN", format!("#wownero-music\r\n"))?; - - Ok(send_stream) -} - -/// Writes a command to a given TcpStream -/// -/// # Arguments -/// -/// * `stream` - A mutable reference to a TcpStream -/// # `server` - A string that holds the desired message -/// -/// # Example -/// -/// `send_cmd(&send_stream, "QUIT", "\r\n".to_string())?;` -/// -pub fn send_cmd(mut stream: &TcpStream, cmd: &str, msg: String) -> Result { - let mut cmd = cmd.to_string(); - cmd.push_str(" "); - cmd.push_str(&msg); - println!("sending: {}", cmd.trim()); - stream.write(cmd.as_bytes()) -} - -/// Loops to recieve data from a TcpStream -/// -/// # Arguments -/// -/// * `stream` - A mutable reference to a TcpStream -/// -/// # Example -/// -/// The following example demonstrates how to set up a threaded TcpStream with one -/// stream reference listening and one receiving. -/// ``` -/// let send_stream = connect()?; -/// let recv_stream = send_stream.try_clone()?; -/// thread::spawn(move || receive(&recv_stream).expect("error setting up recv_stream")); -/// ``` -/// -fn receive(mut stream: &TcpStream) -> std::io::Result<()> { - let mut first_line: bool = true; - loop { - let mut buffer = Vec::new(); - let mut temp = [1]; - for _ in 0..512 { - stream.read_exact(&mut temp)?; - match temp[0] { - 0x1 => continue, // start of heading - 0xD => continue, // carriage return - 0xA => break, // line feed - _ => buffer.push(temp[0]), - } - } - let res_string = str::from_utf8(&buffer[..]); - match res_string { - Ok(r) => { - if !res_string.unwrap().is_empty() { - // if std::fs::File::open(crate::IRC_LOG).is_err() { - // let _ = std::fs::write(crate::IRC_LOG, ""); - // } - // let mut f = OpenOptions::new() - // .append(true) - // .open(crate::IRC_LOG) - // .unwrap(); - // if ! first_line { - // let _ = writeln!(f, "-------------writing to file-------------"); - // first_line = true; - // } - // if let Err(e) = writeln!(f, "{}", r.to_string()) { - // eprintln!("[!] Failed to write to file: {}", e); - // } - let _ = write_log(r, first_line); - first_line = false; - } - } - Err(error) => eprintln!("error while reading from tcp stream: {}", error), - } - } -} - -pub fn write_log(log: &str, first_line: bool) -> Result<(), std::io::Error> { - if std::fs::File::open(crate::IRC_LOG).is_err() { - let _ = std::fs::write(crate::IRC_LOG, ""); - } - let mut f = OpenOptions::new() - .append(true) - .open(crate::IRC_LOG) - .unwrap(); - if first_line { - let _ = writeln!(f, "-------------writing to file-------------"); - } - if let Err(e) = writeln!(f, "{}", log.to_string()) { - eprintln!("[!] Failed to write to file: {}", e); - } - Ok(()) -} - -/// Generates a friendly IRC nick string -/// -/// # Example -/// -/// ``` -/// let nick = gen_name(); // wowboombox1232348765 -/// ``` -/// -fn gen_name() -> String { - let secs = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); - return format!("wowboombox{}", secs); -} - -/// A client struct holds nickname, server, and command information as well as -/// implementing functions to connect to a server and issue commands. -pub struct Client { - /// Storing command data in a hashmap will supply the - /// user with accurate feedback - commands: HashMap, -} - -impl Client { - /// Returns a Client with a hashmap built with command data - /// - /// # Example - /// - /// `let client = Client::new();` - /// - pub fn new() -> Client { - let mut commands = HashMap::new(); - commands.insert("/quit".to_string(), "Command: /quit".to_string()); - commands.insert( - "/join".to_string(), - "Command: /join Parameters: ".to_string(), - ); - commands.insert( - "/part".to_string(), - "Command: /part Parameters: ".to_string(), - ); - commands.insert( - "/nick".to_string(), - "Command: /nick Parameters: ".to_string(), - ); - commands.insert( - "/msg".to_string(), - "Command: /msg Parameters: ".to_string(), - ); - commands.insert( - "/topic".to_string(), - "Command: /topic Parameters: []".to_string(), - ); - commands.insert( - "/list".to_string(), - "Command: /list Parameters: ".to_string(), - ); - commands.insert( - "/names".to_string(), - "Command: /names Parameters: ".to_string(), - ); - Client { - commands - } - } - - /// Returns an option specifying whether the given - /// command/message is valid. If the message is not valid, - /// the function prints information about the command to - /// the user and returns None. - /// - /// # Arguments - /// - /// * `params` - The minimum number of params needed for the command - /// * `msg` - The msg to verify - /// - /// # Example - /// - /// if let None = self.verify(2, &msg) { - /// continue - /// } - /// - pub fn verify(&self, params: usize, msg: &[&str]) -> Option<()> { - if msg.len() < params { - let msg = self.commands.get(msg[0].trim()).unwrap(); - println!("{}", msg); - return None; - } - Some(()) - } - - pub fn read_irc_log(&self, active_channel: String) -> String { - let mut s: String = String::new(); - let f = std::fs::File::open(crate::IRC_LOG); // ("unable to open irc log"); - if f.is_err() { return "".to_owned() } - if active_channel.len() > 0 { - let re = Regex::new(format!(r".*PRIVMSG {} :.*", active_channel).as_str()).unwrap(); - let reader = BufReader::new(f.unwrap()); - for line in reader.lines() { - if line.is_err() { continue } - let msg = line.unwrap(); - if re.is_match(msg.as_str()) { - s = s + "\n" + msg.as_str(); - } - } - } else { - let _ = f.unwrap().read_to_string(&mut s); - } - return s; - - } - - pub fn send_tune(&self) -> std::io::Result<()> { - let stream = connect()?; - thread::spawn(move || send_cmd(&stream, "PRIVMSG", "#wownero-music :!tune\r\n".to_owned())); - Ok(()) - } - - /// Creates a send and recv TcpStream (with the same socket) - /// spins recv to its own thread - /// main thread takes user input and matches it to commands - /// after commands and processed and messages verified, - /// the send stream is used to send command/message combinations. - pub fn run(&self) -> Result { - let send_stream = connect()?; - let recv_stream = send_stream.try_clone()?; - // https://doc.rust-lang.org/nightly/std/thread/ - thread::spawn(move || receive(&recv_stream).expect("error setting up recv_stream")); - Ok(send_stream) - - // Read the input. - // loop { - // let mut msg = String::new(); - // match io::stdin().read_line(&mut msg) { - // Ok(_) => { - // // https://users.rust-lang.org/t/how-to-split-a-string-by-and-then-print-first-or-last-component/23042 - // let mut msg: Vec<&str> = msg.trim().split(' ').collect(); - // let cmd: &str = msg[0].trim(); - // match cmd { - // "help" => { - // self.commands - // .iter() - // .for_each(|(_, val)| println!("{}", val)); - // } - // "/quit" => { - // send_cmd(&send_stream, "QUIT", "\r\n".to_string())?; - // println!("Quitting..."); - // return Ok(()); - // } - // "/join" => { - // if self.verify(2, &msg).is_none() { - // continue; - // } - // let msg = format!("{}\r\n", msg[1].trim()); - // send_cmd(&send_stream, "JOIN", msg)?; - // } - // "/part" => { - // if self.verify(2, &msg).is_none() { - // continue; - // } - // let msg = format!("{}\r\n", msg[1].trim()); - // send_cmd(&send_stream, "PART", msg)?; - // } - // "/nick" => { - // if self.verify(2, &msg).is_none() { - // continue; - // } - // let msg = format!("{}\r\n", msg[1].trim()); - // send_cmd(&send_stream, "NICK", msg)?; - // } - // "/msg" => { - // if self.verify(2, &msg).is_none() { - // continue; - // } - // let receiver = msg[1].trim(); - // msg.remove(0); - // msg.remove(0); - // let mut text = String::new(); - // msg.iter().for_each(|word| { - // text.push_str(word); - // text.push_str(" ") - // }); - // let text = text.trim(); - // let msg = format!("{} :{:?}\r\n", receiver, text); - // send_cmd(&send_stream, "PRIVMSG", msg)?; - // } - // "/list" => { - // let target = if msg.len() > 1 { msg[1].trim() } else { "" }; - // let msg = format!("{}\r\n", target); - // send_cmd(&send_stream, "LIST", msg)?; - // } - // "/names" => { - // let target = if msg.len() > 1 { msg[1].trim() } else { "" }; - // let msg = format!("{}\r\n", target); - // send_cmd(&send_stream, "NAMES", msg)?; - // } - // "/topic" => { - // if self.verify(3, &msg).is_none() { - // continue; - // } - // let msg = format!("{} {}\r\n", msg[1].trim(), msg[2].trim()); - // send_cmd(&send_stream, "NAMES", msg)?; - // } - // _ => { - // println!("Unrecognized command: {}", msg[0]); - // } - // } - // } - // Err(error) => eprintln!("error while reading user input: {}", error), - // } - // } - } -} - -// Parse command line arguments and use them create and run a client -// fn main() { -// // Process the arguments. -// let args: Vec = std::env::args().collect(); -// let mut nick: String; -// let mut server: String; - -// match args.len() { -// 3 => server = args[2].to_owned(), -// 2 => server = "irc.freenode.net".to_string(), -// _ => usage(), -// } - -// nick = args[1].to_owned(); -// let client = Client::new(nick, server); -// client.run().expect("Client Error"); -// } diff --git a/src/main.rs b/src/main.rs index 7175f77..58cfd2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,16 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -pub use crate::player::Player; +pub use crate::node::Node; pub use crate::app::App; mod app; -mod player; -mod tor; -mod stats; -mod irc; - -// "http://wowradiod6mhb4ignjqy5ghf5l42yh2yeumgeq3yi7gn7yqy3efhe5ad.onion" -// "http://wowradiof5wx62w4avdk5fwbvcoea2z4ul2q3awffn5vmfaa3vhlgiid.onion" -// "http://radio.poysibicsj73uhw7sjrv3fyopoyulrns4nlr5amyqdtafkqzlocd4qad.onion" -// "http://anonyradixhkgh5myfrkarggfnmdzzhhcgoy2v66uf7sml27to5n2tid.onion" -// "http://u2frppcgwqmoca7h3hu5l72upkwhcf2n6umrkqsnvnpahjynkre6sqyd.onion:8300/radio" -// "https://radio.wownero.com/wow.ogg" +mod node; pub const TOR_DATA: &str = &"/tmp/tor-rust"; pub const TOR_LOG: &str = &"/tmp/tor-rust/tor.log"; pub const RADIO_STREAM: &str = &"radio.ogg"; -pub const IRC_LOG: &str = &"irc.log"; +pub const NODE_LOG: &str = &"node.log"; fn cleanup() { let r: std::io::Result<()> = std::fs::remove_file(&RADIO_STREAM); @@ -30,14 +20,10 @@ fn cleanup() { } fn main() { - let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap(); - let sink: rodio::Sink = rodio::Sink::try_new(&stream_handle).unwrap(); - let player: player::Player = player::Player::new(sink, stream_handle); - let mut app: app::App = app::App::default(); - app.player = player; + let app: app::App = app::App::default(); let options: eframe::NativeOptions = eframe::NativeOptions::default(); eframe::run_native( - "lza gui", + "node gui", options, Box::new(|_cc| Box::new(app)), ); diff --git a/src/node.rs b/src/node.rs new file mode 100644 index 0000000..578c476 --- /dev/null +++ b/src/node.rs @@ -0,0 +1,122 @@ +use std::{io::{Read, BufReader}, process::{Command, Child}}; + +pub struct Node { + pub thread: std::thread::JoinHandle<()>, + pub running: bool +} + +impl Node { + pub fn new() -> Self { + Self { + thread: std::thread::spawn(|| {}), + running: false + } + } + + pub fn default() -> Self { + Self::new() + } + + pub fn start(&self) -> Child { + let cmd = Command::new("wownerod") + // .arg("--detach") + // .arg("--non-interactive") + .arg("--log-file") + .arg(crate::NODE_LOG) + .spawn() + .expect("failed"); + return cmd; + } + + // --detach + // --pidfile + // --non-interactive + // --log-file + // --log-level + // --max-log-file-size + + pub fn read_log() -> String { + let mut s: String = String::new(); + let f = std::fs::File::open(crate::NODE_LOG); // ("unable to open irc log"); + if f.is_err() { return "".to_owned() } + // let re = Regex::new(format!(r".*PRIVMSG {} :.*", active_channel).as_str()).unwrap(); + let reader = BufReader::new(f.unwrap()); + for line in reader.lines() { + if line.is_err() { continue } + let msg = line.unwrap(); + // if re.is_match(msg.as_str()) { + // s = s + "\n" + msg.as_str(); + // } + s = s + "\n" + msg.as_str() + } + return s; + } + + // pub fn start_radio_stream(&self, tor_required: bool) -> std::thread::JoinHandle<()> { + // let url = self.stream_source.clone(); + // let t: Result, std::io::Error> = std::thread::Builder::new().name("radio_stream".to_string()).spawn(move || { + // let mut client_builder = reqwest::blocking::Client::builder() + // .user_agent("WOC GUI + BoomBox"); + // if tor_required { + // let proxy = reqwest::Proxy::all("socks5://127.0.0.1:19050").unwrap(); + // client_builder = client_builder.proxy(proxy); + // } + // let mut res = client_builder.build() + // .unwrap() + // .get(url) + // .send() + // .unwrap(); + // let mut out: std::fs::File = std::fs::File::create(&crate::RADIO_STREAM).expect("failed to create file"); + // std::io::copy(&mut res, &mut out).expect("failed to copy content"); + // }); + // return t.unwrap() + // } + + // pub fn wait_for_source(&self) { + // loop { + // let r: Result = std::fs::File::open(&crate::RADIO_STREAM); + // if r.is_ok() { + // std::thread::sleep(std::time::Duration::from_secs(1)); + // return () + // } + // std::thread::sleep(std::time::Duration::from_secs(2)); + // } + // } + + // pub fn get_song_meta(&self) -> Option { + // let file = std::fs::File::open(&crate::RADIO_STREAM); + // if file.is_ok() { + // let mut buffer = vec![]; + // let file_size = file.unwrap().metadata().unwrap().len(); + // let chunk_size = 100000; + // let mut start_pos = if file_size < chunk_size { 0 } else { file_size - chunk_size }; + // let tries = file_size / chunk_size; + // for _i in 0..tries + 1 { + // // println!("Scanning radio stream: {} ({} bytes)\nTry: {}", &crate::RADIO_STREAM, file_size, _i); + // let mut f = std::fs::File::open(&crate::RADIO_STREAM).unwrap(); + // f.seek(std::io::SeekFrom::Start(start_pos)).unwrap(); + // f.take(chunk_size).read_to_end(&mut buffer).unwrap(); + // let s = std::string::String::from_utf8_lossy(&buffer); + // let re = regex::Regex::new(r"title=(.*).{4}server=").unwrap(); + // let caps = re.captures(&s); + // if caps.is_some() { + // // eat whatever the fuck you want - food moderation and other philosophies + // // im 63, i walk everyday, everyone can do that, if they want + // // if you're gonna drink, you gotta balance it out + // return Some(caps.unwrap().get(1).map_or("", |m| m.as_str()).to_owned()); + // } + // if start_pos < chunk_size { + // start_pos = 0; + // } else { + // start_pos -= chunk_size; + // } + // } + // } + // return Some("".to_owned()); + // } +} + + + + + diff --git a/src/player.rs b/src/player.rs deleted file mode 100644 index 9ea462d..0000000 --- a/src/player.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::{io::{Read, Seek}, time::SystemTime}; - -pub struct Player { - pub sink: rodio::Sink, - pub stream_thread: std::thread::JoinHandle<()>, - pub stream_handle: rodio::OutputStreamHandle, - pub stream_source: String, - pub stream_exif: String, - pub exif_date: SystemTime, - pub decode_err_date: SystemTime, - pub volume: f32, - pub playing: bool -} - -impl Player { - pub fn new(sink: rodio::Sink, stream_handle: rodio::OutputStreamHandle) -> Self { - Self { - sink, - stream_handle, - stream_thread: std::thread::spawn(|| {}), - stream_source: "https://radio.wownero.com/wow.ogg".to_owned(), - stream_exif: "".to_owned(), - exif_date: SystemTime::now(), - decode_err_date: SystemTime::now(), - volume: 100.0, - playing: false - } - } - - pub fn default() -> Self { - let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap(); - let sink = rodio::Sink::try_new(&stream_handle).unwrap(); - Self::new(sink, stream_handle) - } - - pub fn check_proxy(&self) -> bool { - let stream = std::net::TcpStream::connect("127.0.0.1:19050"); - return stream.is_ok() - } - - pub fn get_radio_size(&self) -> u64 { - let file = std::fs::File::open(crate::RADIO_STREAM); - if file.is_ok() { - return file.unwrap().metadata().unwrap().len(); - } else { - return 0; - } - } - - pub fn start_radio_stream(&self, tor_required: bool) -> std::thread::JoinHandle<()> { - let url = self.stream_source.clone(); - let t: Result, std::io::Error> = std::thread::Builder::new().name("radio_stream".to_string()).spawn(move || { - let mut client_builder = reqwest::blocking::Client::builder() - .user_agent("WOC GUI + BoomBox"); - if tor_required { - let proxy = reqwest::Proxy::all("socks5://127.0.0.1:19050").unwrap(); - client_builder = client_builder.proxy(proxy); - } - let mut res = client_builder.build() - .unwrap() - .get(url) - .send() - .unwrap(); - let mut out: std::fs::File = std::fs::File::create(&crate::RADIO_STREAM).expect("failed to create file"); - std::io::copy(&mut res, &mut out).expect("failed to copy content"); - }); - return t.unwrap() - } - - pub fn wait_for_source(&self) { - loop { - let r: Result = std::fs::File::open(&crate::RADIO_STREAM); - if r.is_ok() { - std::thread::sleep(std::time::Duration::from_secs(1)); - return () - } - std::thread::sleep(std::time::Duration::from_secs(2)); - } - } - - pub fn get_song_meta(&self) -> Option { - let file = std::fs::File::open(&crate::RADIO_STREAM); - if file.is_ok() { - let mut buffer = vec![]; - let file_size = file.unwrap().metadata().unwrap().len(); - let chunk_size = 100000; - let mut start_pos = if file_size < chunk_size { 0 } else { file_size - chunk_size }; - let tries = file_size / chunk_size; - for _i in 0..tries + 1 { - // println!("Scanning radio stream: {} ({} bytes)\nTry: {}", &crate::RADIO_STREAM, file_size, _i); - let mut f = std::fs::File::open(&crate::RADIO_STREAM).unwrap(); - f.seek(std::io::SeekFrom::Start(start_pos)).unwrap(); - f.take(chunk_size).read_to_end(&mut buffer).unwrap(); - let s = std::string::String::from_utf8_lossy(&buffer); - let re = regex::Regex::new(r"title=(.*).{4}server=").unwrap(); - let caps = re.captures(&s); - if caps.is_some() { - // eat whatever the fuck you want - food moderation and other philosophies - // im 63, i walk everyday, everyone can do that, if they want - // if you're gonna drink, you gotta balance it out - return Some(caps.unwrap().get(1).map_or("", |m| m.as_str()).to_owned()); - } - if start_pos < chunk_size { - start_pos = 0; - } else { - start_pos -= chunk_size; - } - } - } - return Some("".to_owned()); - } - - pub fn get_radio_source(&self) -> Result>, ()> { - // Self::wait_for_source(); - let f = std::fs::File::open(&crate::RADIO_STREAM); - if let Ok(fo) = f { - let file = std::io::BufReader::new(fo); - let source = rodio::Decoder::new(file).unwrap(); - return Ok(source) - } - Err(()) - } -} - - - - -