Skip to main content

Device

Struct Device 

Source
pub struct Device<Io: IoImpl<UdpSocket, TcpStream, TcpListener, TlsStream>, UdpSocket: UdpSocketImpl, TcpStream: TcpStreamImpl, TcpListener: TcpListenerImpl<TcpStream>, TlsStream: TlsStreamImpl> { /* private fields */ }
Expand description

Structure representing the host device.

To make one, you need to make a configuration with DeviceConfig, to choose plugins to use, you need a trust handler i.e a structure implementing TrustHandler and an IO implementation of your choice (you can use TokioIoImpl as a default).

§Example

This code snippet launches a new device with no plugin defined and the trust handler defined in the example of TrustHandler, assuming that an X.509 certificate exists at cert.pem and an X.509 private key exists at private_key.pem (see DeviceConfig to learn how to create them).

To learn how to make plugins, check Plugin.

use std::{fs, collections::HashMap, path::{Path, PathBuf}};
use kdeconnect_proto::{
    config::DeviceConfig,
    device::{Device, DeviceType},
    trust::TrustHandler,
    io::TokioIoImpl,
};

struct TrustHandlerImpl {
   path: PathBuf,
   trusted_devices: HashMap<String, Vec<u8>>,
}

impl TrustHandlerImpl {
   pub fn new<P: AsRef<Path>>(path: P) -> Self {
       let path = path.as_ref();

       let trusted_devices = if path.exists() {
            HashMap::from_iter(fs::read_dir(path).unwrap().filter_map(Result::ok).map(|f| {
                let device_id = f.path().file_stem().unwrap().to_string_lossy().to_string();
                let cert = fs::read(f.path()).expect("failed to read certificate");
                (device_id, cert)
            }))
        } else {
            fs::create_dir_all(path).expect("failed to create directory for trusted devices");
            HashMap::new()
        };

       Self {
           path: path.to_path_buf(),
           trusted_devices,
       }
   }
}

#[kdeconnect_proto::async_trait]
impl TrustHandler for TrustHandlerImpl {
    async fn trust_device(&mut self, device_id: String, cert: Vec<u8>) {
       fs::write(self.path.join(device_id.clone() + ".pem"), &cert).unwrap();
       self.trusted_devices.insert(device_id, cert);
   }

   async fn untrust_device(&mut self, device_id: &str) {
       fs::remove_file(self.path.join(device_id.to_string() + ".pem")).unwrap();
       self.trusted_devices.remove(device_id);
   }

   async fn get_certificate(&mut self, device_id: &str) -> Option<&[u8]> {
       self.trusted_devices.get(device_id).map(|v| &**v)
   }
}

let config = DeviceConfig {
    name: String::from("kdeconnect client"),
    device_type: DeviceType::Desktop,
    cert: fs::read("cert.pem").expect("failed to read certificate"),
    private_key: fs::read("private_key.pem").expect("failed to read private key"),
};

let device = Device::new(config, vec![], TrustHandlerImpl::new("trusted_devices"), TokioIoImpl);
device.start();

§Pairing

You need to manually accept each pair request coming from a peer device using the Device::accept_pair method. You can use a background asynchronous task to do that.

Implementations§

Source§

impl<Io: IoImpl<UdpSocket, TcpStream, TcpListener, TlsStream> + Unpin + 'static, UdpSocket: UdpSocketImpl + Unpin + 'static, TcpStream: TcpStreamImpl + Unpin + 'static, TcpListener: TcpListenerImpl<TcpStream> + Unpin + 'static, TlsStream: TlsStreamImpl + Unpin + 'static> Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>

Source

pub fn new<T: TrustHandler + Send + Sync + 'static>( config: DeviceConfig, plugins: Vec<Box<dyn Plugin + Send + Sync>>, trust_handler: T, io_impl: Io, ) -> Self

Make a new Device.

Get an arc mutex’d map of (Device ID, Link) pairs.

Source

pub async fn pair_with(&self, link_id: &str)

Pair with a peer device.

In most cases, the pair state will be advanced from PairState::Unpaired to PairState::Requested.

Source

pub async fn unpair_with(&self, link_id: &str)

Unpair from a peer device.

In most cases, the pair state will be advanced from PairState::Paired to PairState::Unpaired.

Source

pub async fn accept_pair(&self, link_id: &str)

Accept the pairing with a peer device which has already requested pairing.

In most cases, the pair state will be advanced from PairState::RequestedByPeer to PairState::Paired.

Source

pub async fn wait_for_connection(&self) -> String

Wait for a peer device to connect and return its device ID.

The connected device may or may not be paired.

Source

pub fn start_arced(self: Arc<Self>)

Start an internal task responsible for handling connections and managing state.

This function takes an Arc of self for easier usage of the Device structure.

Source

pub fn start(self)

Start an internal task responsible for handling connections and managing state.

Auto Trait Implementations§

§

impl<Io, UdpSocket, TcpStream, TcpListener, TlsStream> !Freeze for Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>

§

impl<Io, UdpSocket, TcpStream, TcpListener, TlsStream> !RefUnwindSafe for Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>

§

impl<Io, UdpSocket, TcpStream, TcpListener, TlsStream> Send for Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>
where Io: Send,

§

impl<Io, UdpSocket, TcpStream, TcpListener, TlsStream> Sync for Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>
where Io: Sync,

§

impl<Io, UdpSocket, TcpStream, TcpListener, TlsStream> !Unpin for Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>

§

impl<Io, UdpSocket, TcpStream, TcpListener, TlsStream> !UnsafeUnpin for Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>

§

impl<Io, UdpSocket, TcpStream, TcpListener, TlsStream> !UnwindSafe for Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.