Skip to content

Commit

Permalink
Merge pull request #226 from ticketsvl/master
Browse files Browse the repository at this point in the history
Add Kozula rate, #223 solved
  • Loading branch information
egregors authored Nov 6, 2021
2 parents b5362d9 + 9824000 commit 816d7e9
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name = "pypi"

[[description]]
name = "vldc-bot"
version = "0.6.6"
version = "0.6.7"
description = "VLDC nyan bot ^_^"
authors = [
#tg
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The official [VLDC](https://vldc.org) telegram group bot.
* 🛠 more than 70k? – try to hire!
* 💻 got sk1lzz? – put them to use!
* 👁 smell like PRISM? nononono!
* 💰 kozula Don't argue with kozula rate!

### Modes
* 😼 smile mode – allow only stickers in the chat
Expand Down
3 changes: 3 additions & 0 deletions bot/skills/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from skills.towel_mode import add_towel_mode
from skills.tree import add_tree
from skills.uwu import add_uwu
from skills.kozula import add_kozula

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -98,6 +99,7 @@ def _make_skill(add_handlers: Callable, name: str, hint: str) -> Dict:
_make_skill(add_prism, "👁 smell like PRISM?", " nononono!"),
_make_skill(add_ban, "🔨 ban!", " ban! ban! ban!"),
_make_skill(add_nya, "😺 meow", " Simon says wat?"),
_make_skill(add_kozula, "💰 kozula", " Don't argue with kozula rate!"),
# modes
_make_skill(add_smile_mode, "😼 smile mode", " allow only stickers in the chat"),
_make_skill(add_since_mode, "🛠 since mode", " under construction"),
Expand All @@ -119,6 +121,7 @@ def _make_skill(add_handlers: Callable, name: str, hint: str) -> Dict:
("ban", "ban! ban! ban!"),
("roll", "life is so cruel... isn't it?"),
("tree", "advent of code time!"),
("kozula", "💰 kozula", " Don't argue with kozula rate!"),
("still", "do u remember it?"),
("banme", "commit sudoku"),
("prism", "top N PRISM words with optional predicate"),
Expand Down
57 changes: 57 additions & 0 deletions bot/skills/kozula.py
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,
)
37 changes: 37 additions & 0 deletions bot/utils/cache.py
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

0 comments on commit 816d7e9

Please sign in to comment.