77
88from collections import namedtuple
99from datetime import datetime
10- from typing import List , Optional , Union
10+ from typing import Generator , List , Optional , Union
1111
1212import aiohttp
1313
14+ import coc
1415from ...http import json_or_text
1516from ...utils import correct_tag
1617from ...wars import ClanWar
1718
1819LOG = logging .getLogger (__name__ )
1920
20- AccessToken = namedtuple ("AccessToken " , ["token" , "expires_at" ])
21+ FWAccessToken = namedtuple ("FWAccessToken " , ["token" , "expires_at" ])
2122
2223
2324def extract_expiry_from_jwt_token (token : Union [str , bytes ]) -> Optional [datetime ]:
@@ -45,7 +46,7 @@ def extract_expiry_from_jwt_token(token: Union[str, bytes]) -> Optional[datetime
4546 return None
4647
4748
48- async def login (username : str , password : str , clash_client ) -> "FullWarClient" :
49+ async def login (username : str , password : str , coc_client : Union [ coc . Client , coc . EventsClient ] ) -> "FullWarClient" :
4950 """Eases logging into the API client.
5051
5152 For more information on this project, please join the discord server - <discord.gg/Eaja7gJ>
@@ -59,17 +60,15 @@ async def login(username: str, password: str, clash_client) -> "FullWarClient":
5960 Your username as given on the discord server.
6061 password : str
6162 Your password as given on the discord server
62- loop : Optional[:class:`asyncio.AbstractEventLoop`]
63- The :class:`asyncio.AbstractEventLoop` to use for HTTP requests.
64- An :func:`asyncio.get_event_loop()` will be used if ``None`` is passed
63+ coc_client : Union[coc.Client, coc.EventsClient]
64+ A coc_client to grap the loop from and create the response objects with
6565 """
6666 if not isinstance (username , str ) or not isinstance (password , str ):
6767 raise TypeError ("username and password must both be a string" )
6868 if not username or not password :
6969 raise ValueError ("username or password must not be an empty string." )
7070
71- loop = asyncio .get_running_loop ()
72- return FullWarClient (username , password , clash_client , loop )
71+ return FullWarClient (username , password , coc_client )
7372
7473
7574class FullWarClient :
@@ -86,9 +85,8 @@ class FullWarClient:
8685 Your username as given on the discord server.
8786 password : str
8887 Your password as given on the discord server
89- clash_client: coc.Client
88+ coc_client: Union[ coc.Client, coc.EventClient]
9089 Client to use
91-
9290 loop : Optional[:class:`asyncio.AbstractEventLoop`]
9391 The :class:`asyncio.AbstractEventLoop` to use for HTTP requests.
9492 An :func:`asyncio.get_event_loop()` will be used if ``None`` is passed
@@ -97,14 +95,15 @@ class FullWarClient:
9795
9896 BASE_URL = "https://fw-api.teamutils.com"
9997
100- __slots__ = ("username" , "password" , "clash_client " , "loop" , "key" , "http_session" )
98+ __slots__ = ("username" , "password" , "coc_client " , "loop" , "key" , "http_session" )
10199
102- def __init__ (self , username : str , password : str , clash_client , loop : asyncio .AbstractEventLoop = None ):
100+ def __init__ (self , username : str , password : str , coc_client : Union [coc .Client , coc .EventsClient ],
101+ loop : asyncio .AbstractEventLoop = None ):
103102 self .username = username
104103 self .password = password
105- self .clash_client = clash_client
104+ self .coc_client = coc_client
106105
107- self .loop = loop or asyncio .get_event_loop ()
106+ self .loop = coc_client . loop or asyncio .get_event_loop ()
108107 self .key = None # set in get_key()
109108
110109 self .http_session = aiohttp .ClientSession (loop = self .loop )
@@ -136,7 +135,7 @@ async def _request(self, method, url, *, token_request: bool = False, **kwargs):
136135 return await self ._request (method , url , ** kwargs )
137136
138137 async def _get_key (self ):
139- if not self .key or (self .key .expires_at < datetime .utcnow ()):
138+ if not self .key or (self .key .expires_at and self . key . expires_at < datetime .utcnow ()):
140139 await self ._refresh_key ()
141140
142141 return self .key .token
@@ -148,63 +147,54 @@ async def _refresh_key(self):
148147 }
149148
150149 payload = await self ._request ("POST" , "/login" , token_request = True , json = data )
151- self .key = AccessToken (payload ["access_token" ], extract_expiry_from_jwt_token (payload ["access_token" ]))
150+ self .key = FWAccessToken (payload ["access_token" ], extract_expiry_from_jwt_token (payload ["access_token" ]))
152151
153- async def war_result (self , clan_tag : str , preparation_start : int = 0 ) -> ClanWar :
152+ async def war_result (self , clan_tag : str , preparation_start : int = 0 ) -> Optional [ ClanWar ] :
154153 """Get a stored war result.
155154
156155 Parameters
157156 ----------
158- client: coc.Client
159- instance of the clash client
160157 clan_tag: str
161158 The clan tag to find war result for.
162159 preparation_start: int
163160 Preparation start of a specific war result to find.
164161
165162 Returns
166163 --------
167- #NOOOOO idea if this is correct xD
168164 Optional[:class:`ClanWar`]
169165 War result, or ``None`` if no war found.
170166 """
171167 data = await self ._request ("GET" ,
172168 f"/war_result?clan_tag={ correct_tag (clan_tag , '%23' )} "
173169 f"&prep_start={ str (preparation_start )} " )
174170 try :
175- return ClanWar (data = data ["response" ], client = self .clash_client )
171+ return ClanWar (data = data ["response" ], client = self .coc_client )
176172 except (IndexError , KeyError , TypeError , ValueError ):
177173 return None
178174
179- async def war_result_log (self , clan_tag : str , preparation_start : int = 0 ) -> List [ ClanWar ]:
175+ async def war_result_log (self , clan_tag : str ) -> Optional [ Generator [ ClanWar ] ]:
180176 """Get all stored war results for a clan.
181177
182178 Parameters
183179 ----------
184- client: coc.Client
185- instance of the clash client
186180 clan_tag: str
187181 The clan tag to find war result for.
188- preparation_start: int
189- Preparation start of a specific war result to find.
190182
191183 Returns
192184 --------
193- #NOOOOO idea if this is correct xD
194- Optional[:class:`ClanWar`]
195- List of war results, or ``None`` if no wars found.
185+ Optional[Generator[:class:`ClanWar`]]
186+ Generator of war results, or ``None`` if no wars found.
196187 """
197188 data = await self ._request ("GET" ,
198189 f"/war_result_log?clan_tag={ correct_tag (clan_tag , '%23' )} " )
199190 try :
200191 responses = data ["log" ]
201192
202- generator = (ClanWar (data = response ["response" ], client = self .clash_client ) for response in responses )
193+ generator = (ClanWar (data = response ["response" ], client = self .coc_client ) for response in responses )
203194 return generator
204195 except (IndexError , KeyError , TypeError , ValueError ):
205196 return None
206197
207-
208198 async def register_war (self , clan_tag : str , preparation_start : int = 0 ):
209199 """Registers a war.
210200
@@ -213,7 +203,7 @@ async def register_war(self, clan_tag: str, preparation_start: int = 0):
213203 clan_tag : str
214204 The clan to register a war for
215205 preparation_start: int
216- Preparation time of the war
206+ Preparation time of the war.
217207 """
218208 return await self ._request ("POST" ,
219209 f"/register_war?clan_tag={ correct_tag (clan_tag , '%23' )} "
0 commit comments