Compare commits
4 Commits
feature/im
...
0436ff57d8
| Author | SHA1 | Date | |
|---|---|---|---|
|
0436ff57d8
|
|||
|
8d9210247b
|
|||
|
1a5fe54213
|
|||
|
9f44554996
|
@@ -1,2 +1,4 @@
|
||||
/target
|
||||
.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
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- feature/**
|
||||
tags:
|
||||
- v*.*.*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build application
|
||||
runs-on: ubuntu-latest
|
||||
container: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
uses: dreaded_x/workflows/.gitea/workflows/rust-kubernetes.yaml@22ee0c1788a8d2157db87d6a6f8dbe520fe48592
|
||||
secrets: inherit
|
||||
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 }}
|
||||
upload_manifests: false
|
||||
|
||||
deploy:
|
||||
name: Deploy container
|
||||
runs-on: ubuntu-latest
|
||||
container: catthehacker/ubuntu:act-latest
|
||||
needs: [container]
|
||||
needs: build
|
||||
if: gitea.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- name: Stop and remove current container
|
||||
@@ -97,11 +37,9 @@ jobs:
|
||||
-e MQTT_PASSWORD=${{ secrets.MQTT_PASSWORD }} \
|
||||
-e HUE_TOKEN=${{ secrets.HUE_TOKEN }} \
|
||||
-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
|
||||
|
||||
- name: Start container
|
||||
run: docker start automation_rs
|
||||
|
||||
# TODO: Perform a healthcheck
|
||||
|
||||
@@ -5,16 +5,12 @@ repos:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
args:
|
||||
- --allow-multiple-documents
|
||||
- id: check-toml
|
||||
- id: check-added-large-files
|
||||
- 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
|
||||
rev: v0.20.0
|
||||
hooks:
|
||||
@@ -26,7 +22,59 @@ repos:
|
||||
- id: typos
|
||||
args: ["--force-exclude"]
|
||||
|
||||
- repo: https://github.com/pryorda/dockerfilelint-precommit-hooks
|
||||
rev: v0.1.0
|
||||
- repo: local
|
||||
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]
|
||||
name = "automation"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
@@ -47,7 +47,6 @@ impls = "1.0.3"
|
||||
indexmap = { version = "2.0.0", features = ["serde"] }
|
||||
itertools = "0.13.0"
|
||||
json_value_merge = "2.0.0"
|
||||
pollster = "0.4.0"
|
||||
proc-macro2 = "1.0.81"
|
||||
quote = "1.0.36"
|
||||
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
|
||||
COPY ./config.lua /app/config.lua
|
||||
|
||||
COPY ./automation /app/automation
|
||||
|
||||
CMD ["/app/automation"]
|
||||
CMD [ "/app/automation" ]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "automation_cast"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "automation_devices"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
automation_lib = { workspace = true }
|
||||
|
||||
@@ -68,11 +68,11 @@ pub struct ContactSensor {
|
||||
}
|
||||
|
||||
impl ContactSensor {
|
||||
async fn state(&self) -> RwLockReadGuard<State> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
self.state.read().await
|
||||
}
|
||||
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||
self.state.write().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::OnMqtt;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use rumqttc::{matches, Publish};
|
||||
use rumqttc::{Publish, matches};
|
||||
use serde::Deserialize;
|
||||
use tracing::{debug, trace, warn};
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use automation_lib::messages::{RemoteAction, RemoteMessage};
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use axum::async_trait;
|
||||
use rumqttc::{matches, Publish};
|
||||
use rumqttc::{Publish, matches};
|
||||
use tracing::{debug, error, trace};
|
||||
|
||||
#[derive(Debug, Clone, LuaDeviceConfig)]
|
||||
|
||||
@@ -38,11 +38,11 @@ pub struct LightSensor {
|
||||
}
|
||||
|
||||
impl LightSensor {
|
||||
async fn state(&self) -> RwLockReadGuard<State> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
self.state.read().await
|
||||
}
|
||||
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||
self.state.write().await
|
||||
}
|
||||
}
|
||||
@@ -99,9 +99,7 @@ impl OnMqtt for LightSensor {
|
||||
let is_dark = self.state().await.is_dark;
|
||||
trace!(
|
||||
"In between min ({}) and max ({}) value, keeping current state: {}",
|
||||
self.config.min,
|
||||
self.config.max,
|
||||
is_dark
|
||||
self.config.min, self.config.max, is_dark
|
||||
);
|
||||
is_dark
|
||||
};
|
||||
|
||||
@@ -38,11 +38,11 @@ pub struct Washer {
|
||||
}
|
||||
|
||||
impl Washer {
|
||||
async fn state(&self) -> RwLockReadGuard<State> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
self.state.read().await
|
||||
}
|
||||
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||
self.state.write().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use google_home::device;
|
||||
use google_home::errors::ErrorCode;
|
||||
use google_home::traits::{Brightness, Color, ColorSetting, ColorTemperatureRange, OnOff};
|
||||
use google_home::types::Type;
|
||||
use rumqttc::{matches, Publish};
|
||||
use rumqttc::{Publish, matches};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
@@ -100,11 +100,11 @@ pub type LightBrightness = Light<StateBrightness>;
|
||||
pub type LightColorTemperature = Light<StateColorTemperature>;
|
||||
|
||||
impl<T: LightState> Light<T> {
|
||||
async fn state(&self) -> RwLockReadGuard<T> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, T> {
|
||||
self.state.read().await
|
||||
}
|
||||
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<T> {
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, T> {
|
||||
self.state.write().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use google_home::device;
|
||||
use google_home::errors::ErrorCode;
|
||||
use google_home::traits::OnOff;
|
||||
use google_home::types::Type;
|
||||
use rumqttc::{matches, Publish};
|
||||
use rumqttc::{Publish, matches};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
@@ -95,11 +95,11 @@ pub type OutletOnOff = Outlet<StateOnOff>;
|
||||
pub type OutletPower = Outlet<StatePower>;
|
||||
|
||||
impl<T: OutletState> Outlet<T> {
|
||||
async fn state(&self) -> RwLockReadGuard<T> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, T> {
|
||||
self.state.read().await
|
||||
}
|
||||
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<T> {
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, T> {
|
||||
self.state.write().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "automation_lib"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
automation_macro = { workspace = true }
|
||||
@@ -15,14 +15,12 @@ reqwest = { workspace = true }
|
||||
serde_repr = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
pollster = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
tokio-cron-scheduler = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
tokio-util = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
dyn-clone = { workspace = true }
|
||||
impls = { workspace = true }
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::collections::HashMap;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::future::join_all;
|
||||
use futures::Future;
|
||||
use futures::future::join_all;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
use tokio_cron_scheduler::{Job, JobScheduler};
|
||||
use tracing::{debug, instrument, trace};
|
||||
@@ -64,7 +64,7 @@ impl DeviceManager {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ impl fmt::Display for MissingEnv {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Missing environment variable")?;
|
||||
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 {
|
||||
write!(f, " '{}'", self.keys[0])?;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(specialization)]
|
||||
#![feature(let_chains)]
|
||||
|
||||
pub mod action_callback;
|
||||
pub mod config;
|
||||
|
||||
@@ -9,7 +9,7 @@ use serde::Serialize;
|
||||
use serde_repr::*;
|
||||
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};
|
||||
|
||||
#[derive(Debug, Serialize_repr, Clone, Copy)]
|
||||
|
||||
@@ -10,7 +10,7 @@ use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use tracing::{debug, trace, warn};
|
||||
|
||||
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::messages::PresenceMessage;
|
||||
use crate::mqtt::WrappedAsyncClient;
|
||||
@@ -40,11 +40,11 @@ pub struct Presence {
|
||||
}
|
||||
|
||||
impl Presence {
|
||||
async fn state(&self) -> RwLockReadGuard<State> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
self.state.read().await
|
||||
}
|
||||
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<State> {
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||
self.state.write().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "automation_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#![feature(let_chains)]
|
||||
#![feature(iter_intersperse)]
|
||||
mod lua_device_config;
|
||||
|
||||
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))]
|
||||
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::token::Paren;
|
||||
use syn::{
|
||||
parenthesized, Data, DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed, LitStr, Result,
|
||||
Token, Type,
|
||||
Data, DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed, LitStr, Result, Token, Type,
|
||||
parenthesized,
|
||||
};
|
||||
|
||||
mod kw {
|
||||
@@ -155,7 +155,7 @@ fn field_from_lua(field: &Field) -> TokenStream {
|
||||
[] => field.ident.clone().unwrap().to_string(),
|
||||
[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)},
|
||||
[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.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]
|
||||
name = "google_home"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# 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 automation_cast::Cast;
|
||||
use futures::future::{join_all, OptionFuture};
|
||||
use futures::future::{OptionFuture, join_all};
|
||||
use thiserror::Error;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::Device;
|
||||
use crate::errors::{DeviceError, ErrorCode};
|
||||
use crate::request::{self, Intent, Request};
|
||||
use crate::response::{self, execute, query, sync, Response, ResponsePayload};
|
||||
use crate::Device;
|
||||
use crate::response::{self, Response, ResponsePayload, execute, query, sync};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GoogleHome {
|
||||
@@ -64,7 +64,7 @@ impl GoogleHome {
|
||||
devices: &HashMap<String, Box<T>>,
|
||||
) -> sync::Payload {
|
||||
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() {
|
||||
Some(Device::sync(device).await)
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(specialization)]
|
||||
#![feature(let_chains)]
|
||||
pub mod device;
|
||||
mod fulfillment;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ use automation_cast::Cast;
|
||||
use google_home_macro::traits;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::errors::ErrorCode;
|
||||
use crate::Device;
|
||||
use crate::errors::ErrorCode;
|
||||
|
||||
traits! {
|
||||
Device,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "google_home_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![feature(let_chains)]
|
||||
#![feature(iter_intersperse)]
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
@@ -6,8 +5,8 @@ use syn::parse::Parse;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::token::Brace;
|
||||
use syn::{
|
||||
braced, parse_macro_input, GenericArgument, Ident, LitStr, Path, PathArguments, PathSegment,
|
||||
ReturnType, Signature, Token, Type, TypePath,
|
||||
GenericArgument, Ident, LitStr, Path, PathArguments, PathSegment, ReturnType, Signature, Token,
|
||||
Type, TypePath, braced, parse_macro_input,
|
||||
};
|
||||
|
||||
mod kw {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2024-12-06"
|
||||
channel = "nightly-2025-08-20"
|
||||
components = ["rustfmt", "clippy", "rust-analyzer"]
|
||||
profile = "minimal"
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::result;
|
||||
|
||||
use axum::async_trait;
|
||||
use axum::extract::{FromRef, FromRequestParts};
|
||||
use axum::http::StatusCode;
|
||||
use axum::http::request::Parts;
|
||||
use axum::http::status::InvalidStatusCode;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::IntoResponse;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
Reference in New Issue
Block a user