Skip to main content

kdeconnect_proto/
plugin.rs

1//! Define the [`Plugin`] trait used to make KDE Connect plugins.
2use crate::{
3    device::Link,
4    error::Result,
5    packet::{NetworkPacket, NetworkPacketType},
6};
7
8#[cfg(not(feature = "std"))]
9use alloc::{boxed::Box, vec::Vec};
10
11/// A plugin is a handler receiving specific packet types and emitting new packets.
12///
13/// Each plugin defines the set of packet types it supports using the [`Plugin::supported_incoming_packets`]
14/// and [`Plugin::supported_outgoing_packets`] methods. It can send initialization packets (e.g to
15/// implement clipboard functionality where the device sends the clipboard content at startup)
16/// during the [`Plugin::on_start`] method. Finally, it handles supported packet types in the
17/// [`Plugin::on_packet_received`] method.
18///
19/// When implementing this trait, you must prepend the `impl` statement with `#[kdeconnect_proto::async_trait]`.
20///
21/// ### Example
22///
23/// ```
24/// use kdeconnect_proto::{
25///     error::Result,
26///     device::Link,
27///     packet::{NetworkPacket, NetworkPacketType, NetworkPacketBody},
28///     plugin::Plugin,
29/// };
30///
31/// struct PingPlugin;
32///
33/// #[kdeconnect_proto::async_trait]
34/// impl Plugin for PingPlugin {
35///     fn supported_incoming_packets(&self) -> Vec<NetworkPacketType> {
36///        vec![NetworkPacketType::Ping]
37///     }
38///
39///     fn supported_outgoing_packets(&self) -> Vec<NetworkPacketType> {
40///         vec![NetworkPacketType::Ping]
41///     }
42///
43///     async fn on_packet_received(&self, packet: &NetworkPacket, link: &Link) -> Result<()> {
44///         match &packet.body {
45///             NetworkPacketBody::Ping(packet) => {
46///                 let device_name = link.info
47///                     .device_name
48///                     .as_ref()
49///                     .unwrap_or(&link.info.device_id);
50///                 let msg = if let Some(msg) = &packet.message {
51///                     format!(" \"{msg}\"")
52///                 } else {
53///                     String::new()
54///                 };
55///                 println!("PING{msg} from {device_name}!");
56///             }
57///             _ => unreachable!(),
58///         }
59///         Ok(())
60///     }
61///
62///     async fn on_start(&self, link: &Link) -> Result<()> {
63///         link.send(NetworkPacket::ping("Connected")).await;
64///         Ok(())
65///     }
66/// }
67/// ```
68#[async_trait::async_trait]
69pub trait Plugin {
70    /// Informative function returning the full list of supported packet types.
71    ///
72    /// Used to determine the capabilities of the device and if the plugin needs to be called when
73    /// a packet is received.
74    fn supported_incoming_packets(&self) -> Vec<NetworkPacketType>;
75
76    /// Informative function returning the full list of supported packet types.
77    ///
78    /// Used to determine the capabilities of the device.
79    fn supported_outgoing_packets(&self) -> Vec<NetworkPacketType>;
80
81    /// Method called when a packet is received.
82    ///
83    /// ### Errors
84    ///
85    /// This method can return an error which will be shown to users but don't stop the execution
86    /// of the event loop.
87    async fn on_packet_received(&self, packet: &NetworkPacket, link: &Link) -> Result<()>;
88
89    /// Method called when the plugin is loaded after establishing a connection with a new device.
90    ///
91    /// It's ensured that the new device is paired with the current device.
92    ///
93    /// It can be used, for instance, to send initialization packets.
94    ///
95    /// ### Errors
96    ///
97    /// If this method returns an error, the plugin is unloaded and its [`Plugin::on_packet_received`]
98    /// method will never be called.
99    async fn on_start(&self, link: &Link) -> Result<()>;
100}