diff --git a/.github/workflows/temp-linux.yml b/.github/workflows/temp-linux.yml deleted file mode 100644 index 98f8cd2..0000000 --- a/.github/workflows/temp-linux.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: Build and upload artifact for Linux - -on: - workflow_dispatch: - push: - branches: - - main - -jobs: - release: - runs-on: ubuntu-latest - permissions: - contents: write - outputs: - release-id: ${{ steps.create-release.outputs.release_id }} - pkg-name: ${{ steps.get-package-info.outputs.pkg_name }} - bin-name: ${{ steps.get-package-info.outputs.bin_name }} - steps: - - uses: actions/checkout@v4 - - name: Get Package Name - id: get-package-info - run: | - pkg_name=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].name') - echo "Package Name: $pkg_name" - echo "pkg_name=$pkg_name" >> $GITHUB_ENV - echo "pkg_name=$pkg_name" >> "$GITHUB_OUTPUT" - - bin_name=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].targets[] | select(.kind[] == "bin" or .crate_types[] == "bin") | .name') - echo "Bin Name: $bin_name" - echo "bin_name=$bin_name" >> $GITHUB_ENV - echo "bin_name=$bin_name" >> "$GITHUB_OUTPUT" - shell: bash - - name: Create New Release - id: create-release - run: | - extn="$(date +%s)" - release_tag="v1-linux-prerelease-${extn}" - cargo_prerelease=("alpha" "beta" "rc") - prerelease=true - commit_msg="Release compiled executable for $release_tag" - release_data="{\"tag_name\":\"$release_tag\",\"name\":\"$release_tag\",\"body\":\"$commit_msg\",\"draft\":false,\"prerelease\":$prerelease}" - response=$(curl -X POST -H "Authorization: token ${{ secrets.GIT_TOKEN }}" \ - -d "$release_data" \ - "https://api.github.com/repos/${{ github.repository }}/releases") - - release_id=$(echo $response | jq -r .id) - echo "Release ID: $release_id" - echo "release_id=$release_id" >> "$GITHUB_OUTPUT" - shell: bash - - upload_assets: - needs: release - strategy: - matrix: - platform: - - release_for: Linux-x86_64 - os: ubuntu-20.04 - target: x86_64-unknown-linux-gnu - bin: ${{ needs.release.outputs.bin-name }} - name: ${{ needs.release.outputs.pkg-name }}-Linux-x86_64.tar.gz - command: build - - name: Upload asset for ${{ matrix.platform.release_for }} - runs-on: ${{ matrix.platform.os }} - permissions: - contents: write - - steps: - - name: Checkout Repo - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: 3.9 - - name: Update Rust - # print it with style - run: | - printf '*%.0s' {1..60} && printf "\n" - echo "Existing rust version: $(rustc --version)" - printf '*%.0s' {1..60} && printf "\n\n" - rustup update && printf "\n" - printf '*%.0s' {1..60} && printf "\n" - echo "Updated rust version: $(rustc --version)" - printf '*%.0s' {1..60} && printf "\n" - - - name: Install binary prerequisites - run: | - sudo apt-get install libssl-dev python3.9 libpython3.9-dev - export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:$LD_LIBRARY_PATH - - - name: Build and test - run: | - cargo build --release - cargo test - shell: bash - - - name: Verify Library Paths - run: ldd ./target/release/${{ matrix.platform.bin }} - - - name: Copy Artifacts - run: | - mkdir -p ${{ needs.release.outputs.pkg-name }} - cp target/release/${{ matrix.platform.bin }} ${{ needs.release.outputs.pkg-name }}/${{ matrix.platform.bin }} - tar -zcvf ${{ matrix.platform.name }} ${{ needs.release.outputs.pkg-name }}/ - shell: bash - - - name: Upload Asset to Release - run: | - curl -X POST -H "Authorization: token ${{ secrets.GIT_TOKEN }}" \ - -H "Content-Type: application/octet-stream" \ - --data-binary @"${{ matrix.platform.name }}" \ - "https://uploads.github.com/repos/${{ github.repository }}/releases/${{ needs.release.outputs.release-id }}/assets?name=${{ matrix.platform.name }}" - shell: bash diff --git a/Cargo.toml b/Cargo.toml index 3afd499..5d020e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,12 @@ path = "src/lib.rs" name = "rustream" path = "src/main.rs" -# [build] +# https://docs.rs/releases/queue +# https://docs.rs/about/metadata +# https://doc.rust-lang.org/cargo/reference/config.html?highlight=RUSTDOCFLAGS # export RUSTDOCFLAGS="document-private-items no-deps" -# rustdocflags = ["document-private-items no-deps"] +[package.metadata.docs.rs] +rustdoc-args = ["--document-private-items"] [dependencies] actix-rt = "2.9.0" diff --git a/README.md b/README.md index 78d8484..18c7154 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # RuStream -[![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-black?style=for-the-badge&logo=Rust)][rust] +[![made-with-rust][rust-logo]][rust-src-page] -[![build](https://github.com/thevickypedia/RuStream/actions/workflows/rust.yml/badge.svg)][build] +[![build][gh-logo]][build] +[![crates.io][crates-logo]][crates] +[![docs.rs][docs-logo]][docs] #### Summary -[`RuStream`][1] is an application written in Rust to stream videos using Actix API via authenticated sessions. +[`RuStream`][repo] is an application written in Rust to stream videos using Actix API via authenticated sessions. ## Usage @@ -63,7 +65,7 @@ async fn main() { - `--version` / `-v` - Get package version #### Config file -[RuStream][1] requires a JSON file with secrets loaded as key-value paris. +[RuStream][repo] requires a JSON file with secrets loaded as key-value paris.
Sample content of JSON file @@ -96,9 +98,16 @@ cargo clippy --no-deps --fix --allow-dirty © Vignesh Rao -Licensed under the [MIT License][2] +Licensed under the [MIT License][license] -[1]: https://github.com/thevickypedia/RuStream -[2]: https://github.com/thevickypedia/RuStream/blob/main/LICENSE +[repo]: https://github.com/thevickypedia/RuStream +[license]: https://github.com/thevickypedia/RuStream/blob/main/LICENSE [build]: https://github.com/thevickypedia/RuStream/actions/workflows/rust.yml -[rust]: https://www.rust-lang.org/ +[rust-src-page]: https://www.rust-lang.org/ +[rust-logo]: https://img.shields.io/badge/Made%20with-Rust-black?style=for-the-badge&logo=Rust +[gh-logo]: https://github.com/thevickypedia/RuStream/actions/workflows/rust.yml/badge.svg +[docs-logo]: https://docs.rs/RuStream/badge.svg +[docs]: https://docs.rs/RuStream +[crates]: https://crates.io/crates/RuStream +[gh-checks]: https://github.com/thevickypedia/RuStream/actions/workflows/rust.yml +[crates-logo]: https://img.shields.io/crates/v/RuStream.svg diff --git a/src/constant.rs b/src/constant.rs index d93a14a..079be49 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -1,19 +1,13 @@ -use std::{env, path}; +use std::env; use std::collections::HashMap; use std::sync::Mutex; use fernet::Fernet; use lazy_static::lazy_static; -pub fn get_binary() -> String { - let binary = env::args().next().unwrap(); - path::Path::new(&binary).file_name().unwrap().to_str().unwrap().to_string() -} - -/// Struct to store the cargo information +/// Struct to store the cargo information gathered at compile time using the `env!` macro. #[derive(Debug)] pub struct Cargo { - pub binary: String, pub crate_name: String, pub manifest_dir: String, pub authors: Vec, @@ -36,7 +30,6 @@ pub struct Cargo { /// - [GitHub Issues](https://github.com/rust-lang/cargo/issues/11966#issue-1664748892) pub fn build_info() -> Cargo { let cargo = Cargo { - binary: get_binary(), crate_name: env!("CARGO_CRATE_NAME").to_string(), manifest_dir: env!("CARGO_MANIFEST_DIR").to_string(), authors: env!("CARGO_PKG_AUTHORS").split(',').map(String::from).collect(), @@ -54,11 +47,16 @@ pub fn build_info() -> Cargo { } lazy_static! { - pub static ref FERNET: Fernet = Fernet::new(&generate_key()).unwrap(); + pub static ref FERNET: Fernet = Fernet::new(&fernet_key()).unwrap(); } /// Create a [Fernet](https://docs.rs/fernet/latest/fernet/) object to encrypt and decrypt session token. -fn generate_key() -> String { +/// +/// Generates a random key, that can be safely passed to `Fernet::new()` +/// +/// # Returns +/// Random key as a `String` +fn fernet_key() -> String { Fernet::generate_key() } diff --git a/src/lib.rs b/src/lib.rs index 9bba224..c4dc69d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,23 @@ +#![allow(rustdoc::bare_urls)] +#![doc = include_str!("../README.md")] + #[macro_use] extern crate actix_web; use std::io; use actix_web::{App, HttpServer, middleware, web}; -use rand::prelude::SliceRandom; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; +use rand::prelude::SliceRandom; -mod squire; -mod jinja; +/// Module to load all the static values and required structs during startup. mod constant; +/// Module to read the HTML files and load as Jinja templates. +mod jinja; +/// Module for all the API entry points. mod routes; +/// Module to store all the helper functions. +mod squire; /// Contains entrypoint and initializer settings to trigger the asynchronous HTTPServer /// @@ -33,8 +40,8 @@ pub async fn start() -> io::Result<()> { let cargo = constant::build_info(); let args = squire::parser::arguments(); - squire::startup::init_logger(args.debug, &cargo); - println!("{}[v{}] - {}", cargo.pkg_name, cargo.pkg_version, cargo.description); + squire::startup::init_logger(args.debug, &cargo.crate_name); + println!("{}[v{}] - {}", &cargo.pkg_name, &cargo.pkg_version, &cargo.description); let arts = [squire::ascii_art::DOG, squire::ascii_art::DOLPHIN, squire::ascii_art::HORSE]; println!("{}", arts.choose(&mut rand::thread_rng()).unwrap()); @@ -45,7 +52,7 @@ pub async fn start() -> io::Result<()> { let template_clone = template.clone(); let host = format!("{}:{}", config.video_host, config.video_port); log::info!("{} [workers:{}] running on http://{} (Press CTRL+C to quit)", - cargo.pkg_name, config.workers, host); + &cargo.pkg_name, &config.workers, &host); /* || syntax is creating a closure that serves as the argument to the HttpServer::new() method. The closure is defining the configuration for the Actix web server. @@ -75,16 +82,14 @@ pub async fn start() -> io::Result<()> { if config.cert_file.exists() && config.key_file.exists() { log::info!("Binding SSL certificate to serve over HTTPS"); let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file(&config.key_file, SslFiletype::PEM) - .unwrap(); + builder.set_private_key_file(&config.key_file, SslFiletype::PEM).unwrap(); builder.set_certificate_chain_file(&config.cert_file).unwrap(); server.bind_openssl(host, builder)? - .run() - .await + .run() + .await } else { server.bind(host)? - .run() - .await + .run() + .await } } diff --git a/src/routes/auth.rs b/src/routes/auth.rs index f5a1bc6..2494070 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -28,6 +28,11 @@ pub struct DetailError { /// /// * `config` - Configuration data for the application. /// * `request` - Actix HttpRequest containing information about the incoming request. +/// +/// # Returns +/// +/// * `200` - HttpResponse with a session-token and redirect URL to the `/home` entrypoint. +/// * `401` - HttpResponse with an error message for failed authentication. #[post("/login")] pub async fn login(config: web::Data>, request: HttpRequest) -> HttpResponse { let verified = routes::authenticator::verify_login(&request, &config); @@ -145,6 +150,10 @@ pub async fn home(config: web::Data>, /// # Arguments /// /// * `request` - Actix HttpRequest containing information about the incoming request. +/// +/// # Returns +/// +/// HttpResponse with either a session expiry or unauthorized message. #[get("/error")] pub async fn error(environment: web::Data>>>, request: HttpRequest) -> HttpResponse { diff --git a/src/routes/authenticator.rs b/src/routes/authenticator.rs index a88a5a5..f49d63e 100644 --- a/src/routes/authenticator.rs +++ b/src/routes/authenticator.rs @@ -143,7 +143,7 @@ pub fn verify_token(request: &HttpRequest, config: &Data config.session_duration as i64 { @@ -166,16 +168,20 @@ pub fn verify_token(request: &HttpRequest, config: &Data, // Path to the full certificate chain file for SSL certificate - #[serde(default="default_ssl")] + #[serde(default = "default_ssl")] pub cert_file: path::PathBuf, // Path to the private key file for SSL certificate - #[serde(default="default_ssl")] + #[serde(default = "default_ssl")] pub key_file: path::PathBuf } diff --git a/src/squire/startup.rs b/src/squire/startup.rs index 77606d2..78d40aa 100644 --- a/src/squire/startup.rs +++ b/src/squire/startup.rs @@ -1,7 +1,6 @@ use std::{env, path}; use std::sync::Arc; -use crate::constant::Cargo; use crate::squire::parser::Args; use crate::squire::settings::Config; @@ -11,18 +10,16 @@ use crate::squire::settings::Config; /// /// * `debug` - A flag indicating whether to enable debug mode for detailed logging. /// * `cargo` - A reference to the Cargo struct containing information about the application. -pub fn init_logger(debug: bool, cargo: &Cargo) { +pub fn init_logger(debug: bool, crate_name: &String) { if debug { env::set_var("RUST_LOG", format!( - "actix_web=debug,actix_server=info,{}=debug,{}=debug", - cargo.binary, cargo.crate_name + "actix_web=debug,actix_server=info,{}=debug", crate_name )); env::set_var("RUST_BACKTRACE", "1"); } else { // Set Actix logging to warning mode since it becomes too noisy when streaming a giant video file. env::set_var("RUST_LOG", format!( - "actix_web=warn,actix_server=warn,{}=info,{}=info", - cargo.binary, cargo.crate_name + "actix_web=warn,actix_server=warn,{}=info", crate_name )); env::set_var("RUST_BACKTRACE", "0"); }