Skip to content

Commit

Permalink
/update_markup, imrovements in syncrhonizer, EnablingManager
Browse files Browse the repository at this point in the history
  • Loading branch information
lavadk committed Apr 8, 2021
1 parent 7a0419a commit eadd7a9
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 121 deletions.
13 changes: 6 additions & 7 deletions liker/command/handler_set_reactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from tengine import Config

from liker.state.enabled_channels import EnabledChannels
from liker.command import set_reactions_utils
from liker.enabling_manager import EnablingManager

logger = logging.getLogger(__file__)

Expand All @@ -14,6 +14,7 @@ class CommandHandlerSetReactions(CommandHandler):
enabled_channels = inject.attr(EnabledChannels)
telegram_bot = inject.attr(TelegramBot)
config = inject.attr(Config)
enabling_manager = inject.attr(EnablingManager)

def get_cards(self) -> Iterable[CommandCard]:
return [CommandCard(command_str='/set_reactions',
Expand All @@ -24,6 +25,7 @@ def get_cards(self) -> Iterable[CommandCard]:
def handle(self,
config: Config,
chat_id,
message: Message,
args: Namespace,
telegram_bot: TelegramBot,
command_parser: CommandParser):
Expand All @@ -45,12 +47,9 @@ def handle(self,
text='channel_id should be a number or start from @')
return

set_successfully = set_reactions_utils.try_set_reactions(config=self.config,
telegram_bot=self.telegram_bot,
enabled_channels=self.enabled_channels,
channel_id=channel_id,
reactions=reactions,
reply_to_chat_id=chat_id)
set_successfully = self.enabling_manager.try_set_reactions(channel_id=channel_id,
reactions=reactions,
reply_to_chat_id=chat_id)
if not set_successfully:
return

Expand Down
64 changes: 64 additions & 0 deletions liker/command/handler_update_markup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import inject
import logging
from tengine.command.command_handler import *
from tengine import TelegramBot
from tengine import Config
from telebot.types import InlineKeyboardMarkup

from liker.state.enabled_channels import EnabledChannels
from liker.state.space_state import SpaceState
from liker.custom_markup import markup_utils
from liker.setup import constants

logger = logging.getLogger(__file__)


class CommandHandlerUpdateMarkup(CommandHandler):
telegram_bot = inject.attr(TelegramBot)
enabled_channels = inject.attr(EnabledChannels)
space_state = inject.attr(SpaceState)

def get_cards(self) -> Iterable[CommandCard]:
return [CommandCard(command_str='/update_markup',
description='Set buttons according to reactions enabled',
is_admin=False),
]

def handle(self,
config: Config,
chat_id,
message: Message,
args: Namespace,
telegram_bot: TelegramBot,
command_parser: CommandParser):
if args.command == '/update_markup':
ref_message: Message = message.reply_to_message
if (ref_message is None) or (ref_message.forward_from_chat is None):
telegram_bot.send_text(chat_id=chat_id,
text='Send /update_markup in comments to target channel post')
return

channel_id = ref_message.forward_from_chat.id
if not self.enabled_channels.is_enabled(str(channel_id)):
telegram_bot.send_text(chat_id=chat_id,
text='Liker is not enabled for the given channel')
return

channel_message_id = ref_message.forward_from_message_id
str_trail_markup = self.space_state \
.ensure_channel_state(str(channel_id)) \
.markup_trail \
.try_get(str(channel_message_id))
trail_markup = None if (str_trail_markup is None) else InlineKeyboardMarkup.de_json(str_trail_markup)
channel_dict = self.enabled_channels.get_channel_dict(str(channel_id))
enabled_reactions = channel_dict['reactions']
reply_markup = markup_utils.extend_reply_markup(current_markup=trail_markup,
enabled_reactions=enabled_reactions,
handler=constants.CHANNEL_POST_HANDLER,
case_id='')
self.telegram_bot.bot.edit_message_reply_markup(chat_id=channel_id,
message_id=channel_message_id,
reply_markup=reply_markup)
else:
raise ValueError(f'Unhandled command: {args.command}')

58 changes: 0 additions & 58 deletions liker/command/set_reactions_utils.py

This file was deleted.

22 changes: 10 additions & 12 deletions liker/custom_markup/channel_post_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from liker.custom_markup.markup_synchronizer import MarkupSynchronizer
from liker.setup import constants
from liker.custom_markup import markup_utils
from liker.command import set_reactions_utils
from liker.enabling_manager import EnablingManager

logger = logging.getLogger(__file__)

Expand All @@ -23,18 +23,16 @@ class ChannelPostHandler(TelegramInboxHandler):
space_state = inject.attr(SpaceState)
markup_synchronizer = inject.attr(MarkupSynchronizer)
abuse_detector = inject.attr(AbuseDetector)
enabling_manager = inject.attr(EnablingManager)

def channel_post(self, channel_post: types.Message) -> bool:
channel_id: int = channel_post.chat.id

str_channel_id = str(channel_id)
if not self.enabled_channels.is_enabled(str_channel_id):
did_enabled = set_reactions_utils.try_set_reactions(config=self.config,
telegram_bot=self.telegram_bot,
enabled_channels=self.enabled_channels,
channel_id=channel_id,
reactions=constants.DEFAULT_REACTIONS,
reply_to_chat_id=None)
did_enabled = self.enabling_manager.try_set_reactions(channel_id=channel_id,
reactions=constants.DEFAULT_REACTIONS,
reply_to_chat_id=None)
if not did_enabled:
return False
else:
Expand All @@ -44,10 +42,10 @@ def channel_post(self, channel_post: types.Message) -> bool:

channel_dict = self.enabled_channels.get_channel_dict(str_channel_id)
enabled_reactions = channel_dict['reactions']
reply_markup = markup_utils.build_reply_markup(enabled_reactions=enabled_reactions,
state_dict=None,
handler=constants.CHANNEL_POST_HANDLER,
case_id='')
reply_markup = markup_utils.extend_reply_markup(current_markup=None,
enabled_reactions=enabled_reactions,
handler=constants.CHANNEL_POST_HANDLER,
case_id='')
self.markup_synchronizer.add(channel_id=channel_id,
message_id=message_id,
reply_markup=reply_markup,
Expand Down Expand Up @@ -100,7 +98,7 @@ def callback_query(self, callback_query: types.CallbackQuery) -> bool:

if reply_markup_new.to_json() == reply_markup_telegram.to_json():
self.markup_synchronizer.try_remove(channel_id=channel_id, message_id=message_id)
logger.debug(f'Dequieuing markup as it was returned to original state')
logger.debug(f'De-queuing markup as it was returned to original state')
else:
self.markup_synchronizer.add(channel_id=channel_id, message_id=message_id, reply_markup=reply_markup_new)

Expand Down
53 changes: 30 additions & 23 deletions liker/custom_markup/markup_synchronizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,42 +73,49 @@ def update(self):
ch_state = self.space_state.ensure_channel_state(str(ch_id))
ch_queue = ch_state.markup_queue.ensure_queue()
while ch_queue:
# If we made 'rate_per_minute' updates per last minute -- don't send more updates
if len(upd_times) >= rate_per_minute:
break
m_id_str = None
reply_markup_str = None
try:
m_id_str = list(ch_queue.keys())[0]
reply_markup_str = ch_queue[m_id_str]

# If we made 'rate_per_minute' updates per last minute -- don't send more updates
if len(upd_times) >= rate_per_minute:
break

# Make elastic delay time
slowdown_factor = len(upd_times) / rate_per_minute
cur_timeout = rate_min_seconds + slowdown_factor * rate_span
logger.debug(f'queue timeout: {cur_timeout}')
if cur_timeout > dt_to_consume:
break
# Make elastic delay time
slowdown_factor = len(upd_times) / rate_per_minute
cur_timeout = rate_min_seconds + slowdown_factor * rate_span
logger.debug(f'queue timeout: {cur_timeout}')
if cur_timeout > dt_to_consume:
break

m_id_str = list(ch_queue.keys())[0]
reply_markup_str = ch_queue[m_id_str]
m_id = int(m_id_str)
m_id = int(m_id_str)

reply_markup = InlineKeyboardMarkup.de_json(reply_markup_str)
reply_markup = InlineKeyboardMarkup.de_json(reply_markup_str)

dt_to_consume -= cur_timeout
upd_times.append(cur_time)

dt_to_consume -= cur_timeout
upd_times.append(cur_time)
try:
self.telegram_bot.bot.edit_message_reply_markup(chat_id=ch_id,
message_id=m_id,
reply_markup=reply_markup)
# We don't break loop for all exceptions except TOO_MANY_REQUESTS to avoid infitie error loop
except ApiTelegramException as ex:
if ex.error_code == telegram_error.BAD_REQUEST:
logger.error(f'Bad params in reply markup, ignoring it: {ex}')
elif ex.error_code == telegram_error.TOO_MANY_REQUESTS:
if ex.error_code == telegram_error.TOO_MANY_REQUESTS:
logger.error(f'Got TOO_MANY_REQUESTS error, will skip current channel update: {ex}')
break
else:
raise ex
logger.exception(ex)
except Exception as ex:
logger.exception(ex)

# We delete markup from the queue only after it's synchronized
ch_state.markup_trail.add(str_message_id=m_id_str,
str_markup=reply_markup_str)
del ch_queue[m_id_str]
if m_id_str is not None:
if reply_markup_str is not None:
ch_state.markup_trail.add(str_message_id=m_id_str,
str_markup=reply_markup_str)
del ch_queue[m_id_str]

self.channel_update_times[ch_id] = upd_times
ch_state.markup_queue.update_queue(ch_queue)
Expand Down
44 changes: 25 additions & 19 deletions liker/custom_markup/markup_utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import logging
from telebot import types
from typing import Optional, Iterable
from typing import Iterable, List, Optional
from tengine import telegram_utils

from liker.setup import constants

logger = logging.getLogger(__file__)


Expand All @@ -24,27 +26,31 @@ def _num_str_to_number(num_str):
return result


def build_reply_markup(enabled_reactions: list,
state_dict: Optional[dict],
handler: str,
case_id: str) -> types.InlineKeyboardMarkup:
state_reactions = {}
if (state_dict is not None) and ('reactions' in state_dict):
state_reactions = state_dict['reactions']
def extend_reply_markup(current_markup: Optional[types.InlineKeyboardMarkup],
enabled_reactions: list,
handler: str,
case_id: str,
include_comment=True) -> types.InlineKeyboardMarkup:
current_buttons: List[types.InlineKeyboardButton] = [] if (current_markup is None) \
else list(iterate_markup_buttons(current_markup))

if include_comment \
and (constants.COMMENT_TEXT not in enabled_reactions) \
and any((b for b in current_buttons if constants.COMMENT_TEXT in b.text)):
enabled_reactions = enabled_reactions.copy()
enabled_reactions.append(constants.COMMENT_TEXT)

buttons_obj = []
for r in enabled_reactions:
if r in state_reactions:
counter = state_reactions[r]
text = f'{r}{counter}'
else:
cur_btn = next((b for b in current_buttons if r in b.text), None)
if cur_btn is None:
text = f'{r}'
data = telegram_utils.encode_button_data(handler=handler,
case_id=case_id,
response=r)
b = types.InlineKeyboardButton(text=text,
callback_data=data)
buttons_obj.append(b)

data = telegram_utils.encode_button_data(handler=handler,
case_id=case_id,
response=r)
cur_btn = types.InlineKeyboardButton(text=text,
callback_data=data)
buttons_obj.append(cur_btn)
return markup_from_buttons(buttons_obj)


Expand Down
Loading

0 comments on commit eadd7a9

Please sign in to comment.