diff --git a/pi/.gitignore b/pi/.gitignore deleted file mode 100644 index c1c6d40..0000000 --- a/pi/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/target -noisebell.service -/logs -.env \ No newline at end of file diff --git a/pi/Cargo.toml b/pi/Cargo.toml deleted file mode 100644 index bbcab7d..0000000 --- a/pi/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "noisebell" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow = "1.0" -tokio = { version = "1.45.1", features = ["full"] } -tracing = "0.1.41" -tracing-subscriber = "0.3.19" -rppal = "0.22.1" -serde = { version = "1.0.219", features = ["derive"] } -tracing-appender = "0.2.3" -axum = { version = "0.8.4", features = ["ws"] } -tower = "0.5.2" -tower-http = { version = "0.6.2", features = ["fs"] } -serde_json = "1.0.140" -regex = "1.11.1" -chrono = { version = "0.4.41", features = ["serde"] } -futures = "0.3.31" -futures-util = "0.3.31" -url = "2.5.4" -thiserror = "1.0" -reqwest = { version = "0.12", features = ["json"] } -toml = "0.9.5" -dotenvy = "0.15.7" diff --git a/pi/README.md b/pi/README.md deleted file mode 100644 index 0ae8078..0000000 --- a/pi/README.md +++ /dev/null @@ -1,180 +0,0 @@ -# Noisebell Logo Noisebell - -A switch monitoring system that detects circuit state changes via GPIO and notifies configured HTTP endpoints via POST requests. - -This is build by [Jet Pham][jetpham] to be used at Noisebridge to replace their old discord status bot - -## Features - -- GPIO circuit monitoring with configurable pin -- HTTP endpoint notifications via POST requests -- Daily rotating log files -- Cross-compilation support for Raspberry Pi deployment -- Software debouncing to prevent noisy switch detection -- Concurrent HTTP notifications for improved performance -- Comprehensive logging and error reporting -- Web-based monitor for testing (no physical hardware required) -- **Unified configuration system** with environment variable support - -## Configuration - -Noisebell uses environment variables for all configuration settings. Copy `env.example` to `.env` and modify the values as needed. - -### Environment Variables - -All configuration is handled through environment variables. Here are the available options: - -#### GPIO Configuration -- `NOISEBELL_GPIO_PIN` (default: 17) - GPIO pin number for circuit monitoring -- `NOISEBELL_GPIO_DEBOUNCE_DELAY_SECS` (default: 5) - Debounce delay in seconds - -#### Web Monitor Configuration -- `NOISEBELL_WEB_MONITOR_PORT` (default: 8080) - Port for web monitor server -- `NOISEBELL_WEB_MONITOR_ENABLED` (default: true) - Enable/disable web monitor - -#### Logging Configuration -- `NOISEBELL_LOGGING_LEVEL` (default: info) - Log level (trace, debug, info, warn, error) -- `NOISEBELL_LOGGING_FILE_PATH` (default: logs/noisebell.log) - Log file path -- `NOISEBELL_LOGGING_MAX_BUFFERED_LINES` (default: 10000) - Maximum buffered log lines - -#### Monitor Configuration -- `NOISEBELL_MONITOR_TYPE` (default: web) - Monitor type (gpio, web) - -#### Endpoint Configuration -- `NOISEBELL_ENDPOINT_URL` (default: https://noisebell.jetpham.com/api/status) - HTTP endpoint URL -- `ENDPOINT_API_KEY` (optional) - API key for Authorization header -- `NOISEBELL_ENDPOINT_TIMEOUT_SECS` (default: 30) - Request timeout in seconds -- `NOISEBELL_ENDPOINT_RETRY_ATTEMPTS` (default: 3) - Number of retry attempts - -### GPIO and Physical Tech - -We interact directly over a [GPIO pin in a pull-up configuration][gpio-pullup] to read whether a circuit has been closed with a switch. This is an extremely simple circuit that will internally call a callback function when the state of the circuit changes. - -When a state change is detected, the system: - -1. Logs the circuit state change -2. Sends HTTP POST requests to all configured endpoints -3. Reports success/failure statistics in the logs - -## Debouncing - -When a switch changes state, it can bounce and create multiple rapid signals. Debouncing adds a delay to wait for the signal to settle, ensuring we only detect one clean state change instead of multiple false ones. - -We do debouncing with software via [`set_async_interupt`][rppal-docs] which handles software debounce for us. - -### Logging - -Logs are stored in a single continuous log file in the `logs` directory - -### Endpoint Notifications - -When a circuit state change is detected, the system sends HTTP POST requests to the configured endpoint with the following JSON payload: - -```json -{ - "status": "open" -} -``` - -The status field will be either `"open"` or `"closed"` (lowercase). - -#### Endpoint Configuration - -The endpoint is configured using the environment variables listed above. If an API key is provided, it will be included in the `Authorization: Bearer ` header. - -### Web Monitor - -A web-based monitor is available for testing without physical hardware. When `NOISEBELL_WEB_MONITOR_ENABLED=true` (default), you can access the monitor at `http://localhost:8080` to manually trigger state changes and test the endpoint notification system. - -### Images - -
-Knife Switch -
-The knife switch used to detect circuit state changes -
- -
- -
-Raspberry Pi Closeup -
-Closeup view of the Raspberry Pi setup -
- -
- -
-Raspberry Pi with Porthole -
-The complete setup showing the Raspberry Pi mounted in a porthole -
- -## Development - -### Requirements - -- Rust toolchain (Install [Rust][rust-install]) -- Raspberry Pi (tested on [RP02W][rp02w]) -- `cross` for cross-compilation (Install [Cross][cross-install]) -- Internet connectivity (wifi for the rp02w) - -### Local Development (Web Monitor) - -For local development and testing, you can run the web-based monitor using the following command: - -```bash -# Copy the example environment file -cp env.example .env - -# Run the application -cargo run -``` - -This will start a web server on port 8080. Open your browser and go to [http://localhost:8080](http://localhost:8080) to interact with the web monitor. - -This is meant to replace the need for testing on an actual raspberry pi with gpio pins while keeping the terminal clean for logs. - -### Deployment - -The project includes a deployment script for Raspberry Pi. To deploy, run the deployment script: - -```bash -./deploy.sh -``` - -### Configuration Validation - -The application validates all configuration values on startup. If any configuration is invalid, the application will exit with a descriptive error message. Common validation checks include: - -- GPIO pin must be between 1-40 -- Debounce delay must be greater than 0 -- Monitor type must be either "gpio" or "web" -- Port numbers must be valid -- Log levels must be valid (trace, debug, info, warn, error) - -### Quick Start - -1. **Clone the repository:** - ```bash - git clone - cd noisebell - ``` - -2. **Set up environment variables:** - ```bash - cp env.example .env - # Edit .env with your configuration - ``` - -3. **Run the application:** - ```bash - cargo run - ``` - -[jetpham]: https://jetpham.com/ -[gpio-pullup]: https://raspberrypi.stackexchange.com/questions/4569/what-is-a-pull-up-resistor-what-does-it-do-and-why-is-it-needed -[rppal-docs]: https://docs.rs/rppal/latest/rppal/gpio/struct.InputPin.html#method.set_async_interrupt -[rust-install]: https://www.rust-lang.org/tools/install -[rp02w]: https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/ -[cross-install]: https://github.com/cross-rs/cross diff --git a/pi/configuration.nix b/pi/configuration.nix new file mode 100644 index 0000000..3609fd0 --- /dev/null +++ b/pi/configuration.nix @@ -0,0 +1,39 @@ +{ config, pkgs, ... }: + +{ + system.stateVersion = "24.11"; + + networking.hostName = "noisebell"; + + # Enable the noisebell service + services.noisebell = { + enable = true; + endpointUrl = "https://example.com/webhook"; # TODO: set your endpoint + }; + + # Basic system config + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + # Tailscale + services.tailscale.enable = true; + + # Caddy reverse proxy — proxies to the noisebell status endpoint + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:${toString config.services.noisebell.port} + ''; + }; + + services.openssh.enable = true; + + # Only allow traffic from Tailscale interface + networking.firewall = { + trustedInterfaces = [ "tailscale0" ]; + allowedUDPPorts = [ config.services.tailscale.port ]; + }; + + users.users.root.openssh.authorizedKeys.keys = [ + # TODO: add your SSH public key + ]; +} diff --git a/pi/deploy.sh b/pi/deploy.sh deleted file mode 100755 index af340b5..0000000 --- a/pi/deploy.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash - -# Exit on error -set -e - -echo "Building for Raspberry Pi..." -cross build --release --target aarch64-unknown-linux-gnu - -# Check if Discord credentials are already set -if [ -z "$DISCORD_TOKEN" ]; then - echo "Please enter your Discord bot token:" - read -s DISCORD_TOKEN -fi - -if [ -z "$DISCORD_CHANNEL_ID" ]; then - echo "Please enter your Discord channel ID:" - read -s DISCORD_CHANNEL_ID -fi - -# Create service file with credentials -cat > noisebell.service << EOL -[Unit] -Description=Noisebell Discord Notification Service -After=network.target - -[Service] -Type=simple -User=noisebridge -WorkingDirectory=/home/noisebridge -Environment=DISCORD_TOKEN=${DISCORD_TOKEN} -Environment=DISCORD_CHANNEL_ID=${DISCORD_CHANNEL_ID} -ExecStart=/home/noisebridge/noisebell -Restart=on-failure -RestartSec=10 - -[Install] -WantedBy=multi-user.target -EOL - -echo "Copying to Raspberry Pi..." -# Debug remote directory status -ssh noisebridge@noisebell.local "pwd && ls -la ~/ && echo 'Directory permissions:' && stat -c '%A %a %n' ~/" -# Remove existing files -ssh noisebridge@noisebell.local "rm -f /home/noisebridge/noisebell /home/noisebridge/noisebell.service" -# Copy files with absolute paths -scp -v target/aarch64-unknown-linux-gnu/release/noisebell noisebridge@noisebell.local:/home/noisebridge/noisebell -scp -v noisebell.service noisebridge@noisebell.local:/home/noisebridge/noisebell.service - -echo "Setting up service..." -# Deploy service -ssh noisebridge@noisebell.local "sudo cp /home/noisebridge/noisebell.service /etc/systemd/system/ && \ - sudo systemctl daemon-reload && \ - sudo systemctl enable noisebell && \ - sudo systemctl restart noisebell" - -# Clean up local service file -rm noisebell.service - -echo "Deployment complete!" -echo "You can check the service status with: ssh noisebridge@noisebell.local 'sudo systemctl status noisebell'" diff --git a/pi/env.example b/pi/env.example deleted file mode 100644 index d7eecb1..0000000 --- a/pi/env.example +++ /dev/null @@ -1,26 +0,0 @@ -# Environment variables for noisebell -# Copy this file to .env and modify as needed - -# GPIO Configuration -NOISEBELL_GPIO_PIN=17 -NOISEBELL_GPIO_DEBOUNCE_DELAY_SECS=5 - -# Web Monitor Configuration -NOISEBELL_WEB_MONITOR_PORT=8080 -NOISEBELL_WEB_MONITOR_ENABLED=true - -# Logging Configuration -NOISEBELL_LOGGING_LEVEL=info -NOISEBELL_LOGGING_FILE_PATH=logs/noisebell.log -NOISEBELL_LOGGING_MAX_BUFFERED_LINES=10000 - -# Monitor Configuration -NOISEBELL_MONITOR_TYPE=web - -# Endpoint Configuration -NOISEBELL_ENDPOINT_URL=https://noisebell.jetpham.com/api/status -NOISEBELL_ENDPOINT_TIMEOUT_SECS=30 -NOISEBELL_ENDPOINT_RETRY_ATTEMPTS=3 - -# API key for endpoint notifications (optional) -ENDPOINT_API_KEY=your_api_key_here diff --git a/pi/flake.nix b/pi/flake.nix new file mode 100644 index 0000000..170de1e --- /dev/null +++ b/pi/flake.nix @@ -0,0 +1,81 @@ +{ + description = "NixOS configuration for noisebell Pi"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + noisebell.url = "path:./pi-service"; + }; + + outputs = { self, nixpkgs, noisebell }: + let + nixosModule = { config, lib, pkgs, ... }: + let + cfg = config.services.noisebell; + in + { + options.services.noisebell = { + enable = lib.mkEnableOption "noisebell GPIO door monitor"; + + gpioPin = lib.mkOption { + type = lib.types.int; + default = 17; + description = "GPIO pin number to monitor."; + }; + + debounceSecs = lib.mkOption { + type = lib.types.int; + default = 5; + description = "Debounce delay in seconds."; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 8080; + description = "HTTP port for the status endpoint."; + }; + + endpointUrl = lib.mkOption { + type = lib.types.str; + description = "URL to POST state changes to."; + }; + + }; + + config = lib.mkIf cfg.enable { + systemd.services.noisebell = { + description = "Noisebell GPIO door monitor"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + + environment = { + NOISEBELL_GPIO_PIN = toString cfg.gpioPin; + NOISEBELL_DEBOUNCE_SECS = toString cfg.debounceSecs; + NOISEBELL_PORT = toString cfg.port; + NOISEBELL_ENDPOINT_URL = cfg.endpointUrl; + }; + + serviceConfig = { + ExecStart = "${noisebell.packages.aarch64-linux.default}/bin/noisebell"; + Restart = "on-failure"; + RestartSec = 5; + DynamicUser = true; + SupplementaryGroups = [ "gpio" ]; + }; + }; + }; + }; + in + { + nixosModules.default = nixosModule; + + nixosConfigurations.pi = nixpkgs.lib.nixosSystem { + system = "aarch64-linux"; + modules = [ + nixosModule + ./configuration.nix + ./hardware-configuration.nix + ]; + }; + }; +} diff --git a/pi/hardware-configuration.nix b/pi/hardware-configuration.nix new file mode 100644 index 0000000..35dd3ad --- /dev/null +++ b/pi/hardware-configuration.nix @@ -0,0 +1,22 @@ +{ config, lib, pkgs, modulesPath, ... }: + +{ + # TODO: Replace this file with the output of `nixos-generate-config --show-hardware-config` + # on your Raspberry Pi, or use an appropriate hardware module. + # + # Example for Raspberry Pi 4: + # + # imports = [ "${modulesPath}/installer/sd-card/sd-image-aarch64.nix" ]; + # + # hardware.enableRedistributableFirmware = true; + + imports = [ ]; + + boot.loader.grub.enable = false; + boot.loader.generic-extlinux-compatible.enable = true; + + fileSystems."/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + }; +} diff --git a/pi/media/closed.png b/pi/media/closed.png deleted file mode 100644 index fa6bff1..0000000 Binary files a/pi/media/closed.png and /dev/null differ diff --git a/pi/media/noisebell knifeswitch.jpg b/pi/media/noisebell knifeswitch.jpg deleted file mode 100644 index 1271dd6..0000000 Binary files a/pi/media/noisebell knifeswitch.jpg and /dev/null differ diff --git a/pi/media/noisebell logo.ico b/pi/media/noisebell logo.ico deleted file mode 100644 index b9f31a3..0000000 Binary files a/pi/media/noisebell logo.ico and /dev/null differ diff --git a/pi/media/noisebell logo.svg b/pi/media/noisebell logo.svg deleted file mode 100644 index 27d17c8..0000000 --- a/pi/media/noisebell logo.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pi/media/noisebell raspberrypi closeup.jpg b/pi/media/noisebell raspberrypi closeup.jpg deleted file mode 100644 index ec7bfff..0000000 Binary files a/pi/media/noisebell raspberrypi closeup.jpg and /dev/null differ diff --git a/pi/media/noisebell raspberrypi with porthole.jpg b/pi/media/noisebell raspberrypi with porthole.jpg deleted file mode 100644 index b947642..0000000 Binary files a/pi/media/noisebell raspberrypi with porthole.jpg and /dev/null differ diff --git a/pi/media/open.png b/pi/media/open.png deleted file mode 100644 index 8a9bbd9..0000000 Binary files a/pi/media/open.png and /dev/null differ diff --git a/pi/.cargo/config.toml b/pi/pi-service/.cargo/config.toml similarity index 100% rename from pi/.cargo/config.toml rename to pi/pi-service/.cargo/config.toml diff --git a/pi/Cargo.lock b/pi/pi-service/Cargo.lock similarity index 56% rename from pi/Cargo.lock rename to pi/pi-service/Cargo.lock index a11a540..b0929ab 100644 --- a/pi/Cargo.lock +++ b/pi/pi-service/Cargo.lock @@ -2,50 +2,11 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "atomic-waker" @@ -53,20 +14,13 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - [[package]] name = "axum" -version = "0.8.4" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", - "base64", "bytes", "form_urlencoded", "futures-util", @@ -81,15 +35,12 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", - "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite", "tower", "tower-layer", "tower-service", @@ -98,9 +49,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", @@ -109,28 +60,12 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - [[package]] name = "base64" version = "0.22.1" @@ -139,60 +74,37 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" -version = "3.18.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.26" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "core-foundation" @@ -205,69 +117,20 @@ dependencies = [ ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ + "core-foundation-sys", "libc", ] [[package]] -name = "crossbeam-channel" -version = "0.5.15" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "displaydoc" @@ -280,12 +143,6 @@ dependencies = [ "syn", ] -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - [[package]] name = "encoding_rs" version = "0.8.35" @@ -303,12 +160,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -317,12 +174,24 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -340,146 +209,81 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", - "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", - "pin-utils", "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", + "wasip3", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "h2" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -496,18 +300,32 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -534,12 +352,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" - [[package]] name = "httparse" version = "1.10.1" @@ -554,13 +366,14 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http", "http-body", @@ -568,6 +381,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -607,14 +421,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -631,35 +444,11 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -670,9 +459,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -683,11 +472,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -698,42 +486,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -742,10 +526,16 @@ dependencies = [ ] [[package]] -name = "idna" -version = "1.0.3" +name = "id-arena" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -764,25 +554,27 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -790,15 +582,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -811,38 +603,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "libc" -version = "0.2.172" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "matchit" @@ -852,9 +649,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mime" @@ -862,41 +659,22 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", @@ -915,58 +693,22 @@ version = "0.1.0" dependencies = [ "anyhow", "axum", - "chrono", - "dotenvy", - "futures", - "futures-util", - "regex", "reqwest", "rppal", "serde", "serde_json", - "thiserror 1.0.69", "tokio", - "toml", - "tower", - "tower-http", "tracing", - "tracing-appender", "tracing-subscriber", - "url", ] [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", + "windows-sys 0.61.2", ] [[package]] @@ -977,9 +719,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ "bitflags", "cfg-if", @@ -1003,15 +745,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -1019,17 +761,11 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1037,28 +773,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-link", ] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -1074,124 +810,61 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ - "zerocopy", + "proc-macro2", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.3", -] +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - [[package]] name = "reqwest" -version = "0.12.22" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64", "bytes", @@ -1235,7 +908,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -1250,30 +923,24 @@ dependencies = [ "libc", ] -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.29" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "once_cell", "rustls-pki-types", @@ -1284,18 +951,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring", "rustls-pki-types", @@ -1304,23 +971,23 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1331,12 +998,12 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -1344,28 +1011,44 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", ] [[package]] -name = "serde" -version = "1.0.219" +name = "semver" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -1374,33 +1057,26 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" -dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -1415,17 +1091,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -1443,21 +1108,19 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -1467,19 +1130,19 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.10" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "subtle" @@ -1489,9 +1152,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1520,12 +1183,12 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -1541,103 +1204,31 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.20.0" +version = "3.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows-sys 0.61.2", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", ] [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1645,11 +1236,10 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.1" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", "bytes", "libc", "mio", @@ -1658,14 +1248,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", @@ -1684,31 +1274,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -1717,50 +1295,11 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_parser", - "toml_writer", - "winnow", -] - -[[package]] -name = "toml_datetime" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_parser" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" -dependencies = [ - "winnow", -] - -[[package]] -name = "toml_writer" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" - [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -1774,30 +1313,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", "bytes", - "futures-core", "futures-util", "http", "http-body", - "http-body-util", - "http-range-header", - "httpdate", "iri-string", - "mime", - "mime_guess", - "percent-encoding", "pin-project-lite", - "tokio", - "tokio-util", "tower", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -1814,9 +1343,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -1824,23 +1353,11 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror 1.0.69", - "time", - "tracing-subscriber", -] - [[package]] name = "tracing-attributes" -version = "0.1.29" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -1849,9 +1366,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -1870,9 +1387,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -1888,40 +1405,17 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand", - "sha1", - "thiserror 2.0.12", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -1931,21 +1425,16 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -1964,12 +1453,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "want" version = "0.3.1" @@ -1981,52 +1464,49 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -2035,9 +1515,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2045,104 +1525,81 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] -name = "web-sys" -version = "0.3.77" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-link" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ "windows-link", "windows-result", @@ -2151,18 +1608,18 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] @@ -2173,16 +1630,25 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -2191,14 +1657,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -2207,42 +1690,84 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2250,33 +1775,111 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winnow" -version = "0.7.12" +name = "windows_x86_64_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", ] [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -2284,9 +1887,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -2294,26 +1897,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zerofrom" version = "0.1.6" @@ -2337,15 +1920,15 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -2354,9 +1937,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -2365,11 +1948,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/pi/pi-service/Cargo.toml b/pi/pi-service/Cargo.toml new file mode 100644 index 0000000..3d31271 --- /dev/null +++ b/pi/pi-service/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "noisebell" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" +axum = "0.8" +reqwest = { version = "0.12", features = ["json"] } +rppal = "0.22" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "1", features = ["full"] } +tracing = "0.1" +tracing-subscriber = "0.3" diff --git a/pi/pi-service/flake.nix b/pi/pi-service/flake.nix new file mode 100644 index 0000000..812dc56 --- /dev/null +++ b/pi/pi-service/flake.nix @@ -0,0 +1,62 @@ +{ + description = "Noisebell - GPIO door monitor service"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + crane.url = "github:ipetkov/crane"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, crane, rust-overlay }: + let + forSystem = system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ rust-overlay.overlays.default ]; + }; + + crossPkgs = import nixpkgs { + inherit system; + crossSystem.config = "aarch64-unknown-linux-gnu"; + overlays = [ rust-overlay.overlays.default ]; + }; + + rustToolchain = pkgs.rust-bin.stable.latest.default.override { + targets = [ "aarch64-unknown-linux-gnu" ]; + }; + + craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; + + src = craneLib.cleanCargoSource ./.; + + commonArgs = { + inherit src; + strictDeps = true; + doCheck = false; + + CARGO_BUILD_TARGET = "aarch64-unknown-linux-gnu"; + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = + "${crossPkgs.stdenv.cc.targetPrefix}cc"; + + HOST_CC = "${pkgs.stdenv.cc.nativePrefix}cc"; + + depsBuildBuild = [ crossPkgs.stdenv.cc ]; + }; + + cargoArtifacts = craneLib.buildDepsOnly commonArgs; + + noisebell = craneLib.buildPackage (commonArgs // { + inherit cargoArtifacts; + }); + in + { + packages.aarch64-linux.default = noisebell; + packages.aarch64-linux.noisebell = noisebell; + }; + in + forSystem "x86_64-linux"; +} diff --git a/pi/pi-service/src/main.rs b/pi/pi-service/src/main.rs new file mode 100644 index 0000000..f63f4a6 --- /dev/null +++ b/pi/pi-service/src/main.rs @@ -0,0 +1,116 @@ +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::Duration; + +use anyhow::{Context, Result}; +use axum::{extract::State, routing::get, Json, Router}; +use rppal::gpio::{Gpio, Level, Trigger}; +use serde::Serialize; +use tracing::{error, info}; + +#[derive(Serialize)] +struct StatusResponse { + status: &'static str, +} + +fn status_str(is_open: bool) -> &'static str { + if is_open { + "open" + } else { + "closed" + } +} + +async fn get_status(State(is_open): State>) -> Json { + Json(StatusResponse { + status: status_str(is_open.load(Ordering::Relaxed)), + }) +} + +#[tokio::main] +async fn main() -> Result<()> { + tracing_subscriber::fmt::init(); + + let gpio_pin: u8 = std::env::var("NOISEBELL_GPIO_PIN") + .unwrap_or_else(|_| "17".into()) + .parse() + .context("NOISEBELL_GPIO_PIN must be a valid u8")?; + + let debounce_secs: u64 = std::env::var("NOISEBELL_DEBOUNCE_SECS") + .unwrap_or_else(|_| "5".into()) + .parse() + .context("NOISEBELL_DEBOUNCE_SECS must be a valid u64")?; + + let port: u16 = std::env::var("NOISEBELL_PORT") + .unwrap_or_else(|_| "8080".into()) + .parse() + .context("NOISEBELL_PORT must be a valid u16")?; + + let endpoint_url = + std::env::var("NOISEBELL_ENDPOINT_URL").context("NOISEBELL_ENDPOINT_URL is required")?; + + info!(gpio_pin, debounce_secs, port, %endpoint_url, "starting noisebell"); + + let gpio = Gpio::new().context("failed to initialize GPIO")?; + let pin = gpio + .get(gpio_pin) + .context(format!("failed to get GPIO pin {gpio_pin}"))? + .into_input_pullup(); + + let is_open = Arc::new(AtomicBool::new(pin.read() == Level::Low)); + + info!(initial_status = status_str(is_open.load(Ordering::Relaxed)), "GPIO initialized"); + + // Channel to bridge sync GPIO callback -> async notification task + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + + // Set up async interrupt for state changes + let state_for_interrupt = is_open.clone(); + pin.set_async_interrupt( + Trigger::Both, + Some(Duration::from_secs(debounce_secs)), + move |event| { + let new_open = match event.trigger { + Trigger::FallingEdge => true, + Trigger::RisingEdge => false, + _ => return, + }; + let was_open = state_for_interrupt.swap(new_open, Ordering::Relaxed); + if was_open != new_open { + let _ = tx.send(new_open); + } + }, + ) + .context("failed to set GPIO interrupt")?; + + // Task that POSTs state changes to the endpoint + tokio::spawn(async move { + let client = reqwest::Client::new(); + while let Some(new_open) = rx.recv().await { + let status = status_str(new_open); + info!(status, "state changed"); + + if let Err(e) = client + .post(&endpoint_url) + .json(&serde_json::json!({ "status": status })) + .send() + .await + { + error!(%e, "failed to notify endpoint"); + } + } + }); + + let app = Router::new() + .route("/status", get(get_status)) + .with_state(is_open); + + let listener = tokio::net::TcpListener::bind(("0.0.0.0", port)) + .await + .context(format!("failed to bind to port {port}"))?; + + info!(port, "listening"); + axum::serve(listener, app).await.context("server error")?; + + Ok(()) +} diff --git a/pi/src/config.rs b/pi/src/config.rs deleted file mode 100644 index af4a476..0000000 --- a/pi/src/config.rs +++ /dev/null @@ -1,195 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::time::Duration; -use anyhow::Result; -use dotenvy::dotenv; -use tracing::info; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Config { - pub gpio: GpioConfig, - pub web_monitor: WebMonitorConfig, - pub logging: LoggingConfig, - pub monitor: MonitorConfig, - pub endpoint: EndpointConfig, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct GpioConfig { - pub pin: u8, - pub debounce_delay_secs: u64, -} - -impl GpioConfig { - pub fn from_env() -> Result { - let pin = std::env::var("NOISEBELL_GPIO_PIN") - .unwrap_or_else(|_| "17".to_string()) - .parse::() - .map_err(|_| anyhow::anyhow!("Invalid GPIO pin number"))?; - - let debounce_delay_secs = std::env::var("NOISEBELL_GPIO_DEBOUNCE_DELAY_SECS") - .unwrap_or_else(|_| "5".to_string()) - .parse::() - .map_err(|_| anyhow::anyhow!("Invalid debounce delay"))?; - - Ok(Self { - pin, - debounce_delay_secs, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WebMonitorConfig { - pub port: u16, - pub enabled: bool, -} - -impl WebMonitorConfig { - pub fn from_env() -> Result { - let port = std::env::var("NOISEBELL_WEB_MONITOR_PORT") - .unwrap_or_else(|_| "8080".to_string()) - .parse::() - .map_err(|_| anyhow::anyhow!("Invalid web monitor port"))?; - - let enabled = std::env::var("NOISEBELL_WEB_MONITOR_ENABLED") - .unwrap_or_else(|_| "true".to_string()) - .parse::() - .map_err(|_| anyhow::anyhow!("Invalid web monitor enabled flag"))?; - - Ok(Self { - port, - enabled, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LoggingConfig { - pub level: String, - pub file_path: String, - pub max_buffered_lines: usize, -} - -impl LoggingConfig { - pub fn from_env() -> Result { - let level = std::env::var("NOISEBELL_LOGGING_LEVEL") - .unwrap_or_else(|_| "info".to_string()); - - let file_path = std::env::var("NOISEBELL_LOGGING_FILE_PATH") - .unwrap_or_else(|_| "logs/noisebell.log".to_string()); - - let max_buffered_lines = std::env::var("NOISEBELL_LOGGING_MAX_BUFFERED_LINES") - .unwrap_or_else(|_| "10000".to_string()) - .parse::() - .map_err(|_| anyhow::anyhow!("Invalid max buffered lines"))?; - - Ok(Self { - level, - file_path, - max_buffered_lines, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct MonitorConfig { - pub monitor_type: String, -} - -impl MonitorConfig { - pub fn from_env() -> Result { - let monitor_type = std::env::var("NOISEBELL_MONITOR_TYPE") - .unwrap_or_else(|_| "web".to_string()); - - Ok(Self { - monitor_type, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EndpointConfig { - pub url: String, - pub api_key: Option, - pub timeout_secs: u64, - pub retry_attempts: u32, -} - -impl EndpointConfig { - pub fn from_env() -> Result { - let url = std::env::var("NOISEBELL_ENDPOINT_URL") - .unwrap_or_else(|_| "https://noisebell.jetpham.com/api/status".to_string()); - - let api_key = std::env::var("ENDPOINT_API_KEY").ok(); - - let timeout_secs = std::env::var("NOISEBELL_ENDPOINT_TIMEOUT_SECS") - .unwrap_or_else(|_| "30".to_string()) - .parse::() - .map_err(|_| anyhow::anyhow!("Invalid endpoint timeout"))?; - - let retry_attempts = std::env::var("NOISEBELL_ENDPOINT_RETRY_ATTEMPTS") - .unwrap_or_else(|_| "3".to_string()) - .parse::() - .map_err(|_| anyhow::anyhow!("Invalid retry attempts"))?; - - Ok(Self { - url, - api_key, - timeout_secs, - retry_attempts, - }) - } -} - -impl Config { - pub fn from_env() -> Result { - Self::load_env()?; - - let config = Config { - gpio: GpioConfig::from_env()?, - web_monitor: WebMonitorConfig::from_env()?, - logging: LoggingConfig::from_env()?, - monitor: MonitorConfig::from_env()?, - endpoint: EndpointConfig::from_env()?, - }; - - Ok(config) - } - - pub fn load_env() -> Result<()> { - // Try to load from .env file, but don't fail if it doesn't exist - match dotenv() { - Ok(_) => { - info!("Successfully loaded environment variables from .env file"); - Ok(()) - } - Err(dotenvy::Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { - info!("No .env file found, using system environment variables"); - Ok(()) - } - Err(e) => { - Err(anyhow::anyhow!("Failed to load .env file: {}", e)) - } - } - } - - pub fn validate(&self) -> Result<()> { - if self.gpio.pin > 40 { - return Err(anyhow::anyhow!("GPIO pin must be between 1-40")); - } - - if self.gpio.debounce_delay_secs <= 0 { - return Err(anyhow::anyhow!("Debounce delay must be greater than 0")); - } - - if !["gpio", "web"].contains(&self.monitor.monitor_type.as_str()) { - return Err(anyhow::anyhow!("Unknown monitor type: {}", self.monitor.monitor_type)); - } - - Ok(()) - } - - pub fn get_debounce_delay(&self) -> Duration { - Duration::from_secs(self.gpio.debounce_delay_secs) - } -} \ No newline at end of file diff --git a/pi/src/endpoint_notifier.rs b/pi/src/endpoint_notifier.rs deleted file mode 100644 index 8bec149..0000000 --- a/pi/src/endpoint_notifier.rs +++ /dev/null @@ -1,95 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_json::json; -use tracing::{info, error, warn}; -use reqwest::Client; -use tokio::time::{sleep, Duration}; - -use crate::StatusEvent; -use anyhow::Result; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EndpointConfig { - pub url: String, - pub api_key: Option, - pub timeout_secs: u64, - pub retry_attempts: u32, -} - -pub struct EndpointNotifier { - config: EndpointConfig, - client: Client, -} - -impl EndpointNotifier { - pub fn new(config: EndpointConfig) -> Self { - let client = Client::builder() - .timeout(Duration::from_secs(config.timeout_secs)) - .build() - .expect("Failed to create HTTP client"); - - Self { config, client } - } - - pub async fn notify_endpoint(&self, event: StatusEvent) -> Result<()> { - let status = match event { - StatusEvent::Open => "open", - StatusEvent::Closed => "closed", - }; - - let payload = json!({ - "status": status, - }); - - let mut success = false; - let mut last_error = None; - - for attempt in 1..=self.config.retry_attempts { - match self.send_request(&payload).await { - Ok(_) => { - success = true; - break; - } - Err(e) => { - last_error = Some(e); - if attempt < self.config.retry_attempts { - warn!("Attempt {} failed: {}. Retrying...", attempt, last_error.as_ref().unwrap()); - sleep(Duration::from_secs(1)).await; - } - } - } - } - - if !success { - let error_msg = last_error.unwrap_or_else(|| anyhow::anyhow!("Unknown error")); - error!("Failed to notify endpoint after {} attempts: {}", self.config.retry_attempts, error_msg); - return Err(error_msg); - } - - Ok(()) - } - - async fn send_request(&self, payload: &serde_json::Value) -> Result<()> { - let mut request = self.client - .post(&self.config.url) - .json(payload); - - if let Some(api_key) = &self.config.api_key { - request = request.header("Authorization", format!("Bearer {}", api_key)); - } - - let response = request - .timeout(Duration::from_secs(self.config.timeout_secs)) - .send() - .await?; - - if !response.status().is_success() { - return Err(anyhow::anyhow!( - "HTTP request failed with status {}: {}", - response.status(), - response.text().await.unwrap_or_else(|_| "Unknown error".to_string()) - )); - } - - Ok(()) - } -} \ No newline at end of file diff --git a/pi/src/gpio_monitor.rs b/pi/src/gpio_monitor.rs deleted file mode 100644 index 9ce15af..0000000 --- a/pi/src/gpio_monitor.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::time::Duration; -use anyhow::{Result, Context}; -use crate::{StatusEvent, monitor::Monitor}; - -pub struct GpioMonitor { - pin: rppal::gpio::InputPin, - debounce_delay: Duration, -} - -impl GpioMonitor { - pub fn new(pin_number: u8, debounce_delay: Duration) -> Result { - let gpio = rppal::gpio::Gpio::new().context("Failed to initialize GPIO")?; - let pin = gpio - .get(pin_number) - .context(format!("Failed to get GPIO pin {}", pin_number))? - .into_input_pullup(); - - Ok(Self { - pin, - debounce_delay, - }) - } -} - -impl Monitor for GpioMonitor { - fn monitor(&mut self, mut callback: Box) -> Result<()> { - self.pin - .set_async_interrupt(rppal::gpio::Trigger::Both, Some(self.debounce_delay), move |event| { - match event.trigger { - rppal::gpio::Trigger::RisingEdge => callback(StatusEvent::Closed), - rppal::gpio::Trigger::FallingEdge => callback(StatusEvent::Open), - _ => (), // Ignore other triggers - } - })?; - - Ok(()) - } - - fn get_current_state(&self) -> StatusEvent { - match self.pin.read() { - rppal::gpio::Level::Low => StatusEvent::Open, - rppal::gpio::Level::High => StatusEvent::Closed, - } - } -} \ No newline at end of file diff --git a/pi/src/logging.rs b/pi/src/logging.rs deleted file mode 100644 index f109acc..0000000 --- a/pi/src/logging.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::fs; -use anyhow::Result; -use tracing_appender::rolling::RollingFileAppender; -use tracing_subscriber::filter::LevelFilter; -use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt}; -use crate::config::LoggingConfig; - -pub fn init(config: &LoggingConfig) -> Result<()> { - tracing::info!("creating logs directory"); - let log_dir = std::path::Path::new(&config.file_path).parent().unwrap_or_else(|| std::path::Path::new("logs")); - fs::create_dir_all(log_dir)?; - - tracing::info!("initializing logging"); - let file_appender = RollingFileAppender::builder() - .rotation(tracing_appender::rolling::Rotation::NEVER) - .filename_prefix("noisebell") - .filename_suffix("log") - .build(log_dir)?; - - let (non_blocking, _guard) = tracing_appender::non_blocking::NonBlockingBuilder::default() - .buffered_lines_limit(config.max_buffered_lines) - .finish(file_appender); - - // Parse log level from config - let level_filter = match config.level.to_lowercase().as_str() { - "trace" => LevelFilter::TRACE, - "debug" => LevelFilter::DEBUG, - "info" => LevelFilter::INFO, - "warn" => LevelFilter::WARN, - "error" => LevelFilter::ERROR, - _ => LevelFilter::INFO, - }; - - // Only show our logs and hide hyper logs - let filter = tracing_subscriber::filter::Targets::new() - .with_target("noisebell", level_filter) - .with_target("hyper", LevelFilter::WARN) - .with_target("hyper_util", LevelFilter::WARN); - - tracing_subscriber::registry() - .with(filter) - .with(fmt::Layer::default().with_writer(std::io::stdout)) - .with(fmt::Layer::default().with_writer(non_blocking)) - .init(); - - Ok(()) -} \ No newline at end of file diff --git a/pi/src/main.rs b/pi/src/main.rs deleted file mode 100644 index 4bcfe1e..0000000 --- a/pi/src/main.rs +++ /dev/null @@ -1,98 +0,0 @@ -mod logging; -mod monitor; -mod gpio_monitor; -mod web_monitor; -mod endpoint_notifier; -mod config; - -use std::{fmt, sync::Arc}; -use tokio::sync::RwLock; - -use anyhow::Result; -use serde::{Deserialize, Serialize}; -use tracing::{error, info}; - -// Shared state types -pub type SharedMonitor = Arc>>; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub enum StatusEvent { - Open, - Closed, -} - -impl fmt::Display for StatusEvent { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - StatusEvent::Open => write!(f, "open"), - StatusEvent::Closed => write!(f, "closed"), - } - } -} - -#[tokio::main] -async fn main() -> Result<()> { - // Load and validate configuration - let config = config::Config::from_env()?; - config.validate()?; - - info!("Configuration loaded successfully"); - info!("Monitor type: {}", config.monitor.monitor_type); - if config.web_monitor.enabled { - info!("Web monitor: port {}", config.web_monitor.port); - } - - // Initialize logging with config - logging::init(&config.logging)?; - - // Load endpoint configuration - info!("Using endpoint URL: {}", config.endpoint.url); - let endpoint_config = endpoint_notifier::EndpointConfig { - url: config.endpoint.url.clone(), - api_key: config.endpoint.api_key.clone(), - timeout_secs: config.endpoint.timeout_secs, - retry_attempts: config.endpoint.retry_attempts, - }; - let notifier = Arc::new(endpoint_notifier::EndpointNotifier::new(endpoint_config)); - - info!("initializing {} monitor", config.monitor.monitor_type); - let monitor = monitor::create_monitor( - &config.monitor.monitor_type, - config.gpio.pin, - config.get_debounce_delay(), - if config.web_monitor.enabled { Some(config.web_monitor.port) } else { None }, - )?; - - let shared_monitor: SharedMonitor = Arc::new(RwLock::new(monitor)); - - let monitor_for_task = shared_monitor.clone(); - - let callback = { - let notifier = notifier.clone(); - Box::new(move |event: StatusEvent| { - let notifier = notifier.clone(); - tokio::spawn(async move { - if let Err(e) = notifier.notify_endpoint(event).await { - error!("Failed to notify endpoint: {}", e); - } - }); - }) - }; - - let monitor_handle = tokio::spawn(async move { - if let Err(e) = monitor_for_task.write().await.monitor(callback) { - error!("Monitor error: {}", e); - } - }); - - info!("Monitor started with endpoint notifications."); - - tokio::select! { - _ = monitor_handle => { - info!("Monitor task completed"); - } - } - - info!("Shutting down noisebell..."); - Ok(()) -} diff --git a/pi/src/monitor.rs b/pi/src/monitor.rs deleted file mode 100644 index dff8a1a..0000000 --- a/pi/src/monitor.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::time::Duration; -use anyhow::Result; -use crate::StatusEvent; - -pub trait Monitor: Send + Sync { - fn monitor(&mut self, callback: Box) -> Result<()>; - fn get_current_state(&self) -> StatusEvent; -} - -pub fn create_monitor(monitor_type: &str, pin_number: u8, debounce_delay: Duration, web_port: Option) -> Result> { - match monitor_type { - "gpio" => Ok(Box::new(crate::gpio_monitor::GpioMonitor::new(pin_number, debounce_delay)?)), - "web" => { - let port = web_port.ok_or_else(|| anyhow::anyhow!("Web monitor requires a port number"))?; - Ok(Box::new(crate::web_monitor::WebMonitor::new(port)?)) - }, - _ => Err(anyhow::anyhow!("Unknown monitor type: {}", monitor_type)), - } -} \ No newline at end of file diff --git a/pi/src/web_monitor.rs b/pi/src/web_monitor.rs deleted file mode 100644 index edd4d00..0000000 --- a/pi/src/web_monitor.rs +++ /dev/null @@ -1,176 +0,0 @@ -use std::sync::Arc; -use anyhow::Result; -use axum::{ - extract::{ws::{Message, WebSocket, WebSocketUpgrade}, State}, - response::{Html, IntoResponse}, - routing::{get}, - Router, -}; -use serde::{Deserialize, Serialize}; -use tokio::sync::{RwLock, Mutex}; -use tracing::{info, error}; -use futures_util::{sink::SinkExt, stream::StreamExt}; -use tower_http::services::ServeDir; - -use crate::{StatusEvent, monitor::Monitor}; - -#[derive(Clone)] -pub struct WebMonitor { - port: u16, - current_state: Arc>, - callback: Arc>>>, -} - -#[derive(Clone)] -struct AppState { - current_state: Arc>, - callback: Arc>>>, -} - -#[derive(Serialize, Deserialize)] -struct StateChangeMessage { - event: String, - state: String, -} - -impl WebMonitor { - pub fn new(port: u16) -> Result { - Ok(Self { - port, - current_state: Arc::new(RwLock::new(StatusEvent::Closed)), // Default to closed - callback: Arc::new(Mutex::new(None)), - }) - } - - async fn serve_html() -> impl IntoResponse { - Html(include_str!("../static/monitor.html")) - } - - async fn websocket_handler( - ws: WebSocketUpgrade, - State(state): State, - ) -> impl IntoResponse { - ws.on_upgrade(move |socket| Self::handle_websocket(socket, state)) - } - - async fn handle_websocket(socket: WebSocket, state: AppState) { - let (mut sender, mut receiver) = socket.split(); - - // Send current state immediately - let current_state = *state.current_state.read().await; - let initial_message = StateChangeMessage { - event: "state_update".to_string(), - state: current_state.to_string(), - }; - - if let Ok(msg) = serde_json::to_string(&initial_message) { - if let Err(e) = sender.send(Message::Text(msg.into())).await { - error!("Failed to send initial state: {}", e); - return; - } - } - - // Handle incoming messages from client - let state_for_receiver = state.clone(); - while let Some(msg) = receiver.next().await { - match msg { - Ok(Message::Text(text)) => { - let text_str = text.to_string(); - if let Ok(state_msg) = serde_json::from_str::(&text_str) { - if state_msg.event == "state_change" { - let new_state = match state_msg.state.as_str() { - "open" => StatusEvent::Open, - "closed" => StatusEvent::Closed, - _ => continue, - }; - - // Update current state - { - let mut current = state_for_receiver.current_state.write().await; - *current = new_state; - } - - // Trigger callback - { - let mut callback_guard = state_for_receiver.callback.lock().await; - if let Some(ref mut callback) = callback_guard.as_mut() { - callback(new_state); - } - } - - info!("Web monitor state changed to: {:?}", new_state); - } - } - } - Ok(Message::Close(_)) => { - info!("WebSocket connection closed"); - break; - } - Err(e) => { - error!("WebSocket error: {}", e); - break; - } - _ => {} - } - } - } - - async fn start_server(&self) -> Result<()> { - let app_state = AppState { - current_state: self.current_state.clone(), - callback: self.callback.clone(), - }; - - let app = Router::new() - .route("/", get(Self::serve_html)) - .route("/ws", get(Self::websocket_handler)) - .nest_service("/media", ServeDir::new("media")) - .with_state(app_state); - - let addr = format!("0.0.0.0:{}", self.port); - info!("Starting web monitor server on {}", addr); - - let listener = tokio::net::TcpListener::bind(&addr).await?; - axum::serve(listener, app).await?; - - Ok(()) - } -} - -impl Monitor for WebMonitor { - fn monitor(&mut self, callback: Box) -> Result<()> { - // Store the callback synchronously to ensure it's available immediately - let callback_arc = self.callback.clone(); - let rt = tokio::runtime::Handle::current(); - tokio::task::block_in_place(|| { - rt.block_on(async { - let mut guard = callback_arc.lock().await; - *guard = Some(callback); - }); - }); - - // Run the web server in a blocking task to avoid runtime conflicts - let server = self.clone(); - tokio::task::spawn_blocking(move || { - let rt = tokio::runtime::Runtime::new().unwrap(); - if let Err(e) = rt.block_on(server.start_server()) { - error!("Web monitor server error: {}", e); - } - }); - - loop { - std::thread::sleep(std::time::Duration::from_secs(1)); - } - } - - fn get_current_state(&self) -> StatusEvent { - // This is a synchronous function, but we need to read async state - // We'll use a blocking operation here similar to how GPIO reads work - let rt = tokio::runtime::Handle::current(); - tokio::task::block_in_place(|| { - rt.block_on(async { - *self.current_state.read().await - }) - }) - } -} \ No newline at end of file diff --git a/pi/static/monitor.html b/pi/static/monitor.html deleted file mode 100644 index e6dd041..0000000 --- a/pi/static/monitor.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - - - Circuit Monitor - - - - -
-
- -

Circuit Monitor

-
- -
- Circuit State -
- -
-
OPEN
- -
CLOSED
-
- -
- Connecting... -
-
- - - - \ No newline at end of file