Skip to content

Commit

Permalink
Only call aiohttp.ClientSession from async func
Browse files Browse the repository at this point in the history
Since `aiohttp==0.20.0`, instantiating `aiohttp.ClientSession` must be
done from an async function. Calling this from a non-async function
relied on deprecated behaviour in Python, which broke in recent
releases.
aio-libs/aiohttp#8555 (comment)
explains the situation.

Rather than pin `aiohttp` to an older version, let's just fix the
behaviour.
  • Loading branch information
anoadragon453 committed Oct 2, 2024
1 parent 345aa61 commit 8118e7a
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 12 deletions.
32 changes: 20 additions & 12 deletions sygnal/gcmpushkin.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,13 @@ def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]) -> None:
tls_client_options_factory = ClientTLSOptionsFactory()

# use the Sygnal global proxy configuration
proxy_url = sygnal.config.get("proxy")
self.proxy_url = sygnal.config.get("proxy")

self.http_agent = ProxyAgent(
reactor=sygnal.reactor,
pool=self.http_pool,
contextFactory=tls_client_options_factory,
proxy_url_str=proxy_url,
proxy_url_str=self.proxy_url,
)

self.api_version = APIVersion.Legacy
Expand Down Expand Up @@ -209,16 +209,8 @@ def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]) -> None:
f"`service_account_file` must be valid: {str(e)}",
)

session = None
if proxy_url:
# `ClientSession` can't directly take the proxy URL, so we need to
# set the usual env var and use `trust_env=True`
os.environ["HTTPS_PROXY"] = proxy_url
session = aiohttp.ClientSession(trust_env=True, auto_decompress=False)

self.google_auth_request = google.auth.transport._aiohttp_requests.Request(
session=session
)
# This is built in `_refresh_credentials`, and must be done in an async function.
self.google_auth_request: google.auth.transport._aiohttp_requests.Request = None

# Use the fcm_options config dictionary as a foundation for the body;
# this lets the Sygnal admin choose custom FCM options
Expand Down Expand Up @@ -513,6 +505,22 @@ async def _get_auth_header(self) -> str:
async def _refresh_credentials(self) -> None:
assert self.credentials is not None
if not self.credentials.valid:
# Setting up a ClientSession must be done from an async function.
# Lazily build `self.google_auth_request` instead of doing so in `__init__`.
if self.google_auth_request is None:
session = None
if self.proxy_url:
# `ClientSession` can't directly take the proxy URL, so we need to
# set the usual env var and use `trust_env=True`
os.environ["HTTPS_PROXY"] = self.proxy_url
session = aiohttp.ClientSession(
trust_env=True, auto_decompress=False
)

self.google_auth_request = (
google.auth.transport._aiohttp_requests.Request(session=session)
)

await Deferred.fromFuture(
asyncio.ensure_future(
self.credentials.refresh(self.google_auth_request)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_gcm.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
import tempfile
from typing import TYPE_CHECKING, Any, AnyStr, Dict, List, Tuple
from unittest.mock import MagicMock

import aiohttp
import google.auth.transport._aiohttp_requests

from sygnal.exceptions import TemporaryNotificationDispatchException
from sygnal.gcmpushkin import APIVersion, GcmPushkin

Expand Down Expand Up @@ -132,6 +136,19 @@ async def _perform_http_request( # type: ignore[override]
async def _refresh_credentials(self) -> None:
assert self.credentials is not None
if not self.credentials.valid:
if self.google_auth_request is None:
session = None
if self.proxy_url:
# `ClientSession` can't directly take the proxy URL, so we need to
# set the usual env var and use `trust_env=True`
os.environ["HTTPS_PROXY"] = self.proxy_url
session = aiohttp.ClientSession(
trust_env=True, auto_decompress=False
)

self.google_auth_request = (
google.auth.transport._aiohttp_requests.Request(session=session)
)
await self.credentials.refresh(self.google_auth_request)


Expand Down

0 comments on commit 8118e7a

Please sign in to comment.