forked from Dstack-TEE/dstack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdstack_client.rs
More file actions
149 lines (131 loc) · 4.7 KB
/
Copy pathdstack_client.rs
File metadata and controls
149 lines (131 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-FileCopyrightText: © 2025 Created-for-a-purpose <rachitchahar@gmail.com>
// SPDX-FileCopyrightText: © 2025 Daniel Sharifi <daniel.sharifi@nearone.org>
// SPDX-FileCopyrightText: © 2025 tuddman <tuddman@users.noreply.github.com>
//
// SPDX-License-Identifier: Apache-2.0
use anyhow::Result;
use hex::encode as hex_encode;
use http_client_unix_domain_socket::{ClientUnix, Method};
use reqwest::Client;
use serde::{de::DeserializeOwned, Serialize};
use serde_json::{json, Value};
use std::env;
pub use dstack_sdk_types::dstack::*;
fn get_endpoint(endpoint: Option<&str>) -> String {
if let Some(e) = endpoint {
return e.to_string();
}
if let Ok(sim_endpoint) = env::var("DSTACK_SIMULATOR_ENDPOINT") {
return sim_endpoint;
}
"/var/run/dstack.sock".to_string()
}
#[derive(Debug)]
pub enum ClientKind {
Http,
Unix,
}
pub trait BaseClient {}
/// The main client for interacting with the dstack service
pub struct DstackClient {
/// The base URL for HTTP requests
base_url: String,
/// The endpoint for Unix domain socket communication
endpoint: String,
/// The type of client (HTTP or Unix domain socket)
client: ClientKind,
}
impl BaseClient for DstackClient {}
impl DstackClient {
pub fn new(endpoint: Option<&str>) -> Self {
let endpoint = get_endpoint(endpoint);
let (base_url, client) = match endpoint {
ref e if e.starts_with("http://") || e.starts_with("https://") => {
(e.to_string(), ClientKind::Http)
}
_ => ("http://localhost".to_string(), ClientKind::Unix),
};
DstackClient {
base_url,
endpoint,
client,
}
}
async fn send_rpc_request<S: Serialize, D: DeserializeOwned>(
&self,
path: &str,
payload: &S,
) -> anyhow::Result<D> {
match &self.client {
ClientKind::Http => {
let client = Client::new();
let url = format!(
"{}/{}",
self.base_url.trim_end_matches('/'),
path.trim_start_matches('/')
);
let res = client
.post(&url)
.json(payload)
.header("Content-Type", "application/json")
.send()
.await?
.error_for_status()?;
Ok(res.json().await?)
}
ClientKind::Unix => {
let mut unix_client = ClientUnix::try_new(&self.endpoint).await?;
let res = unix_client
.send_request_json::<_, _, Value>(
path,
Method::POST,
&[("Content-Type", "application/json")],
Some(&payload),
)
.await?;
Ok(res.1)
}
}
}
pub async fn get_key(
&self,
path: Option<String>,
purpose: Option<String>,
) -> Result<GetKeyResponse> {
let data = json!({
"path": path.unwrap_or_default(),
"purpose": purpose.unwrap_or_default(),
});
let response = self.send_rpc_request("/GetKey", &data).await?;
let response = serde_json::from_value::<GetKeyResponse>(response)?;
Ok(response)
}
pub async fn get_quote(&self, report_data: Vec<u8>) -> Result<GetQuoteResponse> {
if report_data.is_empty() || report_data.len() > 64 {
anyhow::bail!("Invalid report data length")
}
let hex_data = hex_encode(report_data);
let data = json!({ "report_data": hex_data });
let response = self.send_rpc_request("/GetQuote", &data).await?;
let response = serde_json::from_value::<GetQuoteResponse>(response)?;
Ok(response)
}
pub async fn info(&self) -> Result<InfoResponse> {
let response = self.send_rpc_request("/Info", &json!({})).await?;
Ok(InfoResponse::validated_from_value(response)?)
}
pub async fn emit_event(&self, event: String, payload: Vec<u8>) -> Result<()> {
if event.is_empty() {
anyhow::bail!("Event name cannot be empty")
}
let hex_payload = hex_encode(payload);
let data = json!({ "event": event, "payload": hex_payload });
self.send_rpc_request::<_, ()>("/EmitEvent", &data).await?;
Ok(())
}
pub async fn get_tls_key(&self, tls_key_config: TlsKeyConfig) -> Result<GetTlsKeyResponse> {
let response = self.send_rpc_request("/GetTlsKey", &tls_key_config).await?;
let response = serde_json::from_value::<GetTlsKeyResponse>(response)?;
Ok(response)
}
}