Skip to content

Commit

Permalink
allow to use raw response content (StreamReader)
Browse files Browse the repository at this point in the history
  • Loading branch information
mib1185 committed Jan 5, 2025
1 parent 8f62661 commit a59a89c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 12 deletions.
49 changes: 38 additions & 11 deletions src/synology_dsm/synology_dsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@
from typing import Any, Coroutine, TypedDict
from urllib.parse import quote, urlencode

from aiohttp import ClientError, ClientSession, ClientTimeout, MultipartWriter, hdrs
from aiohttp import (
ClientError,
ClientSession,
ClientTimeout,
MultipartWriter,
StreamReader,
hdrs,
)
from yarl import URL

from .api import SynoBaseApi
Expand Down Expand Up @@ -239,13 +246,13 @@ def device_token(self) -> str | None:

async def get(
self, api: str, method: str, params: dict | None = None, **kwargs: Any
) -> bytes | dict | str:
) -> bytes | dict | str | StreamReader:
"""Handles API GET request."""
return await self._request("GET", api, method, params, **kwargs)

async def post(
self, api: str, method: str, params: dict | None = None, **kwargs: Any
) -> bytes | dict | str:
) -> bytes | dict | str | StreamReader:
"""Handles API POST request."""
return await self._request("POST", api, method, params, **kwargs)

Expand Down Expand Up @@ -310,18 +317,22 @@ async def _request(
method: str,
params: dict | None = None,
retry_once: bool = True,
raw_response_content: bool = False,
**kwargs: Any,
) -> bytes | dict | str:
) -> bytes | dict | str | StreamReader:
"""Handles API request."""
url, params, kwargs = await self._prepare_request(api, method, params, **kwargs)

# Request data
self._debuglog("---------------------------------------------------------")
self._debuglog("API: " + api)
self._debuglog("Request Method: " + request_method)
response = await self._execute_request(request_method, url, params, **kwargs)
response = await self._execute_request(
request_method, url, params, raw_response_content, **kwargs
)
self._debuglog("Successful returned data")
self._debuglog("RESPONSE: " + str(response))
if not raw_response_content:
self._debuglog("RESPONSE: " + str(response))

# Handle data errors
if isinstance(response, dict) and response.get("error") and api != API_AUTH:
Expand All @@ -339,19 +350,32 @@ async def _request(
return response

async def _execute_request(
self, method: str, url: URL, params: dict, **kwargs: Any
) -> bytes | dict | str:
self,
method: str,
url: URL,
params: dict,
raw_response_content: bool = False,
**kwargs: Any,
) -> bytes | dict | str | StreamReader:
"""Function to execute and handle a request."""
# special handling for spaces in parameters
# because yarl.URL does encode a space as + instead of %20
# safe extracted from yarl.URL._QUERY_PART_QUOTER
query = urlencode(params, safe="?/:@-._~!$'()*,", quote_via=quote)
url_encoded = url.join(URL(f"?{query}", encoded=True))

if params.get("api") in [
SynoFileStation.UPLOAD_API_KEY,
SynoFileStation.DOWNLOAD_API_KEY,
]:
timeout = ClientTimeout(connect=10.0, total=43200.0)
else:
timeout = self._aiohttp_timeout

try:
if method == "GET":
response = await self._session.get(
url_encoded, timeout=self._aiohttp_timeout, **kwargs
url_encoded, timeout=timeout, **kwargs
)
elif (
method == "POST" and params.get("api") == SynoFileStation.UPLOAD_API_KEY
Expand All @@ -377,7 +401,7 @@ async def _execute_request(

response = await self._session.post(
url_encoded,
timeout=ClientTimeout(connect=10.0, total=43200.0),
timeout=timeout,
data=mp,
)
elif method == "POST":
Expand All @@ -390,7 +414,7 @@ async def _execute_request(
self._debuglog("POST data: " + str(data))

response = await self._session.post(
url_encoded, timeout=self._aiohttp_timeout, **kwargs
url_encoded, timeout=timeout, **kwargs
)

# mask sesitive parameters
Expand All @@ -408,6 +432,9 @@ async def _execute_request(
# We got a DSM response
content_type = response.headers.get("Content-Type", "").split(";")[0]

if raw_response_content:
return response.content

if content_type in [
"application/json",
"text/json",
Expand Down
4 changes: 3 additions & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ def __init__(
self.error = False
self.with_surveillance = False

async def _execute_request(self, method, url, params, **kwargs):
async def _execute_request(
self, method, url, params, raw_response_content, **kwargs
):
url = str(url)
url += urlencode(params or {})

Expand Down

0 comments on commit a59a89c

Please sign in to comment.