1use std::sync::Arc;
2
3use crate::{
4 types::Capability,
5 util::{create_websocket_client, query},
6 ClientInfo,
7};
8use anyhow::{anyhow, Context, Result};
9use futures::StreamExt;
10use graphql_client::{GraphQLQuery, Response};
11use graphql_ws_client::graphql::StreamingOperation;
12
13#[derive(GraphQLQuery)]
14#[graphql(
15 schema_path = "schema.gql",
16 query_path = "src/agent.gql",
17 response_derives = "Debug"
18)]
19pub struct RequestCapability;
20
21pub async fn request_capability(
22 executor_url: String,
23 app_name: String,
24 app_desc: String,
25 app_domain: String,
26 app_url: Option<String>,
27 app_icon_path: Option<String>,
28 capabilities: Option<Vec<Capability>>,
29) -> Result<String> {
30 let query = RequestCapability::build_query(request_capability::Variables {
31 auth_info: request_capability::AuthInfoInput {
32 app_name,
33 app_desc,
34 app_domain,
35 app_url,
36 app_icon_path,
37 capabilities: capabilities.map(|val| val.into_iter().map(|val| val.into()).collect()),
38 },
39 });
40 let response_body: Response<request_capability::ResponseData> = reqwest::Client::new()
41 .post(executor_url)
42 .json(&query)
43 .send()
44 .await?
45 .json()
46 .await?;
47
48 let response_data = response_body
49 .data
50 .ok_or_else(|| anyhow!("No data in response! Errors: {:?}", response_body.errors))?;
51 Ok(response_data.agent_request_capability)
52}
53
54#[derive(GraphQLQuery)]
55#[graphql(
56 schema_path = "schema.gql",
57 query_path = "src/agent.gql",
58 response_derives = "Debug"
59)]
60pub struct RetrieveCapability;
61
62pub async fn retrieve_capability(
63 executor_url: String,
64 request_id: String,
65 rand: String,
66) -> Result<String> {
67 let query =
68 RetrieveCapability::build_query(retrieve_capability::Variables { request_id, rand });
69 let response_body: Response<retrieve_capability::ResponseData> = reqwest::Client::new()
70 .post(executor_url)
71 .json(&query)
72 .send()
73 .await?
74 .json()
75 .await?;
76
77 let response_data = response_body
78 .data
79 .ok_or_else(|| anyhow!("No data in response! Errors: {:?}", response_body.errors))?;
80 Ok(response_data.agent_generate_jwt)
81}
82
83#[derive(GraphQLQuery)]
84#[graphql(
85 schema_path = "schema.gql",
86 query_path = "src/agent.gql",
87 response_derives = "Debug"
88)]
89pub struct Me;
90
91pub async fn me(executor_url: String, cap_token: String) -> Result<me::MeAgent> {
92 let response_data: me::ResponseData =
93 query(executor_url, cap_token, Me::build_query(me::Variables {}))
94 .await
95 .with_context(|| "Failed to run agent->me query")?;
96 Ok(response_data.agent)
97}
98
99#[derive(GraphQLQuery)]
100#[graphql(
101 schema_path = "schema.gql",
102 query_path = "src/agent.gql",
103 response_derives = "Debug"
104)]
105pub struct GetApps;
106
107pub async fn get_apps(
108 executor_url: String,
109 cap_token: String,
110) -> Result<Vec<get_apps::GetAppsAgentGetApps>> {
111 let response_data: get_apps::ResponseData = query(
112 executor_url,
113 cap_token,
114 GetApps::build_query(get_apps::Variables {}),
115 )
116 .await
117 .with_context(|| "Failed to run agent->get apps query")?;
118 Ok(response_data.agent_get_apps)
119}
120
121#[derive(GraphQLQuery)]
122#[graphql(
123 schema_path = "schema.gql",
124 query_path = "src/agent.gql",
125 response_derives = "Debug"
126)]
127pub struct RevokeToken;
128
129pub async fn revoke_token(
130 executor_url: String,
131 cap_token: String,
132 request_id: String,
133) -> Result<Vec<revoke_token::RevokeTokenAgentRevokeToken>> {
134 let response_data: revoke_token::ResponseData = query(
135 executor_url,
136 cap_token,
137 RevokeToken::build_query(revoke_token::Variables { request_id }),
138 )
139 .await
140 .with_context(|| "Failed to run agent->revoke_token query")?;
141 Ok(response_data.agent_revoke_token)
142}
143
144#[derive(GraphQLQuery)]
145#[graphql(
146 schema_path = "schema.gql",
147 query_path = "src/agent.gql",
148 response_derives = "Debug"
149)]
150pub struct RemoveApp;
151
152pub async fn remove_app(
153 executor_url: String,
154 cap_token: String,
155 request_id: String,
156) -> Result<Vec<remove_app::RemoveAppAgentRemoveApp>> {
157 let response_data: remove_app::ResponseData = query(
158 executor_url,
159 cap_token,
160 RemoveApp::build_query(remove_app::Variables { request_id }),
161 )
162 .await
163 .with_context(|| "Failed to run agent->remove_app query")?;
164 Ok(response_data.agent_remove_app)
165}
166
167#[derive(GraphQLQuery)]
168#[graphql(
169 schema_path = "schema.gql",
170 query_path = "src/agent.gql",
171 response_derives = "Debug"
172)]
173pub struct AgentStatus;
174
175pub async fn status(
176 executor_url: String,
177 cap_token: String,
178) -> Result<agent_status::AgentStatusAgentStatus> {
179 let response_data: agent_status::ResponseData = query(
180 executor_url,
181 cap_token,
182 AgentStatus::build_query(agent_status::Variables {}),
183 )
184 .await
185 .with_context(|| "Failed to run agent->me query")?;
186 Ok(response_data.agent_status)
187}
188
189#[derive(GraphQLQuery)]
190#[graphql(
191 schema_path = "schema.gql",
192 query_path = "src/agent.gql",
193 response_derives = "Debug"
194)]
195pub struct Lock;
196
197pub async fn lock(
198 executor_url: String,
199 cap_token: String,
200 passphrase: String,
201) -> Result<lock::LockAgentLock> {
202 let response_data: lock::ResponseData = query(
203 executor_url,
204 cap_token,
205 Lock::build_query(lock::Variables { passphrase }),
206 )
207 .await
208 .with_context(|| "Failed to run agent->lock")?;
209 Ok(response_data.agent_lock)
210}
211
212#[derive(GraphQLQuery)]
213#[graphql(
214 schema_path = "schema.gql",
215 query_path = "src/agent.gql",
216 response_derives = "Debug"
217)]
218pub struct Unlock;
219
220pub async fn unlock(
221 executor_url: String,
222 cap_token: String,
223 passphrase: String,
224 holochain: bool,
225) -> Result<unlock::UnlockAgentUnlock> {
226 let response_data: unlock::ResponseData = query(
227 executor_url,
228 cap_token,
229 Unlock::build_query(unlock::Variables {
230 passphrase,
231 holochain,
232 }),
233 )
234 .await
235 .with_context(|| "Failed to run agent->unlock")?;
236 Ok(response_data.agent_unlock)
237}
238
239#[derive(GraphQLQuery)]
240#[graphql(
241 schema_path = "schema.gql",
242 query_path = "src/agent.gql",
243 response_derives = "Debug"
244)]
245pub struct ByDID;
246
247pub async fn by_did(
248 executor_url: String,
249 cap_token: String,
250 did: String,
251) -> Result<Option<by_did::ByDidAgentByDid>> {
252 let response_data: by_did::ResponseData = query(
253 executor_url,
254 cap_token,
255 ByDID::build_query(by_did::Variables { did }),
256 )
257 .await
258 .with_context(|| "Failed to run agent->byDID query")?;
259 Ok(response_data.agent_by_did)
260}
261
262#[derive(GraphQLQuery)]
263#[graphql(
264 schema_path = "schema.gql",
265 query_path = "src/agent.gql",
266 response_derives = "Debug"
267)]
268pub struct Generate;
269
270pub async fn generate(
271 executor_url: String,
272 cap_token: String,
273 passphrase: String,
274) -> Result<generate::GenerateAgentGenerate> {
275 let response_data: generate::ResponseData = query(
276 executor_url,
277 cap_token,
278 Generate::build_query(generate::Variables { passphrase }),
279 )
280 .await
281 .with_context(|| "Failed to run agent->generate")?;
282 Ok(response_data.agent_generate)
283}
284
285#[derive(GraphQLQuery)]
286#[graphql(
287 schema_path = "schema.gql",
288 query_path = "src/agent.gql",
289 response_derives = "Debug"
290)]
291pub struct SignMessage;
292
293pub async fn sign_message(
294 executor_url: String,
295 cap_token: String,
296 message: String,
297) -> Result<sign_message::SignMessageAgentSignMessage> {
298 let response: sign_message::ResponseData = query(
299 executor_url,
300 cap_token,
301 SignMessage::build_query(sign_message::Variables { message }),
302 )
303 .await
304 .with_context(|| "Failed to run agent->sign_message")?;
305
306 Ok(response.agent_sign_message)
307}
308
309#[derive(GraphQLQuery, Debug, Clone)]
310#[graphql(
311 schema_path = "schema.gql",
312 query_path = "src/agent.gql",
313 response_derives = "Debug"
314)]
315pub struct AddEntanglementProofs;
316
317pub async fn add_entanglement_proofs(
318 executor_url: String,
319 cap_token: String,
320 proofs: Vec<add_entanglement_proofs::EntanglementProofInput>,
321) -> Result<add_entanglement_proofs::ResponseData> {
322 query(
323 executor_url,
324 cap_token,
325 AddEntanglementProofs::build_query(add_entanglement_proofs::Variables { proofs }),
326 )
327 .await
328 .with_context(|| "Failed to run runtime->add-trusted-agents query")
329}
330
331#[derive(GraphQLQuery, Debug, Clone)]
332#[graphql(
333 schema_path = "schema.gql",
334 query_path = "src/agent.gql",
335 response_derives = "Debug"
336)]
337pub struct DeleteEntanglementProofs;
338
339pub async fn delete_entanglement_proofs(
340 executor_url: String,
341 cap_token: String,
342 proofs: Vec<delete_entanglement_proofs::EntanglementProofInput>,
343) -> Result<delete_entanglement_proofs::ResponseData> {
344 query(
345 executor_url,
346 cap_token,
347 DeleteEntanglementProofs::build_query(delete_entanglement_proofs::Variables { proofs }),
348 )
349 .await
350 .with_context(|| "Failed to run runtime->add-trusted-agents query")
351}
352
353#[derive(GraphQLQuery, Debug, Clone)]
354#[graphql(
355 schema_path = "schema.gql",
356 query_path = "src/agent.gql",
357 response_derives = "Debug"
358)]
359pub struct EntanglementProofPreFlight;
360
361pub async fn entanglement_proof_pre_flight(
362 executor_url: String,
363 cap_token: String,
364 device_key: String,
365 device_key_type: String,
366) -> Result<entanglement_proof_pre_flight::ResponseData> {
367 query(
368 executor_url,
369 cap_token,
370 EntanglementProofPreFlight::build_query(entanglement_proof_pre_flight::Variables {
371 device_key,
372 device_key_type,
373 }),
374 )
375 .await
376 .with_context(|| "Failed to run runtime->add-trusted-agents query")
377}
378
379#[derive(GraphQLQuery)]
380#[graphql(
381 schema_path = "schema.gql",
382 query_path = "src/agent.gql",
383 response_derives = "Debug"
384)]
385pub struct SubscriptionAgentStatusChanged;
386
387pub async fn watch(executor_url: String, cap_token: String) -> Result<()> {
388 let mut client = create_websocket_client(executor_url, cap_token)
389 .await
390 .with_context(|| "Failed to create websocket client")?;
391
392 println!("Successfully created websocket client");
393 let mut stream = client
394 .streaming_operation({
395 StreamingOperation::<SubscriptionAgentStatusChanged>::new(
396 subscription_agent_status_changed::Variables {},
397 )
398 })
399 .await
400 .with_context(|| "Failed to subscribe to agentStatusChanged")?;
401
402 println!("Successfully subscribed agentStatusChanged",);
403 println!("Waiting for events...");
404
405 while let Some(item) = stream.next().await {
406 match item {
407 Ok(response) => {
408 if let Some(data) = response.data.and_then(|data| data.agent_status_changed) {
409 println!("Received agentStatusChanged: {:?}", data);
410 }
411 }
412 Err(e) => {
413 println!("Received Error: {:?}", e);
414 }
415 }
416 }
417
418 println!("Stream ended. Exiting...");
419
420 Ok(())
421}
422
423pub struct AgentClient {
424 info: Arc<ClientInfo>,
425}
426
427impl AgentClient {
428 pub fn new(info: Arc<ClientInfo>) -> Self {
429 Self { info }
430 }
431
432 pub async fn request_capability(
433 &self,
434 app_name: String,
435 app_desc: String,
436 app_domain: String,
437 app_url: Option<String>,
438 app_icon_path: Option<String>,
439 capabilities: Option<Vec<Capability>>,
440 ) -> Result<String> {
441 request_capability(
442 self.info.executor_url.clone(),
443 app_name,
444 app_desc,
445 app_domain,
446 app_url,
447 app_icon_path,
448 capabilities,
449 )
450 .await
451 }
452
453 pub async fn retrieve_capability(&self, request_id: String, rand: String) -> Result<String> {
454 retrieve_capability(self.info.executor_url.clone(), request_id, rand).await
455 }
456
457 pub async fn me(&self) -> Result<me::MeAgent> {
458 me(self.info.executor_url.clone(), self.info.cap_token.clone()).await
459 }
460
461 pub async fn status(&self) -> Result<agent_status::AgentStatusAgentStatus> {
462 status(self.info.executor_url.clone(), self.info.cap_token.clone()).await
463 }
464
465 pub async fn get_apps(&self) -> Result<Vec<get_apps::GetAppsAgentGetApps>> {
466 get_apps(self.info.executor_url.clone(), self.info.cap_token.clone()).await
467 }
468
469 pub async fn lock(&self, passphrase: String) -> Result<lock::LockAgentLock> {
470 lock(
471 self.info.executor_url.clone(),
472 self.info.cap_token.clone(),
473 passphrase,
474 )
475 .await
476 }
477
478 pub async fn unlock(
479 &self,
480 passphrase: String,
481 holochain: bool,
482 ) -> Result<unlock::UnlockAgentUnlock> {
483 unlock(
484 self.info.executor_url.clone(),
485 self.info.cap_token.clone(),
486 passphrase,
487 holochain,
488 )
489 .await
490 }
491
492 pub async fn by_did(&self, did: String) -> Result<Option<by_did::ByDidAgentByDid>> {
493 by_did(
494 self.info.executor_url.clone(),
495 self.info.cap_token.clone(),
496 did,
497 )
498 .await
499 }
500
501 pub async fn generate(&self, passphrase: String) -> Result<generate::GenerateAgentGenerate> {
502 generate(
503 self.info.executor_url.clone(),
504 self.info.cap_token.clone(),
505 passphrase,
506 )
507 .await
508 }
509
510 pub async fn sign_message(
511 &self,
512 message: String,
513 ) -> Result<sign_message::SignMessageAgentSignMessage> {
514 sign_message(
515 self.info.executor_url.clone(),
516 self.info.cap_token.clone(),
517 message,
518 )
519 .await
520 }
521
522 pub async fn add_entanglement_proofs(
523 &self,
524 proofs: Vec<add_entanglement_proofs::EntanglementProofInput>,
525 ) -> Result<add_entanglement_proofs::ResponseData> {
526 add_entanglement_proofs(
527 self.info.executor_url.clone(),
528 self.info.cap_token.clone(),
529 proofs,
530 )
531 .await
532 }
533
534 pub async fn delete_entanglement_proofs(
535 &self,
536 proofs: Vec<delete_entanglement_proofs::EntanglementProofInput>,
537 ) -> Result<delete_entanglement_proofs::ResponseData> {
538 delete_entanglement_proofs(
539 self.info.executor_url.clone(),
540 self.info.cap_token.clone(),
541 proofs,
542 )
543 .await
544 }
545
546 pub async fn entanglement_proof_pre_flight(
547 &self,
548 device_key: String,
549 device_key_type: String,
550 ) -> Result<entanglement_proof_pre_flight::ResponseData> {
551 entanglement_proof_pre_flight(
552 self.info.executor_url.clone(),
553 self.info.cap_token.clone(),
554 device_key,
555 device_key_type,
556 )
557 .await
558 }
559
560 pub async fn watch(&self) -> Result<()> {
561 watch(self.info.executor_url.clone(), self.info.cap_token.clone()).await
562 }
563}