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}