use crate::consts;
use crate::types::*;
use reqwest::blocking::Client;
use reqwest::blocking::ClientBuilder;
use reqwest::header;
use serde_json::from_str;
use std::any::type_name;
use std::collections::HashMap;
use std::env::var;
use std::fs::create_dir_all;
use std::fs::read_to_string;
use std::fs::remove_file;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
use url::Url;
pub fn get_defaults(playit_opts: Option<PlayItOpts>) -> Result<PlayIt, String> {
let os: OS = consts::OS;
let arch: Arch = if consts::ARCH == Arch::Unsupported {
return Err(String::from("Unsupported Architexture"));
} else {
consts::ARCH
};
let dir: PathBuf = Path::new(&if os == OS::Linux {
if var("XDG_CONFIG_HOME").is_err() {
format!("{}/.config/playit/", var("HOME").unwrap())
} else {
format!("{}/playit/", var("XDG_CONFIG_HOME").unwrap())
}
} else if os == OS::Windows {
format!("{}/playit/", var("AppData").unwrap())
} else {
format!(
"{}/Library/Application Support/playit/",
var("HOME").unwrap()
)
})
.to_owned();
let config_file: PathBuf = {
let path = dir.join("config.json");
remove_file(&path).ok();
path
};
let destroyed: bool = false;
let tunnels: Vec<Tunnel> = Vec::new();
let started: bool = false;
let used_packets: u8 = 0;
let free_packets: u8 = 0;
let connections: Vec<Connection> = Vec::new();
let version: String = String::from(consts::VERSION);
let download_urls: Binaries = Binaries {
win: Url::parse(&format!(
"https://playit.gg/downloads/playit-win_64-{}.exe",
version
))
.expect("Failed To Parse Download URL"),
lin: Url::parse(&format!(
"https://playit.gg/downloads/playit-linux_64-{}",
version
))
.expect("Failed To Parse Download URL"),
mac: Url::parse(&format!(
"https://playit.gg/downloads/playit-darwin_64-{}.zip",
version
))
.expect("Failed To Parse Download URL"),
arm64: Url::parse(&format!(
"https://playit.gg/downloads/playit-aarch64-{}",
version
))
.expect("Failed To Parse Download URL"),
arm: Url::parse(&format!(
"https://playit.gg/downloads/playit-armv7-{}",
version
))
.expect("Failed To Parse Download URL"),
};
let binary_type: BinaryType = consts::BINARY_TYPE;
let binary: PathBuf = download(&dir, &download_urls).expect("Failed To Download PlayIt");
let playit: Child = {
let mut env = HashMap::new();
env.insert(String::from("NO_BROWSER"), String::from("true"));
if playit_opts.clone().is_some() {
env.insert(
String::from("PREFERRED_TUNNEL"),
playit_opts
.clone()
.unwrap()
.PREFERRED_TUNNEL
.unwrap_or(String::from("")),
);
env.insert(
String::from("PREFERRED_THRESHOLD"),
playit_opts
.clone()
.unwrap()
.PREFERRED_THRESHOLD
.unwrap_or(50)
.to_string(),
);
env.insert(
String::from("NO_SPECIAL_LAN"),
playit_opts
.clone()
.unwrap()
.NO_SPECIAL_LAN
.unwrap_or(false)
.to_string(),
);
}
exec(String::from(binary.to_str().unwrap()), None, Some(env)).unwrap()
};
let output: Vec<String> = Vec::new();
let stdout: Vec<String> = Vec::new();
let stderr: Vec<String> = Vec::new();
let errors: Vec<String> = Vec::new();
let warnings: Vec<String> = Vec::new();
let (agent_key, server) = loop {
let config: Config = from_str::<Config>(
&read_to_string(&config_file).unwrap_or(String::from("{}")),
)
.unwrap_or(Config {
agent_key: None,
preferred_tunnel: None,
});
if config.agent_key.is_some() && config.preferred_tunnel.is_some() {
break (config.agent_key.unwrap(), config.preferred_tunnel.unwrap());
}
};
let req_client: Client = {
let mut headers: header::HeaderMap = header::HeaderMap::new();
let mut auth: header::HeaderValue =
header::HeaderValue::from_str(&format!("agent {}", agent_key)).unwrap();
auth.set_sensitive(true);
headers.insert(header::AUTHORIZATION, auth);
ClientBuilder::new()
.default_headers(headers)
.build()
.unwrap()
};
let api_path = Url::parse("https://api.playit.gg/").unwrap();
return Ok(PlayIt {
req_client,
os,
config_file,
arch,
dir,
destroyed,
tunnels,
agent_key,
started,
playit,
server,
used_packets,
free_packets,
connections,
version,
download_urls,
binary,
binary_type,
output,
stdout,
stderr,
errors,
warnings,
api_path,
});
}
pub fn exec(
cmd: String,
args: Option<Vec<String>>,
envs: Option<HashMap<String, String>>,
) -> Result<Child, String> {
let mut command: Command = Command::new(&cmd);
command
.args(args.unwrap_or(Vec::new()))
.envs(envs.unwrap_or(HashMap::new()))
.stdin(Stdio::piped())
.stderr(Stdio::piped())
.stdout(Stdio::piped());
#[cfg(target_os = "windows")]
{
use std::os::windows::process::CommandExt;
command.creation_flags(0x08000000);
}
let command: Child = Child(
command
.spawn()
.expect(&format!("Failed To Start Process: {}", &cmd)),
);
return Ok(command);
}
pub fn trim_newlines(string: &String) -> String {
return string.trim_end().replace('\n', " ").replace('\r', "");
}
pub fn download(dir: &PathBuf, download_urls: &Binaries) -> Result<PathBuf, String> {
let file: PathBuf = dir
.join(&format!(
"playit-{:#?}-{}.{}",
if consts::BINARY_TYPE == BinaryType::Unsupported {
return Err(String::from("Unsupported Architexture"));
} else {
consts::BINARY_TYPE
},
consts::VERSION,
String::from(if consts::OS == OS::Windows {
"exe"
} else if consts::OS == OS::Linux {
"bin"
} else {
"zip"
})
))
.to_owned();
if file.exists() {
return Ok(file);
}
if !file.parent().unwrap().exists() {
create_dir_all(file.parent().unwrap()).ok();
}
let mut _file: OpenOptions = OpenOptions::new();
_file.create(true).write(true).truncate(true);
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd"
))]
{
use std::os::unix::fs::OpenOptionsExt;
_file.mode(0o555);
}
let mut _file: File = _file.open(&file).unwrap();
_file
.write(
&reqwest::blocking::get(download_urls[consts::BINARY_TYPE].clone())
.unwrap()
.bytes()
.expect("Failed To Download PlayIt"),
)
.expect("Failed To Download PlayIt");
return Ok(file);
}
pub fn type_of<T>(_: &T) -> &str {
return type_name::<T>();
}