Merge branch 'release/V0.2.0_Alpha' into stable
This commit is contained in:
commit
110c6aad08
30 changed files with 2229 additions and 62 deletions
|
@ -1,4 +0,0 @@
|
|||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Wl,-rpath,$ORIGIN",
|
||||
]
|
27
.gitignore
vendored
27
.gitignore
vendored
|
@ -1,16 +1,13 @@
|
|||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
*
|
||||
!*/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
!Resources/*
|
||||
!.gitignore
|
||||
!src/**
|
||||
!res/HarmonyLinkLogo.ico
|
||||
!Resources/**
|
||||
!.github/**
|
||||
!Build.rs
|
||||
!Cargo.toml
|
||||
!Cargo.lock
|
||||
!LICENSE
|
||||
!README.md
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"rust-analyzer.linkedProjects": [
|
||||
".\\Cargo.toml",
|
||||
".\\Cargo.toml"
|
||||
]
|
||||
}
|
1589
Cargo.lock
generated
Normal file
1589
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
26
Cargo.toml
26
Cargo.toml
|
@ -1,7 +1,11 @@
|
|||
[package]
|
||||
name = "harmony_link_server"
|
||||
version = "1.0.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
authors = ["Jordon jordon@jordongamedev.co.uk"]
|
||||
homepage = "https://jordongamedev.co.uk"
|
||||
repository = "https://github.com/Jordonbc/HarmonyLinkServer"
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -12,9 +16,27 @@ lto = true # Enables link to optimizations
|
|||
opt-level = "z" # Optimize for binary size
|
||||
strip = true # Remove debug symbols
|
||||
|
||||
[package.metadata.winres]
|
||||
LegalCopyright = "Copyright © 2023 Jordon Brooks"
|
||||
ProductName = "HarmonyLink: Server"
|
||||
FileDescription = "Optimized games for your handheld!"
|
||||
|
||||
[[bin]]
|
||||
name = "harmony_link_server"
|
||||
path = "src/main.rs"
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "8.2.1", features = ["build", "cargo", "git", "gitcl", "rustc", "si"] }
|
||||
winres = "0.1.12"
|
||||
|
||||
[dependencies]
|
||||
libloading = "0.8.0"
|
||||
actix-web = "4.3.1"
|
||||
env_logger = "0.10.0"
|
||||
log = "0.4.18"
|
||||
serde = {version = "1.0.163", features = ["derive"]}
|
||||
serde_json = "1.0.96"
|
||||
sysinfo = "0.29.0"
|
||||
os_info = "3.0"
|
||||
battery = "0.7.8"
|
||||
lazy_static = "1.4.0"
|
||||
rusb = "0.9.2"
|
||||
|
|
11
Resources/dock_models.json
Normal file
11
Resources/dock_models.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
[
|
||||
{
|
||||
"brand": "JSAUX",
|
||||
"model": "HB0603",
|
||||
"usb_ids": [
|
||||
[ 4826, 21521 ],
|
||||
[ 4826, 1041 ],
|
||||
[ 4826, 33139 ]
|
||||
]
|
||||
}
|
||||
]
|
Binary file not shown.
Binary file not shown.
53
build.rs
53
build.rs
|
@ -1,14 +1,21 @@
|
|||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
use vergen::EmitBuilder;
|
||||
|
||||
fn copy_resources() -> Result<(), Box<dyn Error>> {
|
||||
// The directory of the Cargo manifest of the package that is currently being built.
|
||||
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not defined");
|
||||
|
||||
// The directory where the final binaries will be placed.
|
||||
let profile = env::var("PROFILE").expect("PROFILE is not defined");
|
||||
let out_dir = Path::new(&manifest_dir).join("target").join(profile);
|
||||
let profile = env::var("PROFILE")?;
|
||||
let out_dir = Path::new(&manifest_dir).join("target").join(profile).join("Resources");
|
||||
|
||||
if !out_dir.exists() {
|
||||
fs::create_dir(&out_dir)?;
|
||||
}
|
||||
|
||||
// The Resources directory.
|
||||
let resources_dir = Path::new(&manifest_dir).join("Resources");
|
||||
|
@ -19,17 +26,47 @@ fn main() {
|
|||
}
|
||||
|
||||
// Iterate over each entry in the Resources directory.
|
||||
for entry in fs::read_dir(resources_dir).expect("read_dir call failed") {
|
||||
let entry = entry.expect("entry is invalid");
|
||||
for entry in fs::read_dir(resources_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
// The destination path is the output directory plus the file name.
|
||||
let dest_path = out_dir.join(path.file_name().expect("file has no name"));
|
||||
// Copy the file.
|
||||
fs::copy(&path, &dest_path).expect("copy failed");
|
||||
fs::copy(&path, &dest_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
println!("cargo:rustc-env=RUSTFLAGS=-C link-arg=-Wl,-rpath,$ORIGIN");
|
||||
println!("cargo:rerun-if-changed=src/main.rs");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn windows_resource() -> Result<(), Box<dyn Error>> {
|
||||
let mut res = winres::WindowsResource::new();
|
||||
res.set_icon("res/HarmonyLinkLogo.ico");
|
||||
res.compile()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn windows_resource() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Emit the instructions
|
||||
EmitBuilder::builder()
|
||||
.all_build()
|
||||
.all_cargo()
|
||||
.all_git()
|
||||
.all_rustc()
|
||||
.all_sysinfo()
|
||||
.emit()?;
|
||||
|
||||
// Copy the Resources folder
|
||||
copy_resources()?;
|
||||
|
||||
windows_resource()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
BIN
res/HarmonyLinkLogo.ico
Normal file
BIN
res/HarmonyLinkLogo.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
14
src/api/api.rs
Normal file
14
src/api/api.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use actix_web::{HttpResponse, get, web};
|
||||
|
||||
use crate::version::info::Version;
|
||||
|
||||
#[get("/supported_versions")]
|
||||
pub async fn versions() -> HttpResponse {
|
||||
let version = Version::get();
|
||||
HttpResponse::Ok().json(&version.supported_api_versions)
|
||||
}
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(versions);
|
||||
// Register other version 1 handlers here...
|
||||
}
|
99
src/api/endpoints_v1.rs
Normal file
99
src/api/endpoints_v1.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
use actix_web::web;
|
||||
use actix_web::{HttpResponse, get};
|
||||
|
||||
use crate::v1::{docking, os, all_info, battery};
|
||||
use crate::version;
|
||||
|
||||
#[get("/are_you_there")]
|
||||
pub async fn heartbeat() -> HttpResponse {
|
||||
HttpResponse::Ok().body("yes")
|
||||
}
|
||||
|
||||
#[get("/all_info")]
|
||||
pub async fn get_all_info() -> HttpResponse {
|
||||
match all_info::stats::get_all_info() {
|
||||
Ok(info) => {
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
println!("Successfully got all info: {}", &info.clone().to_string());
|
||||
}
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("Failed to get all info: {}", 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) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
println!("Successfully got dock info: {}", &info.clone().to_string());
|
||||
}
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("Failed to get dock info: {}", err);
|
||||
HttpResponse::InternalServerError().body(format!("Failed to get dock info: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[get("/os_info")]
|
||||
pub async fn get_os_info() -> HttpResponse {
|
||||
match os::stats::get_os() {
|
||||
Ok(info) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
println!("Successfully got os info: {}", &info.clone().to_string());
|
||||
}
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("Failed to get os info: {}", 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) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
println!("Successfully got battery info: {}", &info.clone().to_string());
|
||||
}
|
||||
HttpResponse::Ok().json(&info)
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("Failed to get battery info: {}", err);
|
||||
HttpResponse::InternalServerError().body(format!("Failed to get battery info: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/version_info")]
|
||||
pub async fn get_version_info() -> HttpResponse {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
println!("Successfully got version info: {}", version::info::Version::get().to_string());
|
||||
}
|
||||
HttpResponse::Ok().json(&version::info::Version::get())
|
||||
}
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(heartbeat);
|
||||
cfg.service(get_all_info);
|
||||
cfg.service(get_dock_info);
|
||||
cfg.service(get_os_info);
|
||||
cfg.service(get_battery_info);
|
||||
cfg.service(get_version_info);
|
||||
// Register other version 1 handlers here...
|
||||
}
|
3
src/api/mod.rs
Normal file
3
src/api/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod server;
|
||||
mod endpoints_v1;
|
||||
mod api;
|
28
src/api/server.rs
Normal file
28
src/api/server.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use actix_web::{HttpServer, web};
|
||||
|
||||
use crate::api::endpoints_v1;
|
||||
use crate::api::api;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn stop_actix_web(server: actix_web::dev::Server) -> std::io::Result<()> {
|
||||
println!("Stopping server.");
|
||||
server.handle().stop(true).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start_actix_web(port: u16) -> std::io::Result<actix_web::dev::Server> {
|
||||
|
||||
println!("Starting webserver on 127.0.0.1:{}", port);
|
||||
|
||||
let server = HttpServer::new(move || {
|
||||
let logger = actix_web::middleware::Logger::default();
|
||||
actix_web::App::new()
|
||||
.wrap(logger)
|
||||
.service(web::scope("/api").configure(api::configure))
|
||||
.service(web::scope("/v1").configure(endpoints_v1::configure))
|
||||
})
|
||||
.bind(("127.0.0.1", port))?
|
||||
.run();
|
||||
|
||||
Ok(server)
|
||||
}
|
57
src/main.rs
57
src/main.rs
|
@ -1,34 +1,37 @@
|
|||
extern crate libloading;
|
||||
mod v1;
|
||||
|
||||
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 lib = unsafe { match libloading::Library::new(lib_path) {
|
||||
Ok(lib) => lib,
|
||||
Err(err) => {
|
||||
eprintln!("Error loading dynamic library: {}", err);
|
||||
return;
|
||||
},
|
||||
//#[cfg(debug_assertions)]
|
||||
{
|
||||
let version_info = Version::get();
|
||||
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!("API versions: {}", version_info.supported_api_versions_to_string());
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
println!("HarmonyLink ©️ Jordon Brooks 2023");
|
||||
|
||||
|
||||
let sys = actix_web::rt::System::new();
|
||||
sys.block_on(async {
|
||||
let result = api::server::start_actix_web(PORT).expect("err");
|
||||
|
||||
func();
|
||||
}
|
||||
let _ = result.await;
|
||||
});
|
||||
}
|
||||
|
|
2
src/v1/all_info/mod.rs
Normal file
2
src/v1/all_info/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod stats;
|
||||
pub mod structs;
|
18
src/v1/all_info/stats.rs
Normal file
18
src/v1/all_info/stats.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use crate::v1::docking;
|
||||
use crate::v1::battery;
|
||||
use crate::v1::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)
|
||||
}
|
24
src/v1/all_info/structs.rs
Normal file
24
src/v1/all_info/structs.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use crate::{v1::{os, battery, docking::{self, structs::DockInfo}}, version};
|
||||
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
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()
|
||||
}
|
||||
}
|
||||
pub fn to_string(self) -> String {
|
||||
serde_json::to_string(&self).expect("Failed to parse into string")
|
||||
}
|
||||
}
|
2
src/v1/battery/mod.rs
Normal file
2
src/v1/battery/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod stats;
|
||||
pub mod structs;
|
38
src/v1/battery/stats.rs
Normal file
38
src/v1/battery/stats.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use crate::v1::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)
|
||||
}
|
28
src/v1/battery/structs.rs
Normal file
28
src/v1/battery/structs.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq, Clone)]
|
||||
pub enum ChargingStatus {
|
||||
Charging,
|
||||
Battery,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
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
|
||||
}
|
||||
}
|
||||
pub fn to_string(self) -> String {
|
||||
serde_json::to_string(&self).expect("Failed to parse into string")
|
||||
}
|
||||
}
|
2
src/v1/docking/mod.rs
Normal file
2
src/v1/docking/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod stats;
|
||||
pub mod structs;
|
90
src/v1/docking/stats.rs
Normal file
90
src/v1/docking/stats.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
use std::{io::BufReader, fs::File};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{v1::{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 */
|
||||
#[allow(dead_code)]
|
||||
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())
|
||||
}
|
39
src/v1/docking/structs.rs
Normal file
39
src/v1/docking/structs.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
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![],
|
||||
}
|
||||
}
|
||||
pub fn to_string(self) -> String {
|
||||
serde_json::to_string(&self).expect("Failed to parse into string")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
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
|
||||
}
|
||||
}
|
||||
pub fn to_string(self) -> String {
|
||||
serde_json::to_string(&self).expect("Failed to parse into string")
|
||||
}
|
||||
}
|
4
src/v1/mod.rs
Normal file
4
src/v1/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod battery;
|
||||
pub mod docking;
|
||||
pub mod os;
|
||||
pub mod all_info;
|
2
src/v1/os/mod.rs
Normal file
2
src/v1/os/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod stats;
|
||||
pub mod structs;
|
45
src/v1/os/stats.rs
Normal file
45
src/v1/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)
|
||||
|
||||
}
|
38
src/v1/os/structs.rs
Normal file
38
src/v1/os/structs.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq, Clone)]
|
||||
pub enum Platform {
|
||||
WINDOWS = 0,
|
||||
LINUX = 1,
|
||||
MAC = 2,
|
||||
UNKNOWN = 255
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub enum Architecture {
|
||||
X86 = 0,
|
||||
X86_64 = 1,
|
||||
UNKNOWN = 255,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
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
|
||||
}
|
||||
}
|
||||
pub fn to_string(self) -> String {
|
||||
serde_json::to_string(&self).expect("Failed to parse into string")
|
||||
}
|
||||
}
|
41
src/version/info.rs
Normal file
41
src/version/info.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
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,
|
||||
pub supported_api_versions: Vec<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: "Alpha".to_string(),
|
||||
supported_api_versions: vec!["v1".to_string()]
|
||||
}
|
||||
}
|
||||
pub fn to_string(self) -> String {
|
||||
serde_json::to_string(&self).expect("Failed to parse into string")
|
||||
}
|
||||
pub fn supported_api_versions_to_string(self) -> String {
|
||||
self.supported_api_versions.join(", ")
|
||||
}
|
||||
|
||||
}
|
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