pebbles 0.0.1

A unfinished webautomation framework for working with Firefox and the geckodriver.
Documentation
use crate::service::Service;
use crate::result::{PebblesError,PebblesErrorDetails};
use std::rc::Rc;
use serde_json::{Value, json};

use serde::{ser::SerializeStruct, Serializer};
use rand_distr::{Triangular, Distribution};

#[derive(Debug)]
pub struct Rect {
    pub x:i64,
    pub y:i64,
    pub width:i64,
    pub height:i64,
}

pub struct WebElement {
    service: Rc<Service>,
    id:String,
}

impl WebElement {
    pub fn new(service: Rc<Service>, id:&str) -> Self {
        WebElement {
            service,
            id:id.to_string(),
        }
    }

    pub fn rect(&self) -> Result<Rect, PebblesError> {
        let json_rect: Value = self.service
            .get(&format!("/element/{}/rect", self.id))?
            .json::<Value>()?
            ["value"].clone();
        Ok(Rect {
            x: match json_rect["x"].as_f64() {
                Some(value) => value as i64,
                None => {
                    return Err(PebblesError::PhrasingError(PebblesErrorDetails::new(
                        "Invalid Rect values from webdriver.",
                    )))
                }
            },
            y: match json_rect["y"].as_f64() {
                Some(value) => value as i64,
                None => {
                    return Err(PebblesError::PhrasingError(PebblesErrorDetails::new(
                        "Invalid Rect values from webdriver.",
                    )))
                }
            },
            width: match json_rect["width"].as_f64() {
                Some(value) => value as i64,
                None => {
                    return Err(PebblesError::PhrasingError(PebblesErrorDetails::new(
                        "Invalid Rect values from webdriver.",
                    )))
                }
            },
            height: match json_rect["height"].as_f64() {
                Some(value) => value as i64,
                None => {
                    return Err(PebblesError::PhrasingError(PebblesErrorDetails::new(
                        "Invalid Rect values from webdriver.",
                    )))
                }
            },
        })
    }

    pub fn point(&self) -> Result<(i64, i64), PebblesError> {
        let mut rng = rand::thread_rng();
        let rect = self.rect()?;
        let triangular_x = Triangular::new(0.0, rect.width as f64, rect.width as f64 / 2.0)
            .map_err(|_| PebblesError::PhrasingError(
                PebblesErrorDetails::new("Invalid Rect values from webdriver.")
            ))?;
        let triangular_y = Triangular::new(0.0, rect.height as f64, rect.height as f64 / 2.0)
            .map_err(|_| PebblesError::PhrasingError(
                PebblesErrorDetails::new("Invalid Rect values from webdriver.")
            ))?;
        Ok((triangular_x.sample(&mut rng) as i64, triangular_y.sample(&mut rng) as i64))
    }

    pub fn attribute(&self, name:&str) -> Result<Value, PebblesError> {
        let java_script: &'static str = include_str!("attribute.js");
        Ok(self
            .service
            .post(
                "/execute/sync",
                &json!({"script": format!("/* getAttribute */return ({}).apply(null, arguments);", java_script).as_str(), "args": [self, name]}),
            )?
            .json::<Value>()?["value"]
            .clone())
    }
}

impl std::fmt::Display for WebElement {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.id)
    }
}

impl serde::Serialize for WebElement {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state = serializer.serialize_struct("WebElement", 1)?;
        state.serialize_field("element-6066-11e4-a52e-4f735466cecf", &self.id)?;
        state.end()
    }
}