import asyncio
from datetime import datetime
import pickle
from lib.bot.converters import dataclass_from_dict
from lib.bot.struct import Message_struct
from config import LOCAL_IP, LOCAL_PORT, MESSAGE_REPLY_RATE
import typing
import functools
def throttled(
delay: float,
measure: typing.Literal[
"end_to_start", "start_to_start"
] = "start_to_start",
):
def decorator(actual_func: typing.Coroutine) -> typing.Coroutine:
queue = None
async def _single_query(future, args, kwargs):
try:
result = await actual_func(
*args, **kwargs
) # тут делаем асинхронное обращение к сервису
except Exception as err:
future.set_exception(
err
) # была ошибка - теперь await future выкинет исключение
else:
future.set_result(
result
) # полуен результат - await future вернёт его
async def _work_loop():
nonlocal queue
while True:
try:
# ждем, пока не придёт запрос, или пока не закончится таймаут
future, args, kwargs = await asyncio.wait_for(
queue.get(), delay
)
except (
asyncio.TimeoutError
): # новые запросы долго не приходят, сворачиваем работу, чтобы не тратить ресурсы
queue = None
return
task = _single_query(future, args, kwargs)
if measure == "start_to_start":
asyncio.create_task(task)
else:
await task
queue.task_done() # каждому успешному get() соответствует task_done()
await asyncio.sleep(
delay
) # можно учесть, сколько времени делался запрос. Но стоит ли?
@functools.wraps(actual_func)
async def query(*args, **kwargs):
nonlocal queue # обращение к переменной выше уровнем, но не глобальной
future = (
asyncio.Future()
) # Future просигналит, когда наш запрос будет обслужен
if (
queue is None
): # либо это первый запрос, либо запросы долго не приходили, и мы свернули работу
queue = asyncio.Queue()
asyncio.create_task(_work_loop())
await queue.put((future, args, kwargs))
return await future
return query
return decorator
async def handle_echo(reader, writer) -> None:
tasks = []
while True:
data = await reader.read()
if not data:
break
message = pickle.loads(data)
message_cls = dataclass_from_dict(
struct=Message_struct, dictionary=message
)
task = asyncio.create_task(replier(message_cls))
tasks.append(task)
addr = writer.get_extra_info("peername")
print(f"Received {message_cls!r} from {addr!r}")
await asyncio.gather(*tasks)
writer.close()
@throttled(delay=1.0/MESSAGE_REPLY_RATE, measure='start_to_start')
async def replier(message_cls: Message_struct):
# send answer to user
print(
f"Answered to {message_cls.user_id}, with text "
f"'{message_cls.text}' at {datetime.now()}"
)
async def main() -> None:
server = await asyncio.start_server(
lambda reader, writer: handle_echo(reader, writer),
LOCAL_IP,
LOCAL_PORT,
)
addrs = ", ".join(str(sock.getsockname()) for sock in server.sockets)
print(f"Serving on {addrs}")
async with server:
await server.serve_forever()
asyncio.run(main())
import asyncio
from datetime import datetime
import pickle
from lib.bot.converters import dataclass_from_dict
from lib.bot.struct import Message_struct
from config import LOCAL_IP, LOCAL_PORT, MESSAGE_REPLY_RATE
class ThrottledResource:
def __init__(self, delay: float):
self._delay = delay
self._queue = asyncio.Queue()
self._task = None
def start(self):
self._task = asyncio.create_task(self._work_loop())
def stop(self):
self._task.cancel()
self._task = None
# этот метод вызывается клиентским кодом, получает параметры и возвращает отклик спустя время.
async def query(self, params):
future = asyncio.Future() # Future просигналит, когда наш запрос будет обслужен
await self._queue.put((future, params))
result = await future # корутина спит, пока запрос не обслужат
return result
async def _work_loop(self):
while True:
future, params = await self._queue.get() # ждем, пока не придёт запрос
try:
result = await replier(params) # тут делаем асинхронное обращение к сервису
except Exception as err:
future.set_exception(err) # была ошибка - теперь await future выкинет исключение
else:
future.set_result(result) # полуен результат - await future вернёт его
self._queue.task_done() # каждому успешному get() соответствует task_done()
await asyncio.sleep(self._delay)
async def handle_echo(reader, writer, message_throttler) -> None:
tasks = []
while True:
data = await reader.read()
if not data:
break
message = pickle.loads(data)
message_cls = dataclass_from_dict(
struct=Message_struct, dictionary=message
)
task = asyncio.create_task(message_throttler.query(message_cls))
tasks.append(task)
await asyncio.gather(*tasks)
addr = writer.get_extra_info("peername")
# print(f"Received {message_cls!r} from {addr!r}")
writer.close()
async def replier(message_cls: Message_struct):
# process the received data here
print(message_cls.text, datetime.now())
async def main() -> None:
message_throttler = ThrottledResource(delay=1.0/MESSAGE_REPLY_RATE)
message_throttler.start()
server = await asyncio.start_server(
lambda reader, writer: handle_echo(reader, writer, message_throttler),
LOCAL_IP,
LOCAL_PORT
)
addrs = ", ".join(str(sock.getsockname()) for sock in server.sockets)
print(f"Serving on {addrs}")
async with server:
await server.serve_forever()
asyncio.run(main())
По понятиям ООП, ты как раз должен прятать подобную реализацию c.keys_funcs.add_key в c.add_key или т.п
today_date = '2022-4-1'
today_date = datetime.datetime.strptime(today_date, '%Y-%m-%d')
today_num = today_date.weekday()
days = [(today_date - datetime.timedelta(days=delta)).strftime('%Y-%m-%d') for delta in reversed(range(0, today_num + 1))]
days += ([(today_date + datetime.timedelta(days=delta)).strftime('%Y-%m-%d') for delta in range(1, 7 - today_num)])
today_date = '2022-4-4'
today_date = datetime.datetime.strptime(today_date, '%Y-%m-%d')
today_num = today_date.weekday()
days = []
for delta in reversed(range(0, today_num + 1)):
day = (today_date - datetime.timedelta(days=delta)).strftime('%Y-%m-%d')
days.append(day)
for delta in range(1, 7 - today_num):
day = (today_date + datetime.timedelta(days=delta)).strftime('%Y-%m-%d')
days.append(day)
for day in days:
print(day)
today_date = '2022-4-1'
today_num = datetime.datetime.strptime(today_date, '%Y-%m-%d').weekday()
days = []
for item in range(0, today_num + 1):
day = (datetime.datetime.strptime(today_date, '%Y-%m-%d') - datetime.timedelta(days=item)).strftime('%Y-%m-%d')
days.append(day)
for item in range(1, 7 - today_num):
day = (datetime.datetime.strptime(today_date, '%Y-%m-%d') + datetime.timedelta(days=item)).strftime('%Y-%m-%d')
days.append(day)
for item in days:
print(item)
а тег PYTHON включил, так как новичок в этом вопросе и не совсем понимаю в чем заключается проблема, возможно, что python код тут не лишний