diff --git a/.dockerignore b/.dockerignore index 8fb0cb0..4616c23 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,7 +4,7 @@ .github .vscode docs -target +# target tmp # Files diff --git a/.envrc b/.envrc deleted file mode 100644 index 4daf9df..0000000 --- a/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -export {{crate_name | shouty_snake_case}}_CONFIG=`pwd`/.config -export {{crate_name | shouty_snake_case}}_DATA=`pwd`/.data -export {{crate_name | shouty_snake_case}}_LOG_LEVEL=debug diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f4fb84f..0000000 --- a/.gitattributes +++ /dev/null @@ -1,5 +0,0 @@ -# Set the default behavior for all files. -* text=auto eol=lf - -# Normalized and converts to native line endings on checkout. -*.rs text diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5117f5b..92c3f6f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -10,6 +10,7 @@ jobs: name: Evaluate code coverage runs-on: ubuntu-latest steps: + - uses: extractions/setup-just@v1 - uses: actions/checkout@v3 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis diff --git a/.justfile b/.justfile index f6e26bf..b07e8bb 100644 --- a/.justfile +++ b/.justfile @@ -1,2 +1,80 @@ +set export + +export MUSL_TARGET_NAME := "ralertsinua-x86_64-unknown-linux-musl" +export MUSL_DIST := "target/distrib/'${MUSL_TARGET_NAME}'" +export RUST_LOG := "verbose" +export RUST_BACKTRACE := "1" + +# foo := if env_var("RELEASE") == "true" { `get-something-from-release-database` } else { "dummy-value" } + clean: - rm -rf tests/data/.task tests/data/.config + #!/bin/sh + find target -mindepth 1 -maxdepth 1 ! -name "debug" ! -name "tmp" -exec rm -rf {} + + +docs: + #!/bin/sh + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/oranda/releases/latest/download/oranda-installer.sh | sh + oranda build --config-path docs/oranda.render.json + +[confirm] +publish: + #!/bin/sh + # If crate A depends on crate B, B must come before A in this list + crates=( + ralertsinua-models + ralertsinua-http + ralertsinua-geo + ) + for crate in "${crates[@]}"; do + echo "Publishing ${crate}" + ( + cd "$crate" + cargo publish --no-verify + ) + sleep 20 + done + +[group('build')] +build target_env="gnu": + #!/bin/sh + echo "Building for target_env: ${target_env}" + if [ "{{target_env}}" = "musl" ]; then + # INFO: https://github.com/clux/muslrust?tab=readme-ov-file#filesystem-permissions-on-local-builds + # Filesystem permissions on local builds + # When building locally, the permissions of the musl parts of the ./target artifacts dir will be owned by root and requires sudo rm -rf target/ to clear. This is an intended complexity tradeoff with user builds. + docker run \ + -v cargo-cache:/root/.cargo/registry \ + -v "$PWD:/volume" \ + -e OPENSSL_LIB_DIR=/usr/lib \ + -e OPENSSL_INCLUDE_DIR=/usr/include \ + --rm -it clux/muslrust \ + cargo build --release --no-default-features --features cache,reqwest-rustls-tls + + # Create a directory for the files to be archived + mkdir -p $MUSL_DIST + cp target/x86_64-unknown-linux-musl/release/ralertsinua $MUSL_DIST + cp CHANGELOG.md LICENSE README.md $MUSL_DIST + tar -C target/distrib -cJf target/distrib/$MUSL_TARGET_NAME.tar.xz $MUSL_TARGET_NAME + else + cargo dist build + fi + + find ./target -type f -name 'ralertsinua' -exec du -sh {} \; + + +[group('run')] +run mode="dev": + #!/bin/sh + echo "Running with mode: ${mode}" + if [ "{{mode}}" = "prod" ]; then + if test -f ./target/release/ralertsinua; then + ./target/release/ralertsinua + else + echo "Binary not found. Run 'cargo build --release' first." + fi + elif [ "{{mode}}" = "ttyd" ]; then + docker build -f Dockerfile -t ralertsinua-ttyd . + docker run --env-file .env -p 7681:7681 --rm -it ralertsinua-ttyd:latest + else + cargo run + fi diff --git a/Cargo.toml b/Cargo.toml index 472c786..5c031e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,8 @@ build = "build.rs" # and we don't rely on it for debugging that much. debug = false -# [profile.release] -# panic = 'unwind' +[profile.release] +panic = 'unwind' # debug = true [workspace] @@ -52,9 +52,9 @@ installers = ["shell"] targets = [ "aarch64-apple-darwin", "x86_64-apple-darwin", - "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc", - # "x86_64-unknown-linux-musl", # TODO: doens't work with cargo-dist, use `sh tools/musl.sh` instead to manually build for musl + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", # INFO: musl is built using clux/muslrust ] # Publish jobs to run in CI pr-run-mode = "plan" @@ -62,7 +62,8 @@ pr-run-mode = "plan" install-updater = false # TODO: https://github.com/moonrepo/proto/blob/master/Cargo.toml#L71 -# [workspace.metadata.dist.github-custom-runners] +[workspace.metadata.dist.github-custom-runners] +x86_64-unknown-linux-musl = "clux/muslrust" # aarch64-unknown-linux-gnu = "buildjet-4vcpu-ubuntu-2204-arm" # aarch64-unknown-linux-musl = "buildjet-4vcpu-ubuntu-2204-arm" diff --git a/Dockerfile b/Dockerfile index 920e7c2..d490726 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,25 @@ FROM raonigabriel/web-terminal +# Set the OpenSSL lib directory +ENV OPENSSL_LIB_DIR=/usr/lib +ENV OPENSSL_INCLUDE_DIR=/usr/include + ENV RELEASE_URL=https://github.com/voiceapiai/ralertsinua/releases/latest/download/ralertsinua-x86_64-unknown-linux-musl.tar.xz ENV RUST_BACKTRACE=1 WORKDIR /home/ralertsinua -COPY ./tmp/ralertsinua . - -RUN mv ralertsinua /usr/local/bin +# COPY /target/x86_64-unknown-linux-musl/release # This is for local testing +# RUN mv ralertsinua /usr/local/bin # This is for local testing -# # Install the latest musl version of ralertsinua -# ADD $RELEASE_URL ralertsinua.tar.xz -# RUN tar -xvJf ralertsinua.tar.xz && \ -# find . -type f -name 'ralertsinua' -exec mv {} /usr/local/bin/ \; && \ -# rm ralertsinua.tar.xz +# Install the latest musl version of ralertsinua +ADD $RELEASE_URL ralertsinua.tar.xz +RUN tar -xvJf ralertsinua.tar.xz && \ + find . -type f -name 'ralertsinua' -exec mv {} /usr/local/bin/ \; && \ + rm ralertsinua.tar.xz HEALTHCHECK CMD ["ralertsinua", "--help"] # Comment this line if you don't need ttyd, and then just run ralertsina # CMD [ "ttyd", "-s", "3", "-t", "titleFixed=Rust alerts.in.ua TUI - ralertsinua", "-t", "rendererType=webgl", "-t", "disableLeaveAlert=true", "ralertsinua" ] CMD [ "ralertsinua" ] - -# TODO: https://github.com/colinmurphy1/docker-ttyd/blob/main/entrypoint.sh diff --git a/README.md b/README.md index b731935..064f795 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ curl --proto '=https' --tlsv1.2 -LsSf https://github.com/voiceapiai/ralertsinua/ ``` ### Download prebuilt binaries from the [releases page](https://github.com/voiceapiai/ralertsinua/releases/latest) +#### NOTE +Linux binaries compiled with musl and are light-weight, call straight into the kernel without other dynamic system library dependencies, can be shipped to most linux distributions without compatibility issues, and can be inserted as-is into lightweight docker images such as static distroless, scratch, or alpine. + ## Usage ⚠️ Before you can use this library, you need to obtain an API token by submitting an [API request form](https://alerts.in.ua/api-request). diff --git a/ralertsinua-http/src/client.rs b/ralertsinua-http/src/client.rs index ac00be8..ef2cc80 100644 --- a/ralertsinua-http/src/client.rs +++ b/ralertsinua-http/src/client.rs @@ -22,6 +22,11 @@ type Result = miette::Result; pub const API_BASE_URL: &str = "https://api.alerts.in.ua"; pub const API_VERSION: &str = "/v1"; pub const API_CACHE_SIZE: usize = 1000; +#[rustfmt::skip] +const CACHE_ENABLED_STR: &str = if cfg!(feature = "cache") { "enabled" } else { "disabled" }; + +const PKG: &str = env!("CARGO_PKG_NAME"); +const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); pub struct AlertsInUaClient { base_url: String, @@ -38,21 +43,21 @@ impl std::fmt::Debug for AlertsInUaClient { } impl AlertsInUaClient { - const APP_USER_AGENT: &'static str = - concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); - pub fn new(base_url: &str, token: &str) -> Self { let base_url = base_url.into(); let token = token.into(); let client = ClientBuilder::new() .timeout(std::time::Duration::from_secs(10)) - .user_agent(Self::APP_USER_AGENT) + .user_agent(USER_AGENT) .build() // building with these options cannot fail .unwrap(); + #[cfg(feature = "cache")] let cache_manager = Arc::new(CacheManagerQuick::new(API_CACHE_SIZE)); + log::debug!(target: PKG, "Caching is {}", CACHE_ENABLED_STR); + Self { base_url, token, @@ -101,11 +106,11 @@ impl AlertsInUaClient { // Configuring the request for the specific type (get/post/put/delete) req = add_data(req); // Finally performing the request and handling the response - log::trace!(target: env!("CARGO_PKG_NAME"), "Request {:?}", req); + log::trace!(target: PKG, "Request {:?}", req); let res: Response = req.send().await.inspect_err(|e| { - log::error!(target: env!("CARGO_PKG_NAME"), "Error making request: {:?}", e); + log::error!(target: PKG, "Error making request: {:?}", e); })?; - log::trace!(target: env!("CARGO_PKG_NAME"), "Response {:?}", res); + log::trace!(target: PKG, "Response {:?}", res); // Making sure that the status code is OK if let Err(err) = res.error_for_status_ref() { let err = match err.status() { @@ -130,7 +135,7 @@ impl AlertsInUaClient { let data: Bytes = match res.status() { #[cfg(feature = "cache")] StatusCode::NOT_MODIFIED => { - log::trace!(target: env!("CARGO_PKG_NAME"), "Response status '304 Not Modified', return cached data"); + log::trace!(target: PKG, "Response status '304 Not Modified', return cached data"); cached_data } _ => { diff --git a/tools/docs.sh b/tools/docs.sh deleted file mode 100644 index 802ed5c..0000000 --- a/tools/docs.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/oranda/releases/latest/download/oranda-installer.sh | sh -oranda build --config-path docs/oranda.render.json diff --git a/tools/install-from-release.sh b/tools/install-from-release.sh deleted file mode 100644 index 713e334..0000000 --- a/tools/install-from-release.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -set -euxo pipefail - -cd "$(mktemp -d)" - -base_url="https://github.com/voiceapiai/ralertsinua/releases/latest/download/ralertsinua-" - -os="$(uname -s)" -if [ "$os" == "Darwin" ]; then - url="${base_url}universal-apple-darwin.zip" - curl -LO --proto '=https' --tlsv1.2 -sSf "$url" - unzip ralertsinua-universal-apple-darwin.zip -elif [ "$os" == "Linux" ]; then - machine="$(uname -m)" - target="${machine}-unknown-linux-musl" - if [ "$machine" == "armv7" ]; then - target="${target}eabihf" - fi - - url="${base_url}${target}.tar.xz" - curl -L --proto '=https' --tlsv1.2 -sSf "$url" | tar -xvJf - --strip-components=1 -elif [ "${OS-}" = "Windows_NT" ]; then - machine="$(uname -m)" - target="${machine}-pc-windows-msvc" - url="${base_url}${target}.zip" - curl -LO --proto '=https' --tlsv1.2 -sSf "$url" - unzip "ralertsinua-${target}.zip" -else - echo "Unsupported OS ${os}" - exit 1 -fi - -# Find the 'ralertsinua' binary and move it to a directory in your PATH -find . -type f -name 'ralertsinua' -exec mv {} /usr/local/bin/ \; -# Install -# cargo binstall -y --force ./ralertsinua - -CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}" - -if ! [[ ":$PATH:" == *":$CARGO_HOME/bin:"* ]]; then - echo - printf "\033[0;31mYour path is missing %s, you might want to add it.\033[0m\n" "$CARGO_HOME/bin" - echo -fi diff --git a/tools/musl.sh b/tools/musl.sh deleted file mode 100644 index 02a4c5f..0000000 --- a/tools/musl.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -export TARGET_NAME="ralertsinua-x86_64-unknown-linux-musl" -export DIST="target/distrib/$TARGET_NAME" -# INFO: https://github.com/clux/muslrust?tab=readme-ov-file#filesystem-permissions-on-local-builds -# Filesystem permissions on local builds -# When building locally, the permissions of the musl parts of the ./target artifacts dir will be owned by root and requires sudo rm -rf target/ to clear. This is an intended complexity tradeoff with user builds. -docker run \ - -v cargo-cache:/root/.cargo/registry \ - -v "$PWD:/volume" \ - --rm -it clux/muslrust \ - cargo build --release --no-default-features --features cache,reqwest-rustls-tls -vv - # -e CARGO_FEATURE_REQWEST_RUSTLS_TLS=1 \ - # -e RUSTFLAGS=-Ctarget-feature=-crt-static \ - -# chown after docker changes permission to target folder -sudo chown -R $USER:$USER target - -# Create a directory for the files to be archived -mkdir -p $DIST - -# Copy the files into the directory -cp target/x86_64-unknown-linux-musl/release/ralertsinua $DIST -cp CHANGELOG.md LICENSE README.md $DIST - -# Create tzr.xz archive with name TARGET_NAME containing folder DIST -tar -C target/distrib -cJf target/distrib/$TARGET_NAME.tar.xz $TARGET_NAME diff --git a/tools/publish.sh b/tools/publish.sh deleted file mode 100644 index 7bf6e89..0000000 --- a/tools/publish.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# If crate A depends on crate B, B must come before A in this list -crates=( - ralertsinua-models - ralertsinua-http - ralertsinua-geo -) - -for crate in "${crates[@]}"; do - echo "Publishing ${crate}" - ( - cd "$crate" - cargo publish --no-verify - ) - sleep 20 -done - -# cargo publish diff --git a/ttyd.sh b/ttyd.sh deleted file mode 100644 index 9fb59d5..0000000 --- a/ttyd.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -# Build the Docker image -docker build -f Dockerfile -t ralertsinua-ttyd . - -# Run the Docker container with the environment variables -docker run --env-file .env -p 7681:7681 --rm -it ralertsinua-ttyd:latest