parent
937240a52f
commit
66b9552cd5
@ -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<usize, std::io::Error> {
|
||||||
|
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<TcpStream, std::io::Error> {
|
||||||
|
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)
|
||||||
|
}
|
@ -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<TcpStream> {
|
|
||||||
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<usize, std::io::Error> {
|
|
||||||
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<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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: <channel>".to_string(),
|
|
||||||
);
|
|
||||||
commands.insert(
|
|
||||||
"/part".to_string(),
|
|
||||||
"Command: /part Parameters: <channel>".to_string(),
|
|
||||||
);
|
|
||||||
commands.insert(
|
|
||||||
"/nick".to_string(),
|
|
||||||
"Command: /nick Parameters: <nickname>".to_string(),
|
|
||||||
);
|
|
||||||
commands.insert(
|
|
||||||
"/msg".to_string(),
|
|
||||||
"Command: /msg Parameters: <receiver>".to_string(),
|
|
||||||
);
|
|
||||||
commands.insert(
|
|
||||||
"/topic".to_string(),
|
|
||||||
"Command: /topic Parameters: <channel> [<topic>]".to_string(),
|
|
||||||
);
|
|
||||||
commands.insert(
|
|
||||||
"/list".to_string(),
|
|
||||||
"Command: /list Parameters: <channel>".to_string(),
|
|
||||||
);
|
|
||||||
commands.insert(
|
|
||||||
"/names".to_string(),
|
|
||||||
"Command: /names Parameters: <channel>".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<TcpStream, std::io::Error> {
|
|
||||||
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<String> = 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");
|
|
||||||
// }
|
|
@ -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::thread::JoinHandle<()>, 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, std::io::Error> = 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<String> {
|
||||||
|
// 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());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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::thread::JoinHandle<()>, 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, std::io::Error> = 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<String> {
|
|
||||||
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<rodio::Decoder<std::io::BufReader<std::fs::File>>, ()> {
|
|
||||||
// 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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in new issue