Skip to main content

txtx_cloud/
router.rs

1use std::{future::Future, pin::Pin};
2
3use serde_json::Value as JsonValue;
4use txtx_addon_kit::{
5    reqwest::{self, Client},
6    types::cloud_interface::{
7        AuthenticatedCloudServiceRouter, CloudService, DeploySubgraphCommand, RegisterIdlCommand,
8        SvmService,
9    },
10};
11
12use crate::auth::AuthConfig;
13
14#[derive(Debug, Clone)]
15pub struct TxtxAuthenticatedCloudServiceRouter {
16    id_service_url: String,
17}
18
19impl AuthenticatedCloudServiceRouter for TxtxAuthenticatedCloudServiceRouter {
20    fn route<'a>(
21        &'a self,
22        service: CloudService,
23    ) -> Pin<Box<dyn Future<Output = Result<String, String>> + Send + 'a>> {
24        Box::pin(async move {
25            let token_required = service.token_required();
26            let access_token = if token_required {
27                let Some(mut auth_config) = AuthConfig::read_from_system_config()? else {
28                    return Err("You must be logged in to use txtx cloud services. Run `txtx cloud login` to log in.".to_string());
29                };
30                auth_config
31                    .refresh_session_if_needed(&self.id_service_url)
32                    .await
33                    .map_err(|e| e.to_string())?;
34                Some(auth_config.access_token)
35            } else {
36                None
37            };
38            TxtxCloudServiceRouter::new(service).route(access_token).await
39        })
40    }
41}
42
43impl TxtxAuthenticatedCloudServiceRouter {
44    pub fn new(id_service_url: &str) -> Self {
45        Self { id_service_url: id_service_url.to_string() }
46    }
47}
48
49#[derive(Debug, Clone)]
50pub struct TxtxCloudServiceRouter {
51    pub service: CloudService,
52}
53
54impl TxtxCloudServiceRouter {
55    async fn route(self, token: Option<String>) -> Result<String, String> {
56        match &self.service {
57            CloudService::Registry => {
58                // Handle registry service
59            }
60            CloudService::Id => {
61                // Handle ID service
62            }
63            CloudService::Svm(svm_service) => match svm_service {
64                SvmService::DeploySubgraph(DeploySubgraphCommand {
65                    url,
66                    params,
67                    do_include_token,
68                }) => {
69                    let token = if *do_include_token { token } else { None };
70                    let client = Client::new();
71
72                    let res =
73                        rpc_call::<JsonValue>(&client, url, "loadPlugin", params, token.as_ref())
74                            .await
75                            .map_err(|e| {
76                                format!("Failed to send request to deploy subgraph: {}", e)
77                            })?;
78
79                    return Ok(res.to_string());
80                }
81                SvmService::RegisterIdl(RegisterIdlCommand {
82                    url,
83                    params,
84                    do_include_token,
85                    ..
86                }) => {
87                    let token = if *do_include_token { token } else { None };
88                    let client = Client::new();
89
90                    let res = rpc_call::<JsonValue>(
91                        &client,
92                        url,
93                        "surfnet_registerIdl",
94                        params,
95                        token.as_ref(),
96                    )
97                    .await
98                    .map_err(|e| format!("Failed to send request to register IDL: {}", e))?;
99
100                    return Ok(res.to_string());
101                }
102            },
103            CloudService::Evm => {
104                // Handle EVM service
105            }
106        }
107        Ok("".into())
108    }
109}
110
111impl TxtxCloudServiceRouter {
112    pub fn new(service: CloudService) -> Self {
113        Self { service }
114    }
115}
116
117async fn rpc_call<T: for<'de> serde::Deserialize<'de> + std::convert::From<JsonValue>>(
118    client: &reqwest::Client,
119    url: &str,
120    method: &str,
121    params: &JsonValue,
122    token: Option<&String>,
123) -> Result<T, Box<dyn std::error::Error>> {
124    let body = serde_json::json!({
125        "jsonrpc": "2.0",
126        "method": method,
127        "params": params,
128        "id": 1, //todo
129    });
130    let mut req = client.post(url).json(&body);
131    if let Some(token) = token {
132        req = req.bearer_auth(token);
133    }
134    let resp = req.send().await?.json::<JsonValue>().await?;
135
136    Ok(resp["result"].clone().try_into()?)
137}