feat: add webhooks with basic json to send to
This commit is contained in:
parent
18aa3dfaa8
commit
1b0284b00b
7 changed files with 1432 additions and 10 deletions
1311
Cargo.lock
generated
1311
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -4,8 +4,12 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1.36", features = ["full"] }
|
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
rppal = "0.22.1"
|
rppal = "0.22"
|
||||||
|
reqwest = { version = "0.12", features = ["json"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
chrono = "0.4"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ cargo zigbuild --release --target aarch64-unknown-linux-gnu
|
||||||
echo "Copying to Raspberry Pi..."
|
echo "Copying to Raspberry Pi..."
|
||||||
scp target/aarch64-unknown-linux-gnu/release/noisebell noisebridge@noisebell.local:~/
|
scp target/aarch64-unknown-linux-gnu/release/noisebell noisebridge@noisebell.local:~/
|
||||||
|
|
||||||
echo "Setting permissions and restarting service..."
|
echo "Setting permissions"
|
||||||
ssh noisebridge@noisebell.local "chmod +x ~/noisebell "
|
ssh noisebridge@noisebell.local "chmod +x ~/noisebell "
|
||||||
|
|
||||||
echo "Deployment complete!"
|
echo "Deployment complete!"
|
||||||
|
|
|
||||||
16
endpoints.json
Normal file
16
endpoints.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"url": "http://localhost:8080/webhook",
|
||||||
|
"description": "Local development endpoint"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://api.example.com/notifications",
|
||||||
|
"description": "Production notification service"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://webhook.site/your-unique-id",
|
||||||
|
"description": "Webhook testing service"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
13
src/gpio.rs
13
src/gpio.rs
|
|
@ -1,14 +1,25 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::fmt;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use rppal::gpio::{Gpio, InputPin, Level};
|
use rppal::gpio::{Gpio, InputPin, Level};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum CircuitEvent {
|
pub enum CircuitEvent {
|
||||||
Open,
|
Open,
|
||||||
Closed,
|
Closed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CircuitEvent {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
CircuitEvent::Open => write!(f, "open"),
|
||||||
|
CircuitEvent::Closed => write!(f, "closed"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct GpioMonitor {
|
pub struct GpioMonitor {
|
||||||
pin: InputPin,
|
pin: InputPin,
|
||||||
poll_interval: Duration,
|
poll_interval: Duration,
|
||||||
|
|
|
||||||
16
src/main.rs
16
src/main.rs
|
|
@ -1,4 +1,5 @@
|
||||||
mod gpio;
|
mod gpio;
|
||||||
|
mod webhook;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
@ -7,24 +8,29 @@ use tracing::{error, info};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
// Initialize logging
|
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
// Initialize GPIO monitor
|
|
||||||
const DEFAULT_GPIO_PIN: u8 = 17;
|
const DEFAULT_GPIO_PIN: u8 = 17;
|
||||||
let gpio_pin = std::env::var("GPIO_PIN")
|
let gpio_pin = std::env::var("GPIO_PIN")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|v| v.parse().ok())
|
.and_then(|v| v.parse().ok())
|
||||||
.unwrap_or(DEFAULT_GPIO_PIN);
|
.unwrap_or(DEFAULT_GPIO_PIN);
|
||||||
|
|
||||||
|
let webhook_notifier = webhook::WebhookNotifier::new()?;
|
||||||
let mut gpio_monitor = gpio::GpioMonitor::new(gpio_pin, Duration::from_millis(100))?;
|
let mut gpio_monitor = gpio::GpioMonitor::new(gpio_pin, Duration::from_millis(100))?;
|
||||||
|
|
||||||
// Simple callback function that just logs the event
|
let callback = move |event: gpio::CircuitEvent| {
|
||||||
let callback = |event: gpio::CircuitEvent| {
|
|
||||||
info!("Circuit state changed: {:?}", event);
|
info!("Circuit state changed: {:?}", event);
|
||||||
|
|
||||||
|
// Clone the webhook notifier for the async block
|
||||||
|
let notifier = webhook_notifier.clone();
|
||||||
|
|
||||||
|
// Spawn a new task to send webhooks
|
||||||
|
tokio::spawn(async move {
|
||||||
|
notifier.notify_all("circuit_state_change", event).await;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start GPIO monitoring
|
|
||||||
if let Err(e) = gpio_monitor.monitor(callback).await {
|
if let Err(e) = gpio_monitor.monitor(callback).await {
|
||||||
error!("GPIO monitoring error: {}", e);
|
error!("GPIO monitoring error: {}", e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
76
src/webhook.rs
Normal file
76
src/webhook.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fs;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
use crate::gpio::CircuitEvent;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
struct Endpoint {
|
||||||
|
url: String,
|
||||||
|
description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct EndpointsConfig {
|
||||||
|
endpoints: Vec<Endpoint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct WebhookPayload {
|
||||||
|
event_type: String,
|
||||||
|
timestamp: String,
|
||||||
|
new_state: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct WebhookNotifier {
|
||||||
|
client: Client,
|
||||||
|
endpoints: Vec<Endpoint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebhookNotifier {
|
||||||
|
pub fn new() -> Result<Self> {
|
||||||
|
let config = fs::read_to_string("endpoints.json")?;
|
||||||
|
let endpoints_config: EndpointsConfig = serde_json::from_str(&config)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
client: Client::new(),
|
||||||
|
endpoints: endpoints_config.endpoints,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn notify_all(&self, event_type: &str, state: CircuitEvent) {
|
||||||
|
let payload = WebhookPayload {
|
||||||
|
event_type: event_type.to_string(),
|
||||||
|
timestamp: chrono::Utc::now().to_rfc3339(),
|
||||||
|
new_state: state.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for endpoint in &self.endpoints {
|
||||||
|
info!("Sending webhook to {}: {}", endpoint.description, serde_json::to_string(&payload).unwrap());
|
||||||
|
match self.client
|
||||||
|
.post(&endpoint.url)
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
info!(
|
||||||
|
"Successfully sent webhook to {}: {}",
|
||||||
|
endpoint.description,
|
||||||
|
response.status()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"Failed to send webhook to {}: {}",
|
||||||
|
endpoint.description,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue