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 }
60 CloudService::Id => {
61 }
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 }
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, });
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}