Removed DLL
Added All functions from DLL into HarmonyLinkServer
This commit is contained in:
parent
53773040d6
commit
0d5497be1c
27 changed files with 2146 additions and 64 deletions
18
src/api/all_info.rs
Normal file
18
src/api/all_info.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use crate::docking;
|
||||
use crate::battery;
|
||||
use crate::os;
|
||||
use crate::version;
|
||||
|
||||
use super::structs::Allinfo;
|
||||
|
||||
/* This will query all the modules and return all the combined data */
|
||||
pub fn get_all_info() -> Result<Allinfo, Box<dyn std::error::Error>> {
|
||||
let mut all_info = Allinfo::new();
|
||||
|
||||
all_info.dock = docking::stats::get_dock_info()?;
|
||||
all_info.battery = battery::stats::get_battery_info()?;
|
||||
all_info.os = os::stats::get_os()?;
|
||||
all_info.version = version::info::Version::get();
|
||||
|
||||
Ok(all_info)
|
||||
}
|
65
src/api/endpoints.rs
Normal file
65
src/api/endpoints.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use actix_web::{HttpResponse, get};
|
||||
|
||||
use crate::docking;
|
||||
use crate::version;
|
||||
use crate::battery;
|
||||
|
||||
#[get("/are_you_there")]
|
||||
pub async fn index() -> HttpResponse {
|
||||
HttpResponse::Ok().body("yes")
|
||||
}
|
||||
|
||||
#[get("/all_info")]
|
||||
pub async fn get_all_info() -> HttpResponse {
|
||||
match crate::api::all_info::get_all_info() {
|
||||
Ok(info) => {
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
HttpResponse::InternalServerError().body(format!("Failed to get device info: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/dock_info")]
|
||||
pub async fn get_dock_info() -> HttpResponse {
|
||||
match docking::stats::get_dock() {
|
||||
Ok(info) => {
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
HttpResponse::InternalServerError().body(format!("Failed to get dock info: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[get("/os_info")]
|
||||
pub async fn get_os_info() -> HttpResponse {
|
||||
match crate::os::stats::get_os() {
|
||||
Ok(info) => {
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
HttpResponse::InternalServerError().body(format!("Failed to get OS info: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/battery_info")]
|
||||
pub async fn get_battery_info() -> HttpResponse {
|
||||
match battery::stats::get_battery_info() {
|
||||
Ok(info) => {
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
HttpResponse::InternalServerError().body(format!("Failed to get battery info: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/version_info")]
|
||||
pub async fn get_version_info() -> HttpResponse {
|
||||
|
||||
HttpResponse::Ok().json(&version::info::Version::get())
|
||||
}
|
4
src/api/mod.rs
Normal file
4
src/api/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod server;
|
||||
mod endpoints;
|
||||
mod structs;
|
||||
mod all_info;
|
26
src/api/server.rs
Normal file
26
src/api/server.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use actix_web::HttpServer;
|
||||
|
||||
use crate::api::endpoints::*;
|
||||
|
||||
pub async fn start_actix_web(port: u16) -> std::io::Result<()> {
|
||||
|
||||
//std::env::set_var("RUST_LOG", "debug");
|
||||
//std::env::set_var("RUST_BACKTRACE", "1");
|
||||
|
||||
println!("Starting webserver on 127.0.0.1:{}", port);
|
||||
|
||||
HttpServer::new(move || {
|
||||
let logger = actix_web::middleware::Logger::default();
|
||||
actix_web::App::new()
|
||||
.wrap(logger)
|
||||
.service(index)
|
||||
.service(get_all_info)
|
||||
.service(get_os_info)
|
||||
.service(get_battery_info)
|
||||
.service(get_version_info)
|
||||
.service(get_dock_info)
|
||||
})
|
||||
.bind(("127.0.0.1", port))?
|
||||
.run()
|
||||
.await
|
||||
}
|
20
src/api/structs.rs
Normal file
20
src/api/structs.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use crate::{os, battery, docking::{self, structs::DockInfo}, version};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Allinfo {
|
||||
pub os: os::structs::OSInfo,
|
||||
pub battery: battery::structs::BatteryInfo,
|
||||
pub dock: docking::structs::DockInfo,
|
||||
pub version: version::info::Version
|
||||
}
|
||||
|
||||
impl Allinfo {
|
||||
pub fn new() -> Allinfo {
|
||||
Allinfo { os: os::structs::OSInfo::new(),
|
||||
battery: battery::structs::BatteryInfo::new(),
|
||||
dock: DockInfo::new(),
|
||||
version: version::info::Version::get()
|
||||
}
|
||||
}
|
||||
}
|
2
src/battery/mod.rs
Normal file
2
src/battery/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod stats;
|
||||
pub mod structs;
|
38
src/battery/stats.rs
Normal file
38
src/battery/stats.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use crate::battery::structs::ChargingStatus;
|
||||
|
||||
use super::structs::BatteryInfo;
|
||||
|
||||
pub fn get_battery_info() -> Result<BatteryInfo, Box<dyn std::error::Error>> {
|
||||
let mut battery_info = BatteryInfo { has_battery: false, battery_percent: 0, charging_status: ChargingStatus::UNKNOWN };
|
||||
|
||||
let manager = battery::Manager::new().unwrap();
|
||||
|
||||
battery_info.has_battery = manager.batteries().unwrap().count() > 0;
|
||||
|
||||
if !battery_info.has_battery {
|
||||
return Ok(battery_info);
|
||||
}
|
||||
|
||||
for (idx, battery) in manager.batteries()?.enumerate() {
|
||||
let battery = battery?;
|
||||
let state = battery.state();
|
||||
let energy = battery.energy();
|
||||
let full_energy = battery.energy_full();
|
||||
let state_of_charge = (energy / full_energy).get::<battery::units::ratio::percent>();
|
||||
|
||||
println!("Battery #{}:", idx);
|
||||
println!("Charging status: {:?}", state);
|
||||
println!("Charge level: {:.2}%", state_of_charge);
|
||||
|
||||
battery_info.battery_percent = state_of_charge.round() as i8;
|
||||
battery_info.charging_status = match state {
|
||||
battery::State::Charging => ChargingStatus::Charging,
|
||||
battery::State::Discharging => ChargingStatus::Battery,
|
||||
battery::State::Empty => ChargingStatus::Battery,
|
||||
battery::State::Full => ChargingStatus::Battery,
|
||||
_ => ChargingStatus::UNKNOWN,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(battery_info)
|
||||
}
|
25
src/battery/structs.rs
Normal file
25
src/battery/structs.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq)]
|
||||
pub enum ChargingStatus {
|
||||
Charging,
|
||||
Battery,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct BatteryInfo {
|
||||
pub has_battery: bool,
|
||||
pub battery_percent: i8,
|
||||
pub charging_status: ChargingStatus,
|
||||
}
|
||||
|
||||
impl BatteryInfo {
|
||||
pub fn new() -> BatteryInfo {
|
||||
BatteryInfo {
|
||||
has_battery: false,
|
||||
battery_percent: 0,
|
||||
charging_status: ChargingStatus::UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
2
src/docking/mod.rs
Normal file
2
src/docking/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod stats;
|
||||
pub mod structs;
|
86
src/docking/stats.rs
Normal file
86
src/docking/stats.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
use std::{io::BufReader, fs::File, collections::HashSet};
|
||||
|
||||
use crate::{battery::{stats::get_battery_info, structs::ChargingStatus}, USE_FALLBACK_DOCK_DETECTION};
|
||||
|
||||
use super::structs::{Dock, DockInfo};
|
||||
|
||||
/* This will get the current dock info. */
|
||||
pub fn get_dock_info() -> Result<DockInfo, Box<dyn std::error::Error>> {
|
||||
let mut dock = DockInfo::new();
|
||||
dock.dock_info = get_dock()?;
|
||||
|
||||
dock.is_docked = dock.dock_info.brand == String::new() && dock.dock_info.model == String::new();
|
||||
|
||||
/*
|
||||
This code will manually detect a dock if it wasn't automatically picked up by get_dock().
|
||||
The code currently doesnt work. To manually detect a dock we will detect the presence of
|
||||
a battery, charging of the handheld, and eventually when I find a cross-platform create,
|
||||
it will also detect the presence of an external monitor (will most likely only work on a
|
||||
Steam Deck for now)
|
||||
*/
|
||||
if USE_FALLBACK_DOCK_DETECTION {
|
||||
if !dock.is_docked {
|
||||
dock.fallback_detection = true;
|
||||
|
||||
let battery_info = get_battery_info()?;
|
||||
|
||||
if battery_info.has_battery && battery_info.charging_status == ChargingStatus::Charging {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(dock)
|
||||
}
|
||||
|
||||
/* Reads the dock_models.json file and returns a vector of structs with the data */
|
||||
pub fn read_dock_models_from_file() -> Result<Vec<Dock>, Box<dyn std::error::Error>> {
|
||||
let file = File::open("Resources/dock_models.json")?;
|
||||
let reader = BufReader::new(file);
|
||||
let dock_models: Vec<Dock> = serde_json::from_reader(reader)?;
|
||||
Ok(dock_models)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
/* This will detect the dock model and brand. */
|
||||
pub fn get_dock() -> Result<Dock, Box<dyn std::error::Error>> {
|
||||
let devices = rusb::devices()?;
|
||||
let dock_models = read_dock_models_from_file()?;
|
||||
|
||||
for dock_model in dock_models {
|
||||
let mut found_components = HashSet::new();
|
||||
|
||||
for device in devices.iter() {
|
||||
let device_desc = device.device_descriptor()?;
|
||||
let device_id = (device_desc.vendor_id(), device_desc.product_id());
|
||||
|
||||
// Check if the device is one of the components of the dock.
|
||||
if dock_model.usb_ids.contains(&[device_desc.vendor_id(), device_desc.product_id()]) {
|
||||
found_components.insert(device_id);
|
||||
println!("(get_dock) Detected: {}", serde_json::to_string_pretty(&device_id)?);
|
||||
}
|
||||
}
|
||||
|
||||
if found_components.len() == dock_model.usb_ids.len() {
|
||||
println!("(get_dock) All components detected for {}", serde_json::to_string_pretty(&dock_model)?);
|
||||
return Ok(Dock {
|
||||
model: dock_model.model.clone(),
|
||||
brand: dock_model.brand.clone(),
|
||||
usb_ids: dock_model.usb_ids.clone()
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(Dock::new())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
/* This will detect the dock model and brand. */
|
||||
pub fn get_dock() -> Result<Dock, Box<dyn std::error::Error>> {
|
||||
Ok(Dock::new())
|
||||
//Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "Incorrect OS")))
|
||||
}
|
||||
|
||||
/* This will detect the dock model and brand. */
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn get_dock() -> Result<Dock, Box<dyn std::error::Error>> {
|
||||
Ok(Dock::new())
|
||||
}
|
33
src/docking/structs.rs
Normal file
33
src/docking/structs.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Dock {
|
||||
pub brand: String, // ex: JSAUX
|
||||
pub model: String, // ex: HB0603
|
||||
pub usb_ids: Vec<[u16; 2]>,
|
||||
}
|
||||
|
||||
impl Dock {
|
||||
pub fn new() -> Dock {
|
||||
Dock { brand: String::new(),
|
||||
model: String::new(),
|
||||
usb_ids: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct DockInfo {
|
||||
pub dock_info: Dock,
|
||||
pub is_docked: bool,
|
||||
pub fallback_detection: bool,
|
||||
}
|
||||
|
||||
impl DockInfo {
|
||||
pub fn new() -> DockInfo {
|
||||
DockInfo { dock_info: Dock::new(),
|
||||
is_docked: false,
|
||||
fallback_detection: false
|
||||
}
|
||||
}
|
||||
}
|
60
src/main.rs
60
src/main.rs
|
@ -1,34 +1,36 @@
|
|||
extern crate libloading;
|
||||
mod battery;
|
||||
mod docking;
|
||||
mod os;
|
||||
|
||||
mod version;
|
||||
use version::info::Version;
|
||||
|
||||
mod api;
|
||||
|
||||
static PORT: u16 = 9000;
|
||||
|
||||
static USE_FALLBACK_DOCK_DETECTION: bool = false;
|
||||
|
||||
fn main() {
|
||||
// Use `cfg!` macro to detect OS
|
||||
let lib_path = if cfg!(target_os = "windows") {
|
||||
"harmony_link_core.dll"
|
||||
} else if cfg!(target_os = "linux") {
|
||||
"libharmony_link_core.so"
|
||||
} else {
|
||||
eprintln!("Unsupported OS");
|
||||
return;
|
||||
};
|
||||
let version_info = Version::get();
|
||||
|
||||
let lib = unsafe { match libloading::Library::new(lib_path) {
|
||||
Ok(lib) => lib,
|
||||
Err(err) => {
|
||||
eprintln!("Error loading dynamic library: {}", err);
|
||||
return;
|
||||
},
|
||||
}
|
||||
};
|
||||
println!("Version: {}", version_info.version);
|
||||
println!("Build Timestamp: {}", version_info.build_timestamp);
|
||||
println!("Git Branch: {}", version_info.git_branch);
|
||||
println!("Git Describe: {}", version_info.git_describe);
|
||||
println!("Git Commit Timestamp: {}", version_info.git_commit_timestamp);
|
||||
println!("Debug Build: {}", version_info.debug);
|
||||
println!("\n\n");
|
||||
|
||||
unsafe {
|
||||
let func: libloading::Symbol<unsafe extern "C" fn()> = match lib.get(b"start") {
|
||||
Ok(func) => func,
|
||||
Err(err) => {
|
||||
eprintln!("Error finding function in dynamic library: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
func();
|
||||
}
|
||||
println!("HarmonyLink ©️ Jordon Brooks 2023");
|
||||
|
||||
|
||||
let sys = actix_web::rt::System::new();
|
||||
sys.block_on(async {
|
||||
let result = api::server::start_actix_web (PORT).await;
|
||||
match result {
|
||||
Ok(_) => println!("Webserver started successfully."),
|
||||
Err(e) => println!("Error starting actix_web: {}", e),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
2
src/os/mod.rs
Normal file
2
src/os/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod stats;
|
||||
pub mod structs;
|
45
src/os/stats.rs
Normal file
45
src/os/stats.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use super::structs::{OSInfo, Platform, Architecture};
|
||||
|
||||
pub fn get_platform() -> Platform {
|
||||
if cfg!(target_os = "windows") {
|
||||
Platform::WINDOWS
|
||||
} else if cfg!(target_os = "macos") {
|
||||
Platform::MAC
|
||||
} else if cfg!(target_os = "linux") {
|
||||
Platform::LINUX
|
||||
} else {
|
||||
Platform::UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_os() -> Result<OSInfo, Box<dyn std::error::Error>> {
|
||||
let mut temp = OSInfo::new();
|
||||
let info = os_info::get();
|
||||
|
||||
temp.platform = get_platform();
|
||||
|
||||
temp.name = match info.codename() {
|
||||
Some(s) => s.to_string(),
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
temp.version = info.version().to_string();
|
||||
|
||||
if temp.name == String::new() {
|
||||
temp.name = match info.edition() {
|
||||
Some(s) => s.to_string(),
|
||||
_ => String::new(),
|
||||
};
|
||||
}
|
||||
|
||||
temp.bits = match info.bitness()
|
||||
{
|
||||
os_info::Bitness::X32 => Architecture::X86,
|
||||
os_info::Bitness::X64 => Architecture::X86_64,
|
||||
_ => Architecture::UNKNOWN,
|
||||
};
|
||||
|
||||
Ok(temp)
|
||||
|
||||
}
|
35
src/os/structs.rs
Normal file
35
src/os/structs.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum Platform {
|
||||
WINDOWS = 0,
|
||||
LINUX = 1,
|
||||
MAC = 2,
|
||||
UNKNOWN = 255
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum Architecture {
|
||||
X86 = 0,
|
||||
X86_64 = 1,
|
||||
UNKNOWN = 255,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct OSInfo {
|
||||
pub platform: Platform, // Windows, Mac, Linux
|
||||
pub name: String, // "Windows 11 2306", "Ubuntu 22.04 LTS"
|
||||
pub version: String, // 2306, 22.04
|
||||
pub bits: Architecture // 32, 64
|
||||
}
|
||||
|
||||
impl OSInfo {
|
||||
pub fn new() -> OSInfo {
|
||||
OSInfo {
|
||||
platform: Platform::UNKNOWN,
|
||||
name: String::new(),
|
||||
version: String::new(),
|
||||
bits: Architecture::UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
32
src/version/info.rs
Normal file
32
src/version/info.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Version {
|
||||
pub build_timestamp: String,
|
||||
pub git_branch: String,
|
||||
pub git_describe: String,
|
||||
pub git_commit_timestamp: String,
|
||||
pub debug: bool,
|
||||
pub version: String,
|
||||
pub version_major: i32,
|
||||
pub version_minor: i32,
|
||||
pub version_patch: i32,
|
||||
pub version_pre: String
|
||||
}
|
||||
|
||||
impl Version {
|
||||
pub fn get() -> Version {
|
||||
Version {
|
||||
build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(),
|
||||
git_branch: env!("VERGEN_GIT_BRANCH").to_string(),
|
||||
git_describe: env!("VERGEN_GIT_DESCRIBE").to_string(),
|
||||
git_commit_timestamp: env!("VERGEN_GIT_COMMIT_TIMESTAMP").to_string(),
|
||||
debug: env!("VERGEN_CARGO_DEBUG").parse().unwrap(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
version_major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
|
||||
version_minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
|
||||
version_patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
|
||||
version_pre: env!("CARGO_PKG_VERSION_PRE").parse().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
1
src/version/mod.rs
Normal file
1
src/version/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod info;
|
Loading…
Add table
Add a link
Reference in a new issue