Skip to content

Commit dfa84ae

Browse files
.
1 parent de87244 commit dfa84ae

File tree

3 files changed

+328
-0
lines changed

3 files changed

+328
-0
lines changed

squarecloud/http/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .http_client import HTTPClient, Response

squarecloud/http/http_client.py

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
from __future__ import annotations
2+
3+
import aiohttp
4+
5+
from .router import Endpoint, Router
6+
from ..errors import (
7+
NotFoundError,
8+
RequestError,
9+
BadRequestError,
10+
AuthenticationFailure
11+
)
12+
from ..logs import logger
13+
from ..square import File
14+
15+
from ..types import RawResponseData
16+
17+
18+
class Response:
19+
"""Represents a request response"""
20+
21+
def __init__(self, data: RawResponseData, route) -> None:
22+
self.data = data
23+
self.route = route
24+
self.headers = data.get('headers')
25+
self.status = data.get('status')
26+
self.code = data.get('code')
27+
self.message = data.get('message')
28+
self.response = data.get('response')
29+
self.app = data.get('app')
30+
31+
32+
class HTTPClient:
33+
"""A client that handles requests and responses"""
34+
35+
def __init__(self, api_key: str) -> None:
36+
self.api_key = api_key
37+
self.__session = aiohttp.ClientSession
38+
self.trace_config: aiohttp.TraceConfig = aiohttp.TraceConfig()
39+
40+
async def request(self, route: Router, **kwargs) -> Response:
41+
"""
42+
Sends a request to the Square API and returns the response.
43+
44+
Args:
45+
route: the route to send a request
46+
Returns:
47+
RawResponseData
48+
"""
49+
headers = {'Authorization': self.api_key}
50+
51+
if route.method == 'POST':
52+
kwargs['skip_auto_headers'] = {'Content-Type'}
53+
if route.endpoint.name in ('COMMIT', 'UPLOAD'):
54+
del kwargs['skip_auto_headers']
55+
file = kwargs.pop('file')
56+
form = aiohttp.FormData()
57+
form.add_field('file', file.bytes, filename=file.name)
58+
kwargs['data'] = form
59+
60+
async with self.__session(
61+
headers=headers, trace_configs=[self.trace_config]) as session:
62+
async with session.request(url=route.url, method=route.method,
63+
**kwargs) as resp:
64+
status_code = resp.status
65+
data: RawResponseData = await resp.json()
66+
extra = {
67+
'status': data.get('status'),
68+
'route': route.url,
69+
'code': data.get('code'),
70+
'request_message': data.get('message', '')
71+
}
72+
match status_code:
73+
case 200:
74+
extra.pop('code')
75+
logger.debug(msg='request to route: ', extra=extra)
76+
response: Response = Response(data=data, route=route)
77+
case 404:
78+
logger.debug(msg='request to route: ', extra=extra)
79+
msg = f'route [{route.endpoint.name}] returned 404, [{data.get("code")}]'
80+
raise NotFoundError(msg)
81+
case 401:
82+
logger.error(msg='request to: ', extra=extra)
83+
msg = 'Invalid api token has been passed'
84+
raise AuthenticationFailure(msg)
85+
case 400:
86+
logger.error(msg='request to: ', extra=extra)
87+
msg = f'route [{route.endpoint.name}] returned 400, [{data.get("code")}]'
88+
raise BadRequestError(msg)
89+
case _:
90+
msg = f'An unexpected error occurred while requesting {route.url}, ' \
91+
f'route: [{route.endpoint.name}], status: {data.get("statusCode")}\n' \
92+
f'Error: {data.get("error")}'
93+
raise RequestError(msg)
94+
return response
95+
96+
async def fetch_user_info(self) -> Response:
97+
"""
98+
Make a request to USER_INFO route
99+
100+
Returns:
101+
Response
102+
"""
103+
route = Router(Endpoint.user_info())
104+
response: Response = await self.request(route)
105+
return response
106+
107+
async def fetch_app_status(self, app_id: str) -> Response:
108+
"""
109+
Make a request for STATUS route
110+
111+
Args:
112+
app_id:
113+
114+
Returns:
115+
Response
116+
"""
117+
route: Router = Router(Endpoint.app_status(), app_id=app_id)
118+
response: Response = await self.request(route)
119+
return response
120+
121+
async def fetch_logs(self, app_id: str) -> Response:
122+
"""
123+
Make a request for LOGS route
124+
125+
Args:
126+
app_id:
127+
128+
Returns:
129+
Response
130+
"""
131+
route: Router = Router(Endpoint.logs(), app_id=app_id)
132+
response: Response = await self.request(route)
133+
return response
134+
135+
async def fetch_logs_complete(self, app_id: str) -> Response:
136+
"""
137+
Make a request for LOGS_COMPLETE route
138+
139+
Args:
140+
app_id:
141+
142+
Returns:
143+
Response
144+
"""
145+
route: Router = Router(Endpoint.full_logs(), app_id=app_id)
146+
response: Response = await self.request(route)
147+
return response
148+
149+
async def start_application(self, app_id: str) -> Response:
150+
"""
151+
Make a request for START route
152+
153+
Args:
154+
app_id: the application ID
155+
156+
Returns:
157+
Response
158+
"""
159+
route: Router = Router(Endpoint.start(), app_id=app_id)
160+
response: Response = await self.request(route)
161+
return response
162+
163+
async def stop_application(self, app_id: str) -> Response:
164+
"""
165+
Make a request for STOP route
166+
167+
Args:
168+
app_id: the application ID
169+
170+
Returns:
171+
Response
172+
"""
173+
route: Router = Router(Endpoint.stop(), app_id=app_id)
174+
response: Response = await self.request(route)
175+
return response
176+
177+
async def restart_application(self, app_id: str) -> Response:
178+
"""
179+
Make a request for RESTART route
180+
181+
Args:
182+
app_id: the application ID
183+
184+
Returns:
185+
Response
186+
"""
187+
route: Router = Router(Endpoint.restart(), app_id=app_id)
188+
response: Response = await self.request(route)
189+
return response
190+
191+
async def backup(self, app_id: str) -> Response:
192+
"""
193+
Make a request for BACKUP route
194+
Args:
195+
app_id: the application ID
196+
197+
Returns:
198+
Response
199+
"""
200+
route: Router = Router(Endpoint.backup(), app_id=app_id)
201+
response: Response = await self.request(route)
202+
return response
203+
204+
async def delete_application(self, app_id: str) -> Response:
205+
"""
206+
Make a request for DELETE route
207+
Args:
208+
app_id: the application ID
209+
"""
210+
route: Router = Router(Endpoint.delete(), app_id=app_id)
211+
response: Response = await self.request(route)
212+
return response
213+
214+
async def commit(self, app_id: str, file: File) -> Response:
215+
"""
216+
Make a request for COMMIT route
217+
Args:
218+
app_id: the application ID
219+
file: the file to be committed
220+
221+
Returns:
222+
Response
223+
"""
224+
route: Router = Router(Endpoint.commit(), app_id=app_id)
225+
response: Response = await self.request(route, file=file)
226+
return response
227+
228+
async def upload(self, file: File):
229+
"""
230+
Make a request to UPLOAD route
231+
Args:
232+
file: file to be uploaded
233+
234+
Returns:
235+
Response
236+
"""
237+
route: Router = Router(Endpoint.upload())
238+
response: Response = await self.request(route, file=file)
239+
return response

squarecloud/http/router.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
from __future__ import annotations
2+
3+
from typing import Dict, Any
4+
5+
6+
class Endpoint:
7+
BASE: str = 'https://api.squarecloud.app/v1/public'
8+
ENDPOINTS = {
9+
'USER_INFO': {'METHOD': 'GET', 'PATH': '/user'},
10+
'APP_STATUS': {'METHOD': 'GET', 'PATH': '/status/{app_id}'},
11+
'LOGS': {'METHOD': 'GET', 'PATH': '/logs/{app_id}'},
12+
'FULL_LOGS': {'METHOD': 'GET', 'PATH': '/full-logs/{app_id}'},
13+
'START': {'METHOD': 'POST', 'PATH': '/start/{app_id}'},
14+
'STOP': {'METHOD': 'POST', 'PATH': '/stop/{app_id}'},
15+
'RESTART': {'METHOD': 'POST', 'PATH': '/restart/{app_id}'},
16+
'BACKUP': {'METHOD': 'GET', 'PATH': '/backup/{app_id}'},
17+
'COMMIT': {'METHOD': 'POST', 'PATH': '/commit/{app_id}'},
18+
'DELETE': {'METHOD': 'POST', 'PATH': '/delete/{app_id}'},
19+
'UPLOAD': {'METHOD': 'POST', 'PATH': '/upload'},
20+
}
21+
22+
def __init__(self, name: str):
23+
endpoint: Dict[str: Dict[str, Any]] = self.ENDPOINTS[name]
24+
self.name: str = name
25+
self.method: str = endpoint['METHOD']
26+
self.path: str = endpoint['PATH']
27+
28+
def __repr__(self):
29+
return f"<{self.__class__.__name__}('{self.name}')>"
30+
31+
@classmethod
32+
def user_info(cls):
33+
return cls('USER_INFO')
34+
35+
@classmethod
36+
def app_status(cls):
37+
return cls('APP_STATUS')
38+
39+
@classmethod
40+
def logs(cls):
41+
return cls('LOGS')
42+
43+
@classmethod
44+
def full_logs(cls):
45+
return cls('FULL_LOGS')
46+
47+
@classmethod
48+
def start(cls):
49+
return cls('START')
50+
51+
@classmethod
52+
def stop(cls):
53+
return cls('STOP')
54+
55+
@classmethod
56+
def restart(cls):
57+
return cls('RESTART')
58+
59+
@classmethod
60+
def backup(cls):
61+
return cls('BACKUP')
62+
63+
@classmethod
64+
def commit(cls):
65+
return cls('COMMIT')
66+
67+
@classmethod
68+
def delete(cls):
69+
return cls('DELETE')
70+
71+
@classmethod
72+
def upload(cls):
73+
return cls('UPLOAD')
74+
75+
76+
class Router:
77+
"""Represents a route"""
78+
BASE: str = 'https://api.squarecloud.app/v1/public'
79+
80+
# noinspection StrFormat
81+
def __init__(self, endpoint: Endpoint, **params) -> None:
82+
self.endpoint: Endpoint = endpoint
83+
self.method: str = endpoint.method
84+
self.path: str = endpoint.path
85+
url: str = self.BASE + self.path.format(**params)
86+
if params:
87+
url.format(params)
88+
self.url = url

0 commit comments

Comments
 (0)