ad4m_client/
agent.rs

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}