async def call_herald_event(ci, destination: str, event_name: str, **kwargs) -> Dict: """Send a :class:`rh.Request` to a specific destination, and wait for a :class:`rh.Response`.""" if self.herald is None: raise rc.UnsupportedError("`royalherald` is not enabled on this Constellation.") request: rh.Request = rh.Request(handler=event_name, data=kwargs) response: rh.Response = await self.herald.request(destination=destination, request=request) if isinstance(response, rh.ResponseFailure): if response.name == "no_event": raise rc.CommandError(f"There is no event named {event_name} in {destination}.") elif response.name == "exception_in_event": # TODO: pretty sure there's a better way to do this if response.extra_info["type"] == "CommandError": raise rc.CommandError(response.extra_info["message"]) elif response.extra_info["type"] == "UserError": raise rc.UserError(response.extra_info["message"]) elif response.extra_info["type"] == "InvalidInputError": raise rc.InvalidInputError(response.extra_info["message"]) elif response.extra_info["type"] == "UnsupportedError": raise rc.UnsupportedError(response.extra_info["message"]) elif response.extra_info["type"] == "ConfigurationError": raise rc.ConfigurationError(response.extra_info["message"]) elif response.extra_info["type"] == "ExternalError": raise rc.ExternalError(response.extra_info["message"]) else: raise TypeError(f"Herald action call returned invalid error:\n" f"[p]{response}[/p]") elif isinstance(response, rh.ResponseSuccess): return response.data else: raise TypeError(f"Other Herald Link returned unknown response:\n" f"[p]{response}[/p]")
async def _call(self, method, *args, **kwargs): log.debug(f"Calling {method}") try: return await ru.asyncify(method, *args, **kwargs) except Exception as e: raise rc.ExternalError("\n".join(e.args).replace( self.token(), "HIDDEN"))
async def update(self, session, obj: Steam, change: Callable[[str, Any], Awaitable[None]]): log.debug(f"Getting player data from OpenDota...") async with aiohttp.ClientSession() as hcs: # Get profile data async with hcs.get(f"https://api.opendota.com/api/players/{obj.steamid.as_32}/") as response: if response.status != 200: raise rc.ExternalError(f"OpenDota / returned {response.status}!") p = await response.json() # No such user if "profile" not in p: log.debug(f"Not found: {obj}") return # Get win/loss data async with hcs.get(f"https://api.opendota.com/api/players/{obj.steamid.as_32}/wl") as response: if response.status != 200: raise rc.ExternalError(f"OpenDota /wl returned {response.status}!") wl = await response.json() # No such user if wl["win"] == 0 and wl["lose"] == 0: log.debug(f"Not found: {obj}") return # Find the Dota record, if it exists dota: Dota = obj.dota if dota is None: # Autocreate the Dota record dota = self.alchemy.get(Dota)(steam=obj) session.add(dota) session.flush() # Make a custom change function async def change(attribute: str, new: Any): await self._change(session=session, obj=dota, attribute=attribute, new=new) await change("wins", wl["win"]) await change("losses", wl["lose"]) if p["rank_tier"]: await change("rank", DotaRank(rank_tier=p["rank_tier"])) else: await change("rank", None)
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async with aiohttp.ClientSession() as session: async with session.get( "https://api.thecatapi.com/v1/images/search") as response: if response.status >= 400: raise rc.ExternalError( f"Request returned {response.status}") result = await response.json() assert len(result) == 1 cat = result[0] assert "url" in cat url = cat["url"] async with session.get(url) as response: img = await response.content.read() await data.reply_image(image=io.BytesIO(img))
async def call_herald_event(self, destination: str, event_name: str, **kwargs) -> Dict: """Send a :class:`royalherald.Request` to a specific destination, and wait for a :class:`royalherald.Response`.""" if self.herald is None: raise rc.UnsupportedError( "`royalherald` is not enabled on this serf.") request: rh.Request = rh.Request(handler=event_name, data=kwargs) response: rh.Response = await self.herald.request( destination=destination, request=request) if isinstance(response, rh.ResponseFailure): if response.name == "no_event": raise rc.ProgramError( f"There is no event named {event_name} in {destination}.") elif response.name == "error_in_event": if response.extra_info["type"] == "CommandError": raise rc.CommandError(response.extra_info["message"]) elif response.extra_info["type"] == "UserError": raise rc.UserError(response.extra_info["message"]) elif response.extra_info["type"] == "InvalidInputError": raise rc.InvalidInputError(response.extra_info["message"]) elif response.extra_info["type"] == "UnsupportedError": raise rc.UnsupportedError(response.extra_info["message"]) elif response.extra_info["type"] == "ConfigurationError": raise rc.ConfigurationError(response.extra_info["message"]) elif response.extra_info["type"] == "ExternalError": raise rc.ExternalError(response.extra_info["message"]) else: raise rc.ProgramError( f"Invalid error in Herald event '{event_name}':\n" f"[b]{response.extra_info['type']}[/b]\n" f"{response.extra_info['message']}") elif response.name == "unhandled_exception_in_event": raise rc.ProgramError( f"Unhandled exception in Herald event '{event_name}':\n" f"[b]{response.extra_info['type']}[/b]\n" f"{response.extra_info['message']}") else: raise rc.ProgramError( f"Unknown response in Herald event '{event_name}':\n" f"[b]{response.name}[/b]" f"[p]{response}[/p]") elif isinstance(response, rh.ResponseSuccess): return response.data else: raise rc.ProgramError( f"Other Herald Link returned unknown response:\n" f"[p]{response}[/p]")
async def update(self, session, obj, change: Callable[[str, Any], Awaitable[None]]): BrawlhallaT = self.alchemy.get(Brawlhalla) DuoT = self.alchemy.get(BrawlhallaDuo) log.info(f"Updating: {obj}") async with aiohttp.ClientSession() as hcs: bh: Brawlhalla = obj.brawlhalla if bh is None: log.debug(f"Checking if player has an account...") async with hcs.get( f"https://api.brawlhalla.com/search?steamid={obj.steamid.as_64}&api_key={self.token()}" ) as response: if response.status != 200: raise rc.ExternalError( f"Brawlhalla API /search returned {response.status}!" ) j = await response.json() if j == {} or j == []: log.debug("No account found.") return bh = BrawlhallaT(steam=obj, brawlhalla_id=j["brawlhalla_id"], name=j["name"]) session.add(bh) session.flush() async with hcs.get( f"https://api.brawlhalla.com/player/{bh.brawlhalla_id}/ranked?api_key={self.token()}" ) as response: if response.status != 200: raise rc.ExternalError( f"Brawlhalla API /ranked returned {response.status}!") j = await response.json() if j == {} or j == []: log.debug("No ranked info found.") else: await self._change(session=session, obj=bh, attribute="rating_1v1", new=j["rating"]) metal_name, tier_name = j["tier"].split(" ", 1) metal = BrawlhallaMetal[metal_name.upper()] tier = BrawlhallaTier(int(tier_name)) rank = BrawlhallaRank(metal=metal, tier=tier) await self._change(session=session, obj=bh, attribute="rank_1v1", new=rank) for jduo in j.get("2v2", []): bhduo: Optional[BrawlhallaDuo] = await ru.asyncify( session.query(DuoT).filter( or_( and_( DuoT.id_one == jduo["brawlhalla_id_one"], DuoT.id_two == jduo["brawlhalla_id_two"]), and_( DuoT.id_one == jduo["brawlhalla_id_two"], DuoT.id_two == jduo[ "brawlhalla_id_one"]))).one_or_none ) if bhduo is None: if bh.brawlhalla_id == jduo["brawlhalla_id_one"]: otherbh: Optional[ Brawlhalla] = await ru.asyncify( session.query(BrawlhallaT).get, jduo["brawlhalla_id_two"]) else: otherbh: Optional[ Brawlhalla] = await ru.asyncify( session.query(BrawlhallaT).get, jduo["brawlhalla_id_one"]) if otherbh is None: continue bhduo = DuoT( one=bh, two=otherbh, ) session.add(bhduo) await self._change(session=session, obj=bhduo, attribute="rating_2v2", new=jduo["rating"]) metal_name, tier_name = jduo["tier"].split(" ", 1) metal = BrawlhallaMetal[metal_name.upper()] tier = BrawlhallaTier(int(tier_name)) rank = BrawlhallaRank(metal=metal, tier=tier) await self._change(session=session, obj=bhduo, attribute="rank_2v2", new=rank)