#![forbid(unsafe_code)]
use std::env;
use serde::{Deserialize, Serialize};
use serde_json::json;
use jsonrpsee::core::client::ClientT;
use jsonrpsee::core::params::ObjectParams;
use jsonrpsee::http_client::{HeaderMap, HeaderValue, HttpClient, HttpClientBuilder};
use std::time::Duration;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
#[derive(Debug, Serialize, Deserialize)]
struct CryptolResult {
#[serde(default)]
answer: serde_json::Value,
state: String,
stderr: String,
stdout: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Answer {
#[serde(rename = "type")]
answer_type: serde_json::Value,
#[serde(rename = "type string")]
type_string: String,
pub value: serde_json::Value,
}
#[derive(Serialize, Deserialize)]
pub struct CryptolError {
code: i64,
data: CryptolErrorData,
message: String,
}
#[derive(Serialize, Deserialize)]
pub struct CryptolErrorData {
data: CryptolDataData,
stderr: String,
stdout: String,
}
#[derive(Serialize, Deserialize)]
pub struct CryptolDataData {
path: Vec<String>,
source: String,
warnings: Vec<Option<serde_json::Value>>,
}
#[derive(Debug, Clone)]
pub struct CryptolClient {
client: HttpClient,
state: String,
answer: serde_json::Value,
}
impl CryptolClient {
#[tokio::main]
pub async fn connect() -> Result<CryptolClient> {
let cryptol_server_url = match env::var("CRYPTOL_SERVER_URL") {
Ok(val) => {
println!("Attempting to connect to cryptol-remote-api at {val}.");
val
}
Err(e) => return Err(e.into()),
};
let mut headers = HeaderMap::new();
headers.insert("Connection", HeaderValue::from_static("keep-alive"));
let client = HttpClientBuilder::default()
.set_headers(headers)
.request_timeout(Duration::from_secs(60 * 60)) .build(cryptol_server_url)?;
let mut params = ObjectParams::new();
params.insert("state", json!(null))?;
params.insert("module name", "Cryptol")?;
let response: CryptolResult = client.request("load module", params).await?;
Ok(CryptolClient {
client,
state: response.state.clone(),
answer: response.answer,
})
}
#[tokio::main]
async fn request(&mut self, action: &str, params: ObjectParams) -> Result<()> {
let response: CryptolResult = self.client.request(action, params).await?;
self.state = response.state.clone();
self.answer = response.answer;
Ok(())
}
pub fn load_module(&mut self, module: &str) -> Result<()> {
let mut params = ObjectParams::new();
params.insert("state", json!(self.state))?;
params.insert("module name", module)?;
self.request("load module", params)?;
Ok(())
}
pub fn call<P: Serialize>(&mut self, function: &str, arguments: &[P]) -> Result<Answer> {
let mut params = ObjectParams::new();
params.insert("state", json!(self.state))?;
params.insert("function", json!(function))?;
params.insert("arguments", json!(arguments))?;
self.request("call", params)?;
let answer: Answer = serde_json::from_value(self.answer.clone())?;
Ok(answer)
}
}