haply 0.8.1

Haply Robotics Client Library for the Inverse Service
Documentation
//! HTTP client module for communicating with the Haply Inverse Service.
//! Provides functionality for querying device information and service status.

use crate::device_model::{
    Inverse3Device,
    VerseGripDevice,
    WirelessVerseGripDevice,
    Config,
};
use reqwest::Client;
use serde::Deserialize;
use crate::device_model::VersionResponse;

// Assuming custom verse grips are also WirelessVerseGrip
type CustomVerseGripDevice = WirelessVerseGripDevice;

/// Response structure for device queries containing device information.
#[derive(Debug, Deserialize)]
pub struct DevicesResponse {
    pub session_id: u64,
    pub inverse3: Vec<Inverse3Device>,
    pub verse_grip: Vec<VerseGripDevice>,
    pub wireless_verse_grip: Vec<WirelessVerseGripDevice>,
    pub custom_verse_grip: Vec<CustomVerseGripDevice>,
}

/// HTTP client implementation for the Haply Inverse Service.
/// Handles all HTTP-based communication with the service endpoint.
pub struct InverseHttpClient {
    client: Client,
    base_url: String,
}

impl InverseHttpClient {
    /// Create a new HTTP client with the given base URL (e.g. "http://localhost:10000").
    pub fn new(base_url: &str) -> Self {
        Self {
            client: Client::new(),
            base_url: base_url.trim_end_matches('/').to_string(),
        }
    }

    /// Get the list of devices.
    pub async fn get_devices(&self) -> Result<Vec<Config>, Box<dyn std::error::Error + Send + Sync>> {
        let url = format!("{}/3.1/devices", self.base_url);
        let resp = self.client.get(&url).send().await?.json::<DevicesResponse>().await?;

        /// Helper function to map devices to Config enum variants
        fn map_devices<D, F>(devices: Vec<D>, mut mapper: F) -> Result<Vec<Config>, Box<dyn std::error::Error + Send + Sync>>
        where
            F: FnMut(D) -> Result<Config, Box<dyn std::error::Error + Send + Sync>>,
        {
            devices.into_iter().map(|d| mapper(d)).collect()
        }

        let mut device_configs: Vec<Config> = Vec::new();
        
        // Inverse3 devices
        device_configs.extend(map_devices(resp.inverse3, |d| {
            let mut config = d.config.ok_or("Missing config for Inverse3 device")?;
            config.id = d.device_id.clone();
            config.device_info.id = d.device_id;
            Ok(Config::DeviceConfig(config))
        })?);

        // Verse Grip devices
        device_configs.extend(map_devices(resp.verse_grip, |d| {
            let mut config = d.config.ok_or("Missing config for Verse Grip device")?;
            config.id = d.device_id;
            Ok(Config::VGConfig(config))
        })?);

        // Wireless Verse Grip devices
        device_configs.extend(map_devices(resp.wireless_verse_grip, |d| {
            let mut config = d.config.ok_or("Missing config for Wireless Verse Grip device")?;
            config.id = d.device_id;
            Ok(Config::WVGConfig(config))
        })?);

        // Custom Verse Grip devices
        device_configs.extend(map_devices(resp.custom_verse_grip, |d| {
            let mut config = d.config.ok_or("Missing config for Custom Verse Grip device")?;
            config.id = d.device_id;
            Ok(Config::WVGConfig(config))
        })?);

        Ok(device_configs)
    }

    /// Get the version of the service.
    pub async fn get_version(&self) -> Result<VersionResponse, reqwest::Error> {
        let url = format!("{}/version", self.base_url);
        let resp = self.client.get(&url).send().await?.json::<VersionResponse>().await?;
        Ok(resp)
    }

    // Other HTTP functions (e.g., get_version, gravity_compensation, etc.) can be added here.
}