main
py 217 lines 7.67 KB
Raw
1 from typing import Any
2 from typing import Dict
3 from typing import Optional
4
5 import httpx
6 import requests
7 from loguru import logger
8
9 from app.connectors.utils import get_connector_info_from_db
10 from app.db.db_session import get_db_session
11
12
13 async def verify_talon_credentials(attributes: Dict[str, Any]) -> Dict[str, Any]:
14 """
15 Verifies the connection to the Talon service.
16
17 Returns:
18 dict: A dictionary containing 'connectionSuccessful' status.
19 """
20 logger.info(f"Verifying the Talon connection to {attributes['connector_url']}")
21 try:
22 response = requests.get(
23 f"{attributes['connector_url']}/health",
24 verify=False,
25 timeout=10,
26 )
27 if response.status_code == 200:
28 logger.info(f"Connection to {attributes['connector_url']} successful")
29 return {
30 "connectionSuccessful": True,
31 "message": "Talon connection successful",
32 }
33 else:
34 logger.error(
35 f"Connection to {attributes['connector_url']} failed with status: {response.status_code}",
36 )
37 return {
38 "connectionSuccessful": False,
39 "message": f"Connection to {attributes['connector_url']} failed with status {response.status_code}",
40 }
41 except Exception as e:
42 logger.error(
43 f"Connection to {attributes['connector_url']} failed with error: {e}",
44 )
45 return {
46 "connectionSuccessful": False,
47 "message": f"Connection to {attributes['connector_url']} failed with error: {e}",
48 }
49
50
51 async def verify_talon_connection(connector_name: str = "Talon") -> Dict[str, Any]:
52 """
53 Verifies the connection to the Talon service using stored connector credentials.
54
55 Args:
56 connector_name (str): The name of the connector. Defaults to "Talon".
57
58 Returns:
59 Dict[str, Any]: Connection verification result.
60 """
61 logger.info("Verifying Talon connection")
62 async with get_db_session() as session:
63 attributes = await get_connector_info_from_db(connector_name, session)
64 if attributes is None:
65 logger.error("No Talon connector found in the database")
66 return None
67 return await verify_talon_credentials(attributes)
68
69
70 def _build_headers(api_key: str) -> Dict[str, str]:
71 """Build request headers with API key authentication."""
72 return {
73 "x-api-key": api_key,
74 "Content-Type": "application/json",
75 }
76
77
78 async def send_get_request(
79 endpoint: str,
80 params: Optional[Dict[str, Any]] = None,
81 connector_name: str = "Talon",
82 ) -> Dict[str, Any]:
83 """
84 Sends a GET request to the Talon service.
85
86 Args:
87 endpoint (str): The endpoint to send the GET request to.
88 params (Optional[Dict[str, Any]], optional): The parameters to send with the GET request. Defaults to None.
89 connector_name (str, optional): The name of the connector to use. Defaults to "Talon".
90
91 Returns:
92 Dict[str, Any]: The response from the GET request.
93 """
94 logger.info(f"Sending GET request to Talon {endpoint}")
95 async with get_db_session() as session:
96 attributes = await get_connector_info_from_db(connector_name, session)
97 if attributes is None:
98 logger.error("No Talon connector found in the database")
99 return {
100 "success": False,
101 "message": "No Talon connector found in the database",
102 }
103 try:
104 headers = _build_headers(attributes["connector_api_key"])
105 response = requests.get(
106 f"{attributes['connector_url']}{endpoint}",
107 headers=headers,
108 params=params,
109 verify=False,
110 timeout=(5, 30),
111 )
112 response.raise_for_status()
113 return {
114 "data": response.json(),
115 "success": True,
116 "message": "Successfully retrieved data",
117 }
118 except Exception as e:
119 logger.error(f"Failed to send GET request to Talon {endpoint} with error: {e}")
120 return {
121 "success": False,
122 "message": f"Failed to send GET request to {endpoint} with error: {e}",
123 }
124
125
126 async def send_post_request(
127 endpoint: str,
128 data: Optional[Dict[str, Any]] = None,
129 connector_name: str = "Talon",
130 timeout: int = 120,
131 ) -> Dict[str, Any]:
132 """
133 Sends a POST request to the Talon service.
134
135 Args:
136 endpoint (str): The endpoint to send the POST request to.
137 data (Optional[Dict[str, Any]]): The data to send with the POST request. Defaults to None.
138 connector_name (str, optional): The name of the connector to use. Defaults to "Talon".
139 timeout (int, optional): Request timeout in seconds. Defaults to 120.
140
141 Returns:
142 Dict[str, Any]: The response from the POST request.
143 """
144 logger.info(f"Sending POST request to Talon {endpoint}")
145 async with get_db_session() as session:
146 attributes = await get_connector_info_from_db(connector_name, session)
147 if attributes is None:
148 logger.error("No Talon connector found in the database")
149 return {
150 "success": False,
151 "message": "No Talon connector found in the database",
152 }
153 try:
154 headers = _build_headers(attributes["connector_api_key"])
155 response = requests.post(
156 f"{attributes['connector_url']}{endpoint}",
157 headers=headers,
158 json=data,
159 verify=False,
160 timeout=timeout,
161 )
162 response.raise_for_status()
163 return {
164 "data": response.json(),
165 "success": True,
166 "message": "Successfully retrieved data",
167 }
168 except Exception as e:
169 logger.error(f"Failed to send POST request to Talon {endpoint} with error: {e}")
170 return {
171 "success": False,
172 "message": f"Failed to send POST request to {endpoint} with error: {e}",
173 }
174
175
176 async def send_post_request_sse(
177 endpoint: str,
178 data: Optional[Dict[str, Any]] = None,
179 connector_name: str = "Talon",
180 ):
181 """
182 Sends a POST request to the Talon service and yields SSE chunks as they arrive.
183
184 Uses httpx async streaming to avoid blocking the event loop and preserves
185 the raw SSE wire format (including \\n\\n event boundaries).
186
187 Args:
188 endpoint (str): The endpoint to send the POST request to.
189 data (Optional[Dict[str, Any]]): The data to send with the POST request.
190 connector_name (str, optional): The name of the connector to use. Defaults to "Talon".
191
192 Yields:
193 bytes: Raw SSE bytes from the upstream response.
194 """
195 logger.info(f"Sending streaming POST request to Talon {endpoint}")
196 async with get_db_session() as session:
197 attributes = await get_connector_info_from_db(connector_name, session)
198 if attributes is None:
199 logger.error("No Talon connector found in the database")
200 yield b'data: {"error": "No Talon connector found in the database"}\n\n'
201 return
202 try:
203 headers = _build_headers(attributes["connector_api_key"])
204 timeout = httpx.Timeout(connect=10.0, read=None, write=10.0, pool=10.0)
205 async with httpx.AsyncClient(verify=False, timeout=timeout) as client:
206 async with client.stream(
207 "POST",
208 f"{attributes['connector_url']}{endpoint}",
209 headers=headers,
210 json=data,
211 ) as response:
212 response.raise_for_status()
213 async for chunk in response.aiter_bytes():
214 yield chunk
215 except Exception as e:
216 logger.error(f"Failed to stream from Talon {endpoint} with error: {e}")
217 yield f'data: {{"error": "Failed to stream from {endpoint}"}}\n\n'.encode()