Compare commits
4 Commits
feature/im
...
0436ff57d8
| Author | SHA1 | Date | |
|---|---|---|---|
|
0436ff57d8
|
|||
|
8d9210247b
|
|||
|
1a5fe54213
|
|||
|
9f44554996
|
@@ -1,2 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
.env
|
.env
|
||||||
|
# Use the rust environment provided by the container
|
||||||
|
rust-toolchain.toml
|
||||||
|
|||||||
@@ -1,84 +1,24 @@
|
|||||||
# Based on: https://pastebin.com/99Fq2b2w
|
|
||||||
name: Build and deploy
|
name: Build and deploy
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- feature/**
|
- feature/**
|
||||||
|
tags:
|
||||||
|
- v*.*.*
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build application
|
uses: dreaded_x/workflows/.gitea/workflows/rust-kubernetes.yaml@22ee0c1788a8d2157db87d6a6f8dbe520fe48592
|
||||||
runs-on: ubuntu-latest
|
secrets: inherit
|
||||||
container: catthehacker/ubuntu:act-latest
|
with:
|
||||||
steps:
|
upload_manifests: false
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Rust
|
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
|
||||||
with:
|
|
||||||
rustflags: ""
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cargo build --release
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: automation
|
|
||||||
path: target/release/automation
|
|
||||||
|
|
||||||
container:
|
|
||||||
name: Build container
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [build]
|
|
||||||
container: catthehacker/ubuntu:act-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Download artifact
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: automation
|
|
||||||
|
|
||||||
- name: Set permissions
|
|
||||||
run: |
|
|
||||||
chown 65532:65532 ./automation
|
|
||||||
chmod 0755 ./automation
|
|
||||||
|
|
||||||
- name: Docker meta
|
|
||||||
id: meta
|
|
||||||
uses: https://github.com/docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: git.huizinga.dev/dreaded_x/automation_rs
|
|
||||||
tags: |
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=pr
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
|
|
||||||
- name: Login to registry
|
|
||||||
uses: https://github.com/docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: git.huizinga.dev
|
|
||||||
username: ${{ gitea.actor }}
|
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push Docker image
|
|
||||||
uses: https://github.com/docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: Deploy container
|
name: Deploy container
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest
|
container: catthehacker/ubuntu:act-latest
|
||||||
needs: [container]
|
needs: build
|
||||||
if: gitea.ref == 'refs/heads/master'
|
if: gitea.ref == 'refs/heads/master'
|
||||||
steps:
|
steps:
|
||||||
- name: Stop and remove current container
|
- name: Stop and remove current container
|
||||||
@@ -97,11 +37,9 @@ jobs:
|
|||||||
-e MQTT_PASSWORD=${{ secrets.MQTT_PASSWORD }} \
|
-e MQTT_PASSWORD=${{ secrets.MQTT_PASSWORD }} \
|
||||||
-e HUE_TOKEN=${{ secrets.HUE_TOKEN }} \
|
-e HUE_TOKEN=${{ secrets.HUE_TOKEN }} \
|
||||||
-e NTFY_TOPIC=${{ secrets.NTFY_TOPIC }} \
|
-e NTFY_TOPIC=${{ secrets.NTFY_TOPIC }} \
|
||||||
git.huizinga.dev/dreaded_x/automation_rs:master
|
git.huizinga.dev/dreaded_x/automation_rs@${{ needs.build.outputs.digest }}
|
||||||
|
|
||||||
docker network connect web automation_rs
|
docker network connect web automation_rs
|
||||||
|
|
||||||
- name: Start container
|
- name: Start container
|
||||||
run: docker start automation_rs
|
run: docker start automation_rs
|
||||||
|
|
||||||
# TODO: Perform a healthcheck
|
|
||||||
|
|||||||
@@ -5,16 +5,12 @@ repos:
|
|||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
|
args:
|
||||||
|
- --allow-multiple-documents
|
||||||
- id: check-toml
|
- id: check-toml
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
|
|
||||||
- repo: https://github.com/doublify/pre-commit-rust
|
|
||||||
rev: v1.0
|
|
||||||
hooks:
|
|
||||||
- id: clippy
|
|
||||||
- id: fmt
|
|
||||||
|
|
||||||
- repo: https://github.com/JohnnyMorganz/StyLua
|
- repo: https://github.com/JohnnyMorganz/StyLua
|
||||||
rev: v0.20.0
|
rev: v0.20.0
|
||||||
hooks:
|
hooks:
|
||||||
@@ -26,7 +22,59 @@ repos:
|
|||||||
- id: typos
|
- id: typos
|
||||||
args: ["--force-exclude"]
|
args: ["--force-exclude"]
|
||||||
|
|
||||||
- repo: https://github.com/pryorda/dockerfilelint-precommit-hooks
|
- repo: local
|
||||||
rev: v0.1.0
|
|
||||||
hooks:
|
hooks:
|
||||||
- id: dockerfilelint
|
- id: fmt
|
||||||
|
name: fmt
|
||||||
|
description: Format files with cargo fmt.
|
||||||
|
entry: cargo +nightly fmt
|
||||||
|
language: system
|
||||||
|
types: [rust]
|
||||||
|
args: ["--", "--check"]
|
||||||
|
# For some reason some formatting is different depending on how you invoke?
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
|
- id: clippy
|
||||||
|
name: clippy
|
||||||
|
description: Lint rust sources
|
||||||
|
entry: cargo clippy
|
||||||
|
language: system
|
||||||
|
args: ["--", "-D", "warnings"]
|
||||||
|
types: [file]
|
||||||
|
files: (\.rs|Cargo.lock)$
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
|
- id: audit
|
||||||
|
name: audit
|
||||||
|
description: Audit packages
|
||||||
|
entry: cargo audit
|
||||||
|
args: ["--deny", "warnings"]
|
||||||
|
language: system
|
||||||
|
pass_filenames: false
|
||||||
|
verbose: true
|
||||||
|
always_run: true
|
||||||
|
|
||||||
|
- id: udeps
|
||||||
|
name: unused
|
||||||
|
description: Check for unused crates
|
||||||
|
entry: cargo udeps
|
||||||
|
args: ["--workspace"]
|
||||||
|
language: system
|
||||||
|
types: [file]
|
||||||
|
files: (\.rs|Cargo.lock)$
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
|
- id: test
|
||||||
|
name: test
|
||||||
|
description: Rust test
|
||||||
|
entry: cargo test
|
||||||
|
language: system
|
||||||
|
args: ["--workspace"]
|
||||||
|
types: [file]
|
||||||
|
files: (\.rs|Cargo.lock)$
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
|
- repo: https://github.com/hadolint/hadolint
|
||||||
|
rev: v2.12.0
|
||||||
|
hooks:
|
||||||
|
- id: hadolint
|
||||||
|
|||||||
1390
Cargo.lock
generated
1390
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "automation"
|
name = "automation"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
@@ -47,7 +47,6 @@ impls = "1.0.3"
|
|||||||
indexmap = { version = "2.0.0", features = ["serde"] }
|
indexmap = { version = "2.0.0", features = ["serde"] }
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
json_value_merge = "2.0.0"
|
json_value_merge = "2.0.0"
|
||||||
pollster = "0.4.0"
|
|
||||||
proc-macro2 = "1.0.81"
|
proc-macro2 = "1.0.81"
|
||||||
quote = "1.0.36"
|
quote = "1.0.36"
|
||||||
reqwest = { version = "0.12.9", features = [
|
reqwest = { version = "0.12.9", features = [
|
||||||
|
|||||||
28
Dockerfile
28
Dockerfile
@@ -1,8 +1,26 @@
|
|||||||
FROM gcr.io/distroless/cc-debian12:nonroot
|
FROM rust:1.89 AS base
|
||||||
|
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
|
||||||
|
RUN cargo install cargo-chef --locked --version 0.1.71 && \
|
||||||
|
cargo install cargo-auditable --locked --version 0.6.6
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
FROM base AS planner
|
||||||
|
COPY . .
|
||||||
|
RUN cargo chef prepare --recipe-path recipe.json
|
||||||
|
|
||||||
|
FROM base AS builder
|
||||||
|
# HACK: Now we can use unstable feature while on stable rust!
|
||||||
|
ENV RUSTC_BOOTSTRAP=1
|
||||||
|
COPY --from=planner /app/recipe.json recipe.json
|
||||||
|
RUN cargo chef cook --release --recipe-path recipe.json
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
ARG RELEASE_VERSION
|
||||||
|
ENV RELEASE_VERSION=${RELEASE_VERSION}
|
||||||
|
RUN cargo auditable build --release
|
||||||
|
|
||||||
|
FROM gcr.io/distroless/cc-debian12:nonroot AS runtime
|
||||||
|
COPY --from=builder /app/target/release/automation /app/automation
|
||||||
ENV AUTOMATION_CONFIG=/app/config.lua
|
ENV AUTOMATION_CONFIG=/app/config.lua
|
||||||
COPY ./config.lua /app/config.lua
|
COPY ./config.lua /app/config.lua
|
||||||
|
CMD [ "/app/automation" ]
|
||||||
COPY ./automation /app/automation
|
|
||||||
|
|
||||||
CMD ["/app/automation"]
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "automation_cast"
|
name = "automation_cast"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "automation_devices"
|
name = "automation_devices"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
automation_lib = { workspace = true }
|
automation_lib = { workspace = true }
|
||||||
@@ -17,7 +17,7 @@ tracing = { workspace = true }
|
|||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
impls = { workspace = true }
|
impls = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
reqwest = { workspace = true } # Use rustls, since the other packages also use rustls
|
reqwest = { workspace = true } # Use rustls, since the other packages also use rustls
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
axum = { workspace = true }
|
axum = { workspace = true }
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
|
|||||||
@@ -68,11 +68,11 @@ pub struct ContactSensor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ContactSensor {
|
impl ContactSensor {
|
||||||
async fn state(&self) -> RwLockReadGuard<State> {
|
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||||
self.state.read().await
|
self.state.read().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||||
self.state.write().await
|
self.state.write().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
|||||||
use automation_lib::event::OnMqtt;
|
use automation_lib::event::OnMqtt;
|
||||||
use automation_lib::mqtt::WrappedAsyncClient;
|
use automation_lib::mqtt::WrappedAsyncClient;
|
||||||
use automation_macro::LuaDeviceConfig;
|
use automation_macro::LuaDeviceConfig;
|
||||||
use rumqttc::{matches, Publish};
|
use rumqttc::{Publish, matches};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use automation_lib::messages::{RemoteAction, RemoteMessage};
|
|||||||
use automation_lib::mqtt::WrappedAsyncClient;
|
use automation_lib::mqtt::WrappedAsyncClient;
|
||||||
use automation_macro::LuaDeviceConfig;
|
use automation_macro::LuaDeviceConfig;
|
||||||
use axum::async_trait;
|
use axum::async_trait;
|
||||||
use rumqttc::{matches, Publish};
|
use rumqttc::{Publish, matches};
|
||||||
use tracing::{debug, error, trace};
|
use tracing::{debug, error, trace};
|
||||||
|
|
||||||
#[derive(Debug, Clone, LuaDeviceConfig)]
|
#[derive(Debug, Clone, LuaDeviceConfig)]
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ pub struct LightSensor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LightSensor {
|
impl LightSensor {
|
||||||
async fn state(&self) -> RwLockReadGuard<State> {
|
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||||
self.state.read().await
|
self.state.read().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||||
self.state.write().await
|
self.state.write().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,9 +99,7 @@ impl OnMqtt for LightSensor {
|
|||||||
let is_dark = self.state().await.is_dark;
|
let is_dark = self.state().await.is_dark;
|
||||||
trace!(
|
trace!(
|
||||||
"In between min ({}) and max ({}) value, keeping current state: {}",
|
"In between min ({}) and max ({}) value, keeping current state: {}",
|
||||||
self.config.min,
|
self.config.min, self.config.max, is_dark
|
||||||
self.config.max,
|
|
||||||
is_dark
|
|
||||||
);
|
);
|
||||||
is_dark
|
is_dark
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ pub struct Washer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Washer {
|
impl Washer {
|
||||||
async fn state(&self) -> RwLockReadGuard<State> {
|
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||||
self.state.read().await
|
self.state.read().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||||
self.state.write().await
|
self.state.write().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use google_home::device;
|
|||||||
use google_home::errors::ErrorCode;
|
use google_home::errors::ErrorCode;
|
||||||
use google_home::traits::{Brightness, Color, ColorSetting, ColorTemperatureRange, OnOff};
|
use google_home::traits::{Brightness, Color, ColorSetting, ColorTemperatureRange, OnOff};
|
||||||
use google_home::types::Type;
|
use google_home::types::Type;
|
||||||
use rumqttc::{matches, Publish};
|
use rumqttc::{Publish, matches};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
@@ -100,11 +100,11 @@ pub type LightBrightness = Light<StateBrightness>;
|
|||||||
pub type LightColorTemperature = Light<StateColorTemperature>;
|
pub type LightColorTemperature = Light<StateColorTemperature>;
|
||||||
|
|
||||||
impl<T: LightState> Light<T> {
|
impl<T: LightState> Light<T> {
|
||||||
async fn state(&self) -> RwLockReadGuard<T> {
|
async fn state(&self) -> RwLockReadGuard<'_, T> {
|
||||||
self.state.read().await
|
self.state.read().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn state_mut(&self) -> RwLockWriteGuard<T> {
|
async fn state_mut(&self) -> RwLockWriteGuard<'_, T> {
|
||||||
self.state.write().await
|
self.state.write().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use google_home::device;
|
|||||||
use google_home::errors::ErrorCode;
|
use google_home::errors::ErrorCode;
|
||||||
use google_home::traits::OnOff;
|
use google_home::traits::OnOff;
|
||||||
use google_home::types::Type;
|
use google_home::types::Type;
|
||||||
use rumqttc::{matches, Publish};
|
use rumqttc::{Publish, matches};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
@@ -95,11 +95,11 @@ pub type OutletOnOff = Outlet<StateOnOff>;
|
|||||||
pub type OutletPower = Outlet<StatePower>;
|
pub type OutletPower = Outlet<StatePower>;
|
||||||
|
|
||||||
impl<T: OutletState> Outlet<T> {
|
impl<T: OutletState> Outlet<T> {
|
||||||
async fn state(&self) -> RwLockReadGuard<T> {
|
async fn state(&self) -> RwLockReadGuard<'_, T> {
|
||||||
self.state.read().await
|
self.state.read().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn state_mut(&self) -> RwLockWriteGuard<T> {
|
async fn state_mut(&self) -> RwLockWriteGuard<'_, T> {
|
||||||
self.state.write().await
|
self.state.write().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "automation_lib"
|
name = "automation_lib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
automation_macro = { workspace = true }
|
automation_macro = { workspace = true }
|
||||||
@@ -15,14 +15,12 @@ reqwest = { workspace = true }
|
|||||||
serde_repr = { workspace = true }
|
serde_repr = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
pollster = { workspace = true }
|
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
indexmap = { workspace = true }
|
indexmap = { workspace = true }
|
||||||
tokio-cron-scheduler = { workspace = true }
|
tokio-cron-scheduler = { workspace = true }
|
||||||
mlua = { workspace = true }
|
mlua = { workspace = true }
|
||||||
tokio-util = { workspace = true }
|
|
||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
dyn-clone = { workspace = true }
|
dyn-clone = { workspace = true }
|
||||||
impls = { workspace = true }
|
impls = { workspace = true }
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use std::collections::HashMap;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use futures::future::join_all;
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
use futures::future::join_all;
|
||||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||||
use tokio_cron_scheduler::{Job, JobScheduler};
|
use tokio_cron_scheduler::{Job, JobScheduler};
|
||||||
use tracing::{debug, instrument, trace};
|
use tracing::{debug, instrument, trace};
|
||||||
@@ -64,7 +64,7 @@ impl DeviceManager {
|
|||||||
self.devices.read().await.get(name).cloned()
|
self.devices.read().await.get(name).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn devices(&self) -> RwLockReadGuard<DeviceMap> {
|
pub async fn devices(&self) -> RwLockReadGuard<'_, DeviceMap> {
|
||||||
self.devices.read().await
|
self.devices.read().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ impl fmt::Display for MissingEnv {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "Missing environment variable")?;
|
write!(f, "Missing environment variable")?;
|
||||||
if self.keys.is_empty() {
|
if self.keys.is_empty() {
|
||||||
unreachable!("This error should only be returned if there are actually missing environment variables");
|
unreachable!(
|
||||||
|
"This error should only be returned if there are actually missing environment variables"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if self.keys.len() == 1 {
|
if self.keys.len() == 1 {
|
||||||
write!(f, " '{}'", self.keys[0])?;
|
write!(f, " '{}'", self.keys[0])?;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
#![feature(let_chains)]
|
|
||||||
|
|
||||||
pub mod action_callback;
|
pub mod action_callback;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use serde::Serialize;
|
|||||||
use serde_repr::*;
|
use serde_repr::*;
|
||||||
use tracing::{error, trace, warn};
|
use tracing::{error, trace, warn};
|
||||||
|
|
||||||
use crate::device::{impl_device, Device, LuaDeviceCreate};
|
use crate::device::{Device, LuaDeviceCreate, impl_device};
|
||||||
use crate::event::{self, Event, EventChannel, OnNotification, OnPresence};
|
use crate::event::{self, Event, EventChannel, OnNotification, OnPresence};
|
||||||
|
|
||||||
#[derive(Debug, Serialize_repr, Clone, Copy)]
|
#[derive(Debug, Serialize_repr, Clone, Copy)]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
|||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
use crate::config::MqttDeviceConfig;
|
use crate::config::MqttDeviceConfig;
|
||||||
use crate::device::{impl_device, Device, LuaDeviceCreate};
|
use crate::device::{Device, LuaDeviceCreate, impl_device};
|
||||||
use crate::event::{self, Event, EventChannel, OnMqtt};
|
use crate::event::{self, Event, EventChannel, OnMqtt};
|
||||||
use crate::messages::PresenceMessage;
|
use crate::messages::PresenceMessage;
|
||||||
use crate::mqtt::WrappedAsyncClient;
|
use crate::mqtt::WrappedAsyncClient;
|
||||||
@@ -40,11 +40,11 @@ pub struct Presence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Presence {
|
impl Presence {
|
||||||
async fn state(&self) -> RwLockReadGuard<State> {
|
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||||
self.state.read().await
|
self.state.read().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||||
self.state.write().await
|
self.state.write().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "automation_macro"
|
name = "automation_macro"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
#![feature(let_chains)]
|
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
mod lua_device_config;
|
mod lua_device_config;
|
||||||
|
|
||||||
use lua_device_config::impl_lua_device_config_macro;
|
use lua_device_config::impl_lua_device_config_macro;
|
||||||
use syn::{parse_macro_input, DeriveInput};
|
use syn::{DeriveInput, parse_macro_input};
|
||||||
|
|
||||||
#[proc_macro_derive(LuaDeviceConfig, attributes(device_config))]
|
#[proc_macro_derive(LuaDeviceConfig, attributes(device_config))]
|
||||||
pub fn lua_device_config_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn lua_device_config_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use syn::punctuated::Punctuated;
|
|||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::token::Paren;
|
use syn::token::Paren;
|
||||||
use syn::{
|
use syn::{
|
||||||
parenthesized, Data, DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed, LitStr, Result,
|
Data, DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed, LitStr, Result, Token, Type,
|
||||||
Token, Type,
|
parenthesized,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod kw {
|
mod kw {
|
||||||
@@ -155,7 +155,7 @@ fn field_from_lua(field: &Field) -> TokenStream {
|
|||||||
[] => field.ident.clone().unwrap().to_string(),
|
[] => field.ident.clone().unwrap().to_string(),
|
||||||
[rename] => rename.to_owned(),
|
[rename] => rename.to_owned(),
|
||||||
_ => {
|
_ => {
|
||||||
return quote_spanned! {field.span() => compile_error!("Field contains duplicate 'rename'")}
|
return quote_spanned! {field.span() => compile_error!("Field contains duplicate 'rename'")};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ fn field_from_lua(field: &Field) -> TokenStream {
|
|||||||
[] => quote! {panic!(#missing)},
|
[] => quote! {panic!(#missing)},
|
||||||
[default] => default.to_owned(),
|
[default] => default.to_owned(),
|
||||||
_ => {
|
_ => {
|
||||||
return quote_spanned! {field.span() => compile_error!("Field contains duplicate 'default'")}
|
return quote_spanned! {field.span() => compile_error!("Field contains duplicate 'default'")};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ fn field_from_lua(field: &Field) -> TokenStream {
|
|||||||
[] => value,
|
[] => value,
|
||||||
[value] => value.to_owned(),
|
[value] => value.to_owned(),
|
||||||
_ => {
|
_ => {
|
||||||
return quote_spanned! {field.span() => compile_error!("Only one of either 'from' or 'with' is allowed")}
|
return quote_spanned! {field.span() => compile_error!("Only one of either 'from' or 'with' is allowed")};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "google_home"
|
name = "google_home"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use automation_cast::Cast;
|
use automation_cast::Cast;
|
||||||
use futures::future::{join_all, OptionFuture};
|
use futures::future::{OptionFuture, join_all};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use crate::Device;
|
||||||
use crate::errors::{DeviceError, ErrorCode};
|
use crate::errors::{DeviceError, ErrorCode};
|
||||||
use crate::request::{self, Intent, Request};
|
use crate::request::{self, Intent, Request};
|
||||||
use crate::response::{self, execute, query, sync, Response, ResponsePayload};
|
use crate::response::{self, Response, ResponsePayload, execute, query, sync};
|
||||||
use crate::Device;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GoogleHome {
|
pub struct GoogleHome {
|
||||||
@@ -64,7 +64,7 @@ impl GoogleHome {
|
|||||||
devices: &HashMap<String, Box<T>>,
|
devices: &HashMap<String, Box<T>>,
|
||||||
) -> sync::Payload {
|
) -> sync::Payload {
|
||||||
let mut resp_payload = sync::Payload::new(&self.user_id);
|
let mut resp_payload = sync::Payload::new(&self.user_id);
|
||||||
let f = devices.iter().map(|(_, device)| async move {
|
let f = devices.values().map(|device| async move {
|
||||||
if let Some(device) = device.as_ref().cast() {
|
if let Some(device) = device.as_ref().cast() {
|
||||||
Some(Device::sync(device).await)
|
Some(Device::sync(device).await)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
#![feature(let_chains)]
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
mod fulfillment;
|
mod fulfillment;
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use automation_cast::Cast;
|
|||||||
use google_home_macro::traits;
|
use google_home_macro::traits;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::errors::ErrorCode;
|
|
||||||
use crate::Device;
|
use crate::Device;
|
||||||
|
use crate::errors::ErrorCode;
|
||||||
|
|
||||||
traits! {
|
traits! {
|
||||||
Device,
|
Device,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "google_home_macro"
|
name = "google_home_macro"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#![feature(let_chains)]
|
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
@@ -6,8 +5,8 @@ use syn::parse::Parse;
|
|||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
use syn::token::Brace;
|
use syn::token::Brace;
|
||||||
use syn::{
|
use syn::{
|
||||||
braced, parse_macro_input, GenericArgument, Ident, LitStr, Path, PathArguments, PathSegment,
|
GenericArgument, Ident, LitStr, Path, PathArguments, PathSegment, ReturnType, Signature, Token,
|
||||||
ReturnType, Signature, Token, Type, TypePath,
|
Type, TypePath, braced, parse_macro_input,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod kw {
|
mod kw {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2024-12-06"
|
channel = "nightly-2025-08-20"
|
||||||
components = ["rustfmt", "clippy", "rust-analyzer"]
|
components = ["rustfmt", "clippy", "rust-analyzer"]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ use std::result;
|
|||||||
|
|
||||||
use axum::async_trait;
|
use axum::async_trait;
|
||||||
use axum::extract::{FromRef, FromRequestParts};
|
use axum::extract::{FromRef, FromRequestParts};
|
||||||
|
use axum::http::StatusCode;
|
||||||
use axum::http::request::Parts;
|
use axum::http::request::Parts;
|
||||||
use axum::http::status::InvalidStatusCode;
|
use axum::http::status::InvalidStatusCode;
|
||||||
use axum::http::StatusCode;
|
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|||||||
Reference in New Issue
Block a user