-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #226 from ticketsvl/master
Add Kozula rate, #223 solved
- Loading branch information
Showing
5 changed files
with
99 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import logging | ||
import xml.etree.ElementTree as ET | ||
from typing import Optional | ||
|
||
import requests | ||
from telegram import Update | ||
from telegram.ext import Updater, CommandHandler, CallbackContext | ||
|
||
from mode import cleanup_queue_update | ||
from utils.cache import timed_lru_cache | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
KOZULA_RATE = 600_000 | ||
CBR_URL = "https://cbr.ru/scripts/XML_daily.asp" | ||
|
||
|
||
def add_kozula(upd: Updater, handlers_group: int): | ||
logger.info("registering tree handlers") | ||
dp = upd.dispatcher | ||
dp.add_handler(CommandHandler("kozula", kozula, run_async=True), handlers_group) | ||
|
||
|
||
@timed_lru_cache(ttl=3600) | ||
def _get_usd_rate() -> Optional[float]: | ||
rate: Optional[float] = None | ||
try: | ||
request = requests.get(CBR_URL) | ||
root = ET.fromstring(request.content) | ||
for child in root: | ||
if child.attrib["ID"] == "R01235": | ||
rate = float(child.find("Value").text.replace(",", ".")) | ||
except requests.exceptions.RequestException as e: | ||
logger.error("can't get USD rate: %s", e) | ||
|
||
return rate | ||
|
||
|
||
def kozula(update: Update, context: CallbackContext): | ||
usd_rate = _get_usd_rate() | ||
kozula_rates = [ | ||
f"{KOZULA_RATE}₽", | ||
f"${round(KOZULA_RATE / usd_rate, 2)}" if usd_rate is not None else "", | ||
] | ||
|
||
result = context.bot.send_message( | ||
update.effective_chat.id, | ||
f"Текущий курс Козули: {' | '.join(filter(bool, kozula_rates))}", | ||
) | ||
|
||
cleanup_queue_update( | ||
queue=context.job_queue, | ||
cmd=update.message, | ||
result=result, | ||
seconds=300, | ||
remove_reply=True, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import collections | ||
import functools | ||
import time | ||
|
||
|
||
def timed_lru_cache(maxsize=128, ttl=60): | ||
""" | ||
A decorator to wrap a function with a lru cache that expires after ttl seconds. | ||
:param maxsize: The maximum size of the cache. | ||
:param ttl: The time to live of the cache. | ||
:return: The wrapped function. | ||
""" | ||
|
||
def decorator(func): | ||
cache = collections.OrderedDict() | ||
|
||
@functools.wraps(func) | ||
def wrapper(*args, **kwargs): | ||
key = args + tuple(sorted(kwargs.items())) | ||
now = time.time() | ||
try: | ||
value, last_updated = cache[key] | ||
if now - last_updated > ttl: | ||
del cache[key] | ||
else: | ||
return value | ||
except KeyError: | ||
pass | ||
value = func(*args, **kwargs) | ||
cache[key] = (value, now) | ||
if len(cache) > maxsize: | ||
cache.popitem(last=False) | ||
return value | ||
|
||
return wrapper | ||
|
||
return decorator |