use crate::channel::Channel;
use crate::error::{Result, UrbitAPIError};
use json::JsonValue;
use reqwest::blocking::{Client, Response};
use reqwest::header::{HeaderValue, COOKIE};
#[derive(Debug, Clone)]
pub struct ShipInterface {
pub url: String,
pub session_auth: HeaderValue,
pub ship_name: String,
req_client: Client,
}
impl ShipInterface {
pub fn new(ship_url: &str, ship_code: &str) -> Result<ShipInterface> {
let client = Client::new();
let login_url = format!("{}/~/login", ship_url);
let resp = client
.post(&login_url)
.body("password=".to_string() + &ship_code)
.send()?;
if resp.status().as_u16() != 204 {
return Err(UrbitAPIError::FailedToLogin);
}
let session_auth = resp
.headers()
.get("set-cookie")
.ok_or(UrbitAPIError::FailedToLogin)?;
let auth_string = session_auth
.to_str()
.map_err(|_| UrbitAPIError::FailedToLogin)?;
let end_pos = auth_string.find('=').ok_or(UrbitAPIError::FailedToLogin)?;
let ship_name = &auth_string[9..end_pos];
Ok(ShipInterface {
url: ship_url.to_string(),
session_auth: session_auth.clone(),
ship_name: ship_name.to_string(),
req_client: client,
})
}
pub fn ship_name_with_sig(&self) -> String {
format!("~{}", self.ship_name)
}
pub fn create_channel(&self) -> Result<Channel> {
Channel::new(self.clone())
}
pub fn send_put_request(&self, url: &str, body: &JsonValue) -> Result<Response> {
let json = body.dump();
let resp = self
.req_client
.put(url)
.header(COOKIE, self.session_auth.clone())
.header("Content-Type", "application/json")
.body(json);
Ok(resp.send()?)
}
pub fn scry(&self, app: &str, path: &str, mark: &str) -> Result<Response> {
let scry_url = format!("{}/~/scry/{}{}.{}", self.url, app, path, mark);
let resp = self
.req_client
.get(&scry_url)
.header(COOKIE, self.session_auth.clone())
.header("Content-Type", "application/json");
Ok(resp.send()?)
}
pub fn spider(
&self,
input_mark: &str,
output_mark: &str,
thread_name: &str,
body: &JsonValue,
) -> Result<Response> {
let json = body.dump();
let spider_url = format!(
"{}/spider/{}/{}/{}.json",
self.url, input_mark, thread_name, output_mark
);
let resp = self
.req_client
.post(&spider_url)
.header(COOKIE, self.session_auth.clone())
.header("Content-Type", "application/json")
.body(json);
Ok(resp.send()?)
}
}
impl Default for ShipInterface {
fn default() -> Self {
ShipInterface::new("http://0.0.0.0:8080", "lidlut-tabwed-pillex-ridrup").unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::subscription::Subscription;
use json::object;
#[test]
fn can_login() {
let ship_interface =
ShipInterface::new("http://0.0.0.0:8080", "lidlut-tabwed-pillex-ridrup").unwrap();
}
#[test]
fn can_create_channel() {
let ship_interface =
ShipInterface::new("http://0.0.0.0:8080", "lidlut-tabwed-pillex-ridrup").unwrap();
let channel = ship_interface.create_channel().unwrap();
channel.delete_channel();
}
#[test]
fn can_subscribe() {
let ship_interface =
ShipInterface::new("http://0.0.0.0:8080", "lidlut-tabwed-pillex-ridrup").unwrap();
let mut channel = ship_interface.create_channel().unwrap();
channel
.create_new_subscription("chat-view", "/primary")
.unwrap();
channel.find_subscription("chat-view", "/primary");
channel.unsubscribe("chat-view", "/primary");
channel.delete_channel();
}
#[test]
fn can_poke() {
let ship_interface =
ShipInterface::new("http://0.0.0.0:8080", "lidlut-tabwed-pillex-ridrup").unwrap();
let mut channel = ship_interface.create_channel().unwrap();
let poke_res = channel
.poke("hood", "helm-hi", &"A poke has been made".into())
.unwrap();
assert!(poke_res.status().as_u16() == 204);
channel.delete_channel();
}
#[test]
fn can_scry() {
let mut ship_interface =
ShipInterface::new("http://0.0.0.0:8080", "lidlut-tabwed-pillex-ridrup").unwrap();
let scry_res = ship_interface.scry("graph-store", "/keys", "json").unwrap();
assert!(scry_res.status().as_u16() == 200);
}
#[test]
fn can_spider() {
let mut ship_interface =
ShipInterface::new("http://0.0.0.0:8080", "lidlut-tabwed-pillex-ridrup").unwrap();
let create_req = object! {
"create": {
"resource": {
"ship": "~zod",
"name": "test",
},
"title": "Testing creation",
"description": "test",
"associated": {
"policy": {
"invite": {
"pending": []
}
}
},
"module": "chat",
"mark": "graph-validator-chat"
}
};
let spider_res = ship_interface
.spider("graph-view-action", "json", "graph-create", &create_req)
.unwrap();
assert!(spider_res.status().as_u16() == 200);
}
}