forked from 3wordchant/capsul-flask
73 lines
2.8 KiB
Python
73 lines
2.8 KiB
Python
|
|
import sys
|
|
import json
|
|
|
|
import aiohttp
|
|
import asyncio
|
|
from flask import current_app
|
|
from capsulflask.db import my_exec_info_message
|
|
from capsulflask.db_model import OnlineHost
|
|
from typing import List
|
|
|
|
class HTTPResult:
|
|
def __init__(self, status_code, body=None):
|
|
self.status_code = status_code
|
|
self.body = body
|
|
|
|
class MyHTTPClient:
|
|
def __init__(self, timeout_seconds = 5):
|
|
self.client_session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=timeout_seconds))
|
|
self.event_loop = asyncio.get_event_loop()
|
|
|
|
def make_requests_sync(self, online_hosts: List[OnlineHost], body: str) -> List(HTTPResult):
|
|
self.event_loop.run_until_complete(self.make_requests(online_hosts=online_hosts, body=body))
|
|
|
|
def post_json_sync(self, url: str, body: str, method="POST", authorization_header=None) -> HTTPResult:
|
|
self.event_loop.run_until_complete(self.post_json_sync(method=method, url=url, body=body))
|
|
|
|
async def post_json(self, url: str, body: str, method="POST", authorization_header=None) -> HTTPResult:
|
|
response = None
|
|
try:
|
|
headers = {}
|
|
if authorization_header != None:
|
|
headers['Authorization'] = authorization_header
|
|
response = await self.client_session.request(
|
|
method=method,
|
|
url=url,
|
|
json=body,
|
|
headers=headers,
|
|
auth=aiohttp.BasicAuth("hub", current_app.config['HUB_TOKEN']),
|
|
verify_ssl=True,
|
|
)
|
|
except:
|
|
error_message = my_exec_info_message(sys.exc_info())
|
|
response_body = json.dumps({"error_message": f"error contacting spoke: {error_message}"})
|
|
current_app.logger.error(f"""
|
|
error contacting spoke: post_json (HTTP {method} {url}) failed with: {error_message}"""
|
|
)
|
|
return HTTPResult(-1, response_body)
|
|
|
|
response_body = None
|
|
try:
|
|
response_body = await response.text()
|
|
except:
|
|
error_message = my_exec_info_message(sys.exc_info())
|
|
response_body = json.dumps({"error_message": f"error reading response from spoke: {error_message}"})
|
|
current_app.logger.error(f"""
|
|
error reading response from spoke: HTTP {method} {url} (status {response.status}) failed with: {error_message}"""
|
|
)
|
|
|
|
return HTTPResult(response.status, response_body)
|
|
|
|
async def make_requests(self, online_hosts: List[OnlineHost], body: str) -> List(HTTPResult):
|
|
tasks = []
|
|
# append to tasks in the same order as online_hosts
|
|
for host in online_hosts:
|
|
tasks.append(
|
|
self.post_json(url=host.url, body=body)
|
|
)
|
|
# gather is like Promise.all from javascript, it returns a future which resolves to an array of results
|
|
# in the same order as the tasks that we passed in -- which were in the same order as online_hosts
|
|
results = await asyncio.gather(*tasks)
|
|
|
|
return results |