Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 61 additions & 10 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
daemon_changed: ${{ steps.files_changed.outputs.daemon_count != '0' }}
daemon_needed: ${{ steps.files_changed.outputs.daemon_count != '0' || steps.files_changed.outputs.installer_build != '0' }}
web_changed: ${{ steps.files_changed.outputs.web_count != '0' }}
docs_changed: ${{ steps.files_changed.outputs.docs_count != '0' }}
docs_changed: ${{ steps.files_changed.outputs.docs_count != '0' || steps.files_changed.outputs.daemon_count != '0' }}
installer_changed: ${{ steps.files_changed.outputs.installer_count != '0' }}
installer_gui_changed: ${{ steps.files_changed.outputs.installer_gui_count != '0' }}
rootshell_needed: ${{ steps.files_changed.outputs.rootshell_count != '0' || steps.files_changed.outputs.installer_build != '0' }}
Expand Down Expand Up @@ -84,40 +84,37 @@ jobs:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: Swatinem/rust-cache@v2
- name: Install mdBook
run: |
cargo install mdbook --no-default-features --features search --vers "^0.4" --locked
- name: Test mdBook
run: mdbook test

mdbook_publish:
name: Publish mdBook to Github Pages
mdbook_build:
name: Build mdBook for Github Pages
needs: mdbook_test
if: ${{ github.ref == 'refs/heads/main' }}
permissions:
pages: write
contents: write
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: Swatinem/rust-cache@v2
- name: Install mdBook
run: |
cargo install mdbook --no-default-features --features search --vers "^0.4" --locked
- name: Build mdBook
run: mdbook build

- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-artifact@v4
with:
name: book
path: book
- name: Deploy to Github Pages
uses: actions/deploy-pages@v4

check_and_test:
needs: files_changed
Expand Down Expand Up @@ -583,3 +580,57 @@ jobs:
rayhunter-v${{ env.VERSION }}-${{ matrix.platform }}.zip
rayhunter-v${{ env.VERSION }}-${{ matrix.platform }}.zip.sha256
if-no-files-found: error

openapi_build:
if: needs.files_changed.outputs.docs_changed == 'true'
needs:
- files_changed
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
with:
targets: armv7-unknown-linux-musleabihf
- uses: Swatinem/rust-cache@v2
- name: Build rayhunter-daemon openapi docs
run: |
mkdir -p daemon/web/build
touch daemon/web/build/{favicon.png,index.html.gz,rayhunter_orca_only.png,rayhunter_text.png}
cargo run --bin gen_api --features apidocs -- ./rayhunter-openapi.json
- name: Make swagger folder
run: |
mkdir api-docs
mv doc/swagger-ui.html api-docs/index.html
mv rayhunter-openapi.json api-docs/
- uses: actions/upload-artifact@v4
with:
name: api-docs
path: api-docs

github_pages_publish:
name: Upload new documentation to Github Pages
if: ${{ github.ref == 'refs/heads/main' }}
permissions:
pages: write
contents: write
id-token: write
needs:
- mdbook_build
- openapi_build
runs-on: ubuntu-latest
steps:
- name: Setup Pages
uses: actions/configure-pages@v4
- uses: actions/download-artifact@v4
- name: Organize pages into directory
run: cp -a api-docs book/
- name: Upload pages
uses: actions/upload-pages-artifact@v3
with:
path: book
- name: Deploy Github Pages
uses: actions/deploy-pages@v4
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@ version = "0.10.1"
edition = "2024"
rust-version = "1.88.0"

[lib]
name = "rayhunter_daemon"
path = "src/lib.rs"

[[bin]]
name = "gen_api"
path = "src/bin/gen_api.rs"
required-features = ["apidocs"]

[features]
default = ["rustcrypto-tls"]
rustcrypto-tls = ["reqwest/rustls-tls-webpki-roots-no-provider", "dep:rustls-rustcrypto"]
ring-tls = ["reqwest/rustls-tls-webpki-roots"]
apidocs = ["dep:utoipa"]

[dependencies]
rayhunter = { path = "../lib" }
Expand All @@ -32,3 +42,4 @@ anyhow = "1.0.98"
reqwest = { version = "0.12.20", default-features = false }
rustls-rustcrypto = { version = "0.0.2-alpha", optional = true }
async-trait = "0.1.88"
utoipa = { version = "5.4.0", optional = true }
29 changes: 29 additions & 0 deletions daemon/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,15 @@ impl AnalysisWriter {
}
}

/// The system status relating to QMDL file analysis
#[derive(Debug, Serialize, Clone)]
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
pub struct AnalysisStatus {
/// The vector array of queued files
queued: Vec<String>,
/// The file currently being analyzed
running: Option<String>,
/// The vector array of finished files
finished: Vec<String>,
}

Expand Down Expand Up @@ -215,6 +220,16 @@ pub fn run_analysis_thread(
});
}

#[cfg_attr(feature = "apidocs", utoipa::path(
get,
path = "/api/analysis",
tag = "Recordings",
responses(
(status = StatusCode::OK, description = "Success", body = AnalysisStatus)
),
summary = "Analysis status",
description = "Show analysis status for all QMDL files."
))]
pub async fn get_analysis_status(
State(state): State<Arc<ServerState>>,
) -> Result<Json<AnalysisStatus>, (StatusCode, String)> {
Expand All @@ -231,6 +246,20 @@ fn queue_qmdl(name: &str, analysis_status: &mut RwLockWriteGuard<AnalysisStatus>
true
}

#[cfg_attr(feature = "apidocs", utoipa::path(
post,
path = "/api/analysis/{name}",
tag = "Recordings",
responses(
(status = StatusCode::ACCEPTED, description = "Success"),
(status = StatusCode::INTERNAL_SERVER_ERROR, description = "Unable to queue analysis file")
),
params(
("name" = String, Path, description = "QMDL file to analyze")
),
summary = "Start analysis",
description = "Begin analysis of QMDL file {name}."
))]
pub async fn start_analysis(
State(state): State<Arc<ServerState>>,
Path(qmdl_name): Path<String>,
Expand Down
4 changes: 4 additions & 0 deletions daemon/src/battery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ pub mod wingtech;

const LOW_BATTERY_LEVEL: u8 = 10;

/// Device battery information
#[derive(Clone, Copy, PartialEq, Debug, Serialize)]
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
pub struct BatteryState {
/// The current level in percentage of the device battery
level: u8,
/// A boolean indicating whether the battery is currently being charged
is_plugged_in: bool,
}

Expand Down
12 changes: 12 additions & 0 deletions daemon/src/bin/gen_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use std::{env, fs};

fn main() {
let content = rayhunter_daemon::ApiDocs::generate();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is pub i wonder if having apidocs as a separate crate would simplify things.

i.e. apidocs crate depends on daemon with the apidocs feature, then you can use cfg(feature = "apidocs") everywhere to disable any code that is not necessary for compiling docs (see other comments)

this way the utoipa crate can also become an optional dependency gated behind that feature and the daemon binary does not explode in size.

#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting thought, though a bit over my head for implementing at the immediate moment. i definitely dont want to inflate the binary and take up space which could be used by recordings. ill look into this option.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introducing the cargo feature for apidocs can technically be done independently of moving the binary to a different crate. If you keep the binary where it is but featuregate all the code, you'd have to invoke the tool like this: cargo run --bin gen_api --features apidocs otherwise it won't compile

let mut filename = "openapi.json".to_string();
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
filename = args[1].to_string();
}

fs::write(filename, content).unwrap();
}
12 changes: 12 additions & 0 deletions daemon/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,30 @@ use rayhunter::analysis::analyzer::AnalyzerConfig;
use crate::error::RayhunterError;
use crate::notifications::NotificationType;

/// The structure of a valid rayhunter configuration
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
pub struct Config {
/// Path to store QMDL files
pub qmdl_store_path: String,
/// Listening port
pub port: u16,
/// Debug mode
pub debug_mode: bool,
/// Internal device name
pub device: Device,
/// UI level
pub ui_level: u8,
/// Colorblind mode
pub colorblind_mode: bool,
/// Key input mode
pub key_input_mode: u8,
/// ntfy.sh URL
pub ntfy_url: Option<String>,
/// Vector containing the types of enabled notifications
pub enabled_notifications: Vec<NotificationType>,
/// Vector containing the list of enabled analyzers
pub analyzers: AnalyzerConfig,
}

Expand Down
Loading