stream_deck_sdk 1.0.6

Rust unofficial SDK for the Elgato Stream Deck
Documentation
use std::collections::HashMap;
use std::sync::Arc;

use futures_channel::mpsc::UnboundedSender;
use futures_util::SinkExt;
use serde::de::value::MapDeserializer;
use serde_json::Value;
use tokio::sync::Mutex;
use tungstenite::Message;

use crate::events::sent::{get_global_settings_event, open_url, set_feedback, set_feedback_layout};
use crate::{
    get_settings_event, log_message, register, send_to_property_inspector, set_global_settings,
    set_image, set_settings, set_state, set_title, show_alert, show_ok, switch_to_profile,
    ActionState, StreamDeckArgs, StreamDeckTarget,
};

#[derive(Clone)]
pub struct StreamDeck {
    pub contexts: Arc<Mutex<HashMap<String, Vec<String>>>>,
    args: StreamDeckArgs,
    pub(crate) global_settings: Arc<Mutex<HashMap<String, Value>>>,
    pub(crate) instances_settings: Arc<Mutex<HashMap<String, HashMap<String, Value>>>>,
    tx: UnboundedSender<Message>,
    ext_tx: Option<UnboundedSender<String>>,
}

impl StreamDeck {
    pub fn to_arc(&self) -> Arc<StreamDeck> {
        Arc::new(self.clone())
    }

    pub fn new(
        args: StreamDeckArgs,
        tx: UnboundedSender<Message>,
        ext_tx: Option<UnboundedSender<String>>,
    ) -> Self {
        Self {
            contexts: Arc::new(Mutex::new(HashMap::new())),
            args,
            tx,
            global_settings: Arc::new(Mutex::new(HashMap::new())),
            instances_settings: Arc::new(Mutex::new(HashMap::new())),
            ext_tx,
        }
    }

    pub async fn global_settings<T: serde::de::DeserializeOwned>(&self) -> Option<T> {
        let deserialized = T::deserialize(MapDeserializer::new(
            self.global_settings.lock().await.clone().into_iter(),
        ));
        match deserialized {
            Ok(deserialized) => Some(deserialized),
            Err(_) => None,
        }
    }

    pub async fn settings<T: serde::de::DeserializeOwned>(&self, context: String) -> Option<T> {
        let all_settings = self.instances_settings.lock().await;
        let settings = all_settings.get(&context);
        match settings {
            Some(settings) => {
                let deserialized =
                    T::deserialize(MapDeserializer::new(settings.clone().into_iter()));
                match deserialized {
                    Ok(deserialized) => Some(deserialized),
                    Err(_) => None,
                }
            }
            None => None,
        }
    }

    pub async fn external(&self, data: String) {
        self.ext_tx.clone().unwrap().send(data).await.unwrap();
    }

    pub(crate) async fn send(&self, content: String) {
        self.tx
            .clone()
            .send(Message::Text(content))
            .await
            .expect("Cannot send message");
    }

    pub async fn register(&self) {
        let uuid = self.args.plugin_uuid.clone();
        self.send(register(self.args.register_event.clone(), uuid.clone()))
            .await;
        self.send(get_global_settings_event(uuid)).await
    }

    pub async fn set_title(&self, context: String, title: Option<String>) {
        #[cfg(feature = "logging")]
        println!(" > set_title: {:?}", title);
        self.send(set_title(context, title, None, None)).await;
    }

    pub async fn contexts_of(&self, uuid: &str) -> Vec<String> {
        let contexts = self.contexts.lock().await;
        if contexts.contains_key(uuid) {
            contexts.get(uuid).unwrap().clone()
        } else {
            vec![]
        }
    }

    pub async fn set_title_extra(
        &self,
        context: String,
        title: Option<String>,
        target: Option<StreamDeckTarget>,
        state: Option<ActionState>,
    ) {
        self.send(set_title(context, title, target, state)).await;
    }

    pub async fn set_image_b64(&self, context: String, base64: Option<String>) {
        self.send(set_image(context, base64, None, None)).await;
    }

    pub async fn show_ok(&self, context: String) {
        self.send(show_ok(context)).await;
    }

    pub async fn log(&self, message: String) {
        self.send(log_message(message)).await;
    }

    pub async fn show_alert(&self, context: String) {
        self.send(show_alert(context)).await;
    }

    pub async fn switch_to_profile(&self, device: String, profile: String) {
        self.send(switch_to_profile(
            self.args.plugin_uuid.clone(),
            device,
            profile,
        ))
        .await;
    }

    pub async fn send_to_property_inspector(
        &self,
        action: String,
        context: String,
        payload: HashMap<String, Value>,
    ) {
        self.send(send_to_property_inspector(action, context, payload))
            .await;
    }

    pub async fn set_state(&self, context: String, state: i32) {
        self.send(set_state(context, state)).await;
    }

    pub async fn set_feedback(&self, context: String, feedback: Value) {
        self.send(set_feedback(context, feedback)).await;
    }

    pub async fn set_feedback_layout(&self, context: String, layout: String) {
        self.send(set_feedback_layout(context, layout)).await;
    }

    pub async fn open_url(&self, url: String) {
        self.send(open_url(url)).await;
    }

    pub async fn set_settings<Settings: serde::ser::Serialize>(
        &self,
        context: String,
        settings: Settings,
    ) {
        self.send(set_settings(&context, settings)).await;
        self.send(get_settings_event(context)).await;
    }

    pub async fn update_global_settings(
        &self,
        settings: HashMap<String, Value>,
        update: Option<bool>,
    ) {
        let mut locked = self.global_settings.lock().await;
        settings.iter().for_each(|(k, v)| {
            locked.insert(k.clone(), v.clone());
        });
        if update.is_some() {
            self.set_global_settings(locked.clone()).await;
        }
    }

    pub(crate) async fn update_instances_settings(
        &self,
        context: String,
        settings: HashMap<String, Value>,
    ) {
        let mut locked = self.instances_settings.lock().await;
        locked.insert(context, settings);
    }

    pub async fn set_global_settings<GlobalSettings: serde::ser::Serialize + Clone>(
        &self,
        settings: GlobalSettings,
    ) {
        self.send(set_global_settings(self.args.plugin_uuid.clone(), settings))
            .await;
        self.send(get_global_settings_event(self.args.plugin_uuid.clone()))
            .await;
    }
}