graphgate_handler/
service_route.rs1use std::collections::HashMap;
2use std::ops::{Deref, DerefMut};
3
4use futures_util::TryFutureExt;
5use graphgate_planner::{Request, Response};
6use http::HeaderMap;
7use once_cell::sync::Lazy;
8
9static HTTP_CLIENT: Lazy<reqwest::Client> = Lazy::new(Default::default);
10
11#[derive(Clone, Eq, PartialEq, Debug)]
13pub struct ServiceRoute {
14 pub addr: String,
18
19 pub tls: bool,
21
22 pub query_path: Option<String>,
24
25 pub subscribe_path: Option<String>,
27}
28
29#[derive(Default, Debug, Clone, Eq, PartialEq)]
33pub struct ServiceRouteTable(HashMap<String, ServiceRoute>);
34
35impl Deref for ServiceRouteTable {
36 type Target = HashMap<String, ServiceRoute>;
37
38 fn deref(&self) -> &Self::Target {
39 &self.0
40 }
41}
42
43impl DerefMut for ServiceRouteTable {
44 fn deref_mut(&mut self) -> &mut Self::Target {
45 &mut self.0
46 }
47}
48
49impl ServiceRouteTable {
50 pub async fn query(
52 &self,
53 service: impl AsRef<str>,
54 request: Request,
55 header_map: Option<&HeaderMap>,
56 ) -> anyhow::Result<Response> {
57 let service = service.as_ref();
58 let route = self.0.get(service).ok_or_else(|| {
59 anyhow::anyhow!("Service '{}' is not defined in the routing table.", service)
60 })?;
61 let scheme = match route.tls {
62 true => "https",
63 false => "http",
64 };
65 let url = match &route.query_path {
66 Some(path) => format!("{}://{}{}", scheme, route.addr, path),
67 None => format!("{}://{}", scheme, route.addr),
68 };
69
70 let resp = HTTP_CLIENT
71 .post(&url)
72 .headers(header_map.cloned().unwrap_or_default())
73 .json(&request)
74 .send()
75 .and_then(|res| async move { res.error_for_status() })
76 .and_then(|res| res.json::<Response>())
77 .await?;
78 Ok(resp)
79 }
80}