use serde::Deserialize;
use thiserror::Error;
use crate::{BoardData, Vestaboard};
const RW_API_URI: &str = "https://rw.vestaboard.com/";
const RW_API_HEADER: &str = "X-Vestaboard-Read-Write-Key";
#[derive(Debug, Clone)]
pub struct RWConfig {
pub read_write_key: String,
}
impl<const ROWS: usize, const COLS: usize> Vestaboard<RWConfig, ROWS, COLS> {
pub fn new_rw_api(config: RWConfig) -> Self {
use std::str::FromStr;
let headers = reqwest::header::HeaderMap::from_iter([
(
reqwest::header::CONTENT_TYPE,
reqwest::header::HeaderValue::from_static("application/json"),
),
(
reqwest::header::HeaderName::from_str(RW_API_HEADER).unwrap(),
reqwest::header::HeaderValue::from_str(&config.read_write_key).expect("failed to parse read/write key"),
),
]);
Vestaboard {
client: reqwest::Client::builder()
.default_headers(headers)
.user_agent(format!("vestaboard-rs/{}", env!("CARGO_PKG_VERSION")))
.build()
.expect("failed to build reqwest client"),
config,
}
}
pub async fn read(&self) -> Result<RWApiReadMessage<ROWS, COLS>, RWApiError> {
use std::str::FromStr;
let res = self.client.get(RW_API_URI).send().await?;
if !res.status().is_success() {
return Err(RWApiError::ApiError(res.text().await?));
}
let res = res.json::<RWApiReadResponse>().await?;
let board = BoardData::from_str(&res.current_message.layout)?;
Ok(RWApiReadMessage {
layout: res.current_message.layout,
id: res.current_message.id,
board,
})
}
pub async fn write(&self, message: BoardData<ROWS, COLS>) -> Result<RWApiWriteResponse, RWApiError> {
let res = self.client.post(RW_API_URI).json(&message).send().await?;
if !res.status().is_success() {
return Err(RWApiError::ApiError(res.text().await?));
}
Ok(res.json::<RWApiWriteResponse>().await?)
}
}
pub struct RWApiReadMessage<const ROWS: usize, const COLS: usize> {
pub layout: String,
pub id: String,
pub board: BoardData<ROWS, COLS>,
}
#[derive(Debug, Clone, Deserialize)]
struct RWApiRawMessage {
pub layout: String,
pub id: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct RWApiReadResponse {
pub current_message: RWApiRawMessage,
}
#[derive(Debug, Clone, Deserialize)]
pub struct RWApiWriteResponse {
pub status: String,
pub id: String,
pub created: usize,
}
#[derive(Error, Debug)]
pub enum RWApiError {
#[error("reqwest error: {0}")]
Reqwest(#[from] reqwest::Error),
#[error("failed to parse response: {0}")]
Deserialize(#[from] serde_json::Error),
#[error("failed to parse message layout: {0}")]
ParseBoardData(#[from] crate::board::BoardError),
#[error("api error: {0}")]
ApiError(String),
}