11import asyncio
22import contextlib
3+ import weakref
34from collections .abc import Callable
45from typing import Any
56from urllib .parse import urljoin
@@ -25,6 +26,18 @@ def create_request(method: str, *args: Any, **kwargs: Any) -> dict:
2526 return request (method , params ) # type: ignore
2627
2728
29+ def _cleanup_sessions (sessions : dict [asyncio .AbstractEventLoop , aiohttp .ClientSession ]) -> None :
30+ loop = get_event_loop ()
31+ for session in list (sessions .values ()):
32+ if session is None or session .closed :
33+ continue
34+ if loop .is_running ():
35+ loop .create_task (session .close ())
36+ else :
37+ loop .run_until_complete (session .close ())
38+ sessions .clear ()
39+
40+
2841class RPCProxy :
2942 def __init__ (
3043 self ,
@@ -42,13 +55,14 @@ def __init__(
4255 self .xpub = xpub
4356 self .proxy = proxy
4457 self .verify = verify
45- self ._connector_class = aiohttp .TCPConnector
58+ self ._connector_class : type [ aiohttp . BaseConnector ] = aiohttp .TCPConnector
4659 self ._connector_init : dict [str , Any ] = {"ssl" : self .verify }
4760 self ._spec = {"exceptions" : {"-32600" : {"exc_name" : "UnauthorizedError" , "docstring" : "Unauthorized" }}}
4861 self ._spec_valid = False
4962 self ._sessions : dict [asyncio .AbstractEventLoop , aiohttp .ClientSession ] = {}
5063 if session is not None :
5164 self ._sessions [get_event_loop ()] = session
65+ self ._finalizer = weakref .finalize (self , _cleanup_sessions , self ._sessions )
5266
5367 @property
5468 def session (self ) -> aiohttp .ClientSession :
@@ -65,7 +79,7 @@ def init_proxy(self) -> None:
6579 from aiohttp_socks .utils import parse_proxy_url
6680
6781 proxy_type , host , port , username , password = parse_proxy_url (self .proxy )
68- self ._connector_class = ProxyConnector # type: ignore
82+ self ._connector_class = ProxyConnector
6983 self ._connector_init .update (
7084 proxy_type = proxy_type ,
7185 host = host ,
@@ -133,14 +147,6 @@ async def wrapper(*args: Any, **kwargs: Any) -> Any:
133147
134148 return wrapper
135149
136- async def _close (self ) -> None :
137- for session in self ._sessions .values ():
138- if session is not None :
139- await session .close ()
140-
141- def __del__ (self ) -> None :
142- loop = get_event_loop ()
143- if loop .is_running ():
144- loop .create_task (self ._close ())
145- else :
146- loop .run_until_complete (self ._close ())
150+ async def close (self ) -> None :
151+ if self ._finalizer .alive :
152+ self ._finalizer ()
0 commit comments