limit the rate of inline keyboard update
This commit is contained in:
parent
58c6e61a30
commit
d17e3086fa
1 changed files with 51 additions and 21 deletions
72
tgmsbot.py
72
tgmsbot.py
|
@ -14,6 +14,11 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
token = "token_here"
|
token = "token_here"
|
||||||
updater = Updater(token, workers=16)
|
updater = Updater(token, workers=16)
|
||||||
|
job_queue = updater.job_queue
|
||||||
|
job_queue.start()
|
||||||
|
|
||||||
|
KBD_MIN_INTERVAL = 0.6
|
||||||
|
KBD_DELAY_SECS = 0.6
|
||||||
|
|
||||||
HEIGHT = 8
|
HEIGHT = 8
|
||||||
WIDTH = 8
|
WIDTH = 8
|
||||||
|
@ -57,31 +62,36 @@ class Game():
|
||||||
self.board = board
|
self.board = board
|
||||||
self.group = group
|
self.group = group
|
||||||
self.creator = creator
|
self.creator = creator
|
||||||
self.actions = dict()
|
self.__actions = dict()
|
||||||
self.last_player = None
|
self.__last_player = None
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
self.stopped = False
|
self.stopped = False
|
||||||
self.extra = {"timeout": 0}
|
# timestamp of the last update keyboard action,
|
||||||
|
# it is used to calculate time gap between
|
||||||
|
# two actions and identify unique actions.
|
||||||
|
self.last_action = 0
|
||||||
|
# number of timeout error catched
|
||||||
|
self.timeouts = 0
|
||||||
def save_action(self, user, spot):
|
def save_action(self, user, spot):
|
||||||
'''spot is supposed to be a tuple'''
|
'''spot is supposed to be a tuple'''
|
||||||
self.last_player = user
|
self.__last_player = user
|
||||||
if self.actions.get(user, None):
|
if self.__actions.get(user, None):
|
||||||
self.actions[user].append(spot)
|
self.__actions[user].append(spot)
|
||||||
else:
|
else:
|
||||||
self.actions[user] = [spot,]
|
self.__actions[user] = [spot,]
|
||||||
def actions_sum(self):
|
def actions_sum(self):
|
||||||
mysum = 0
|
mysum = 0
|
||||||
for user in self.actions:
|
for user in self.__actions:
|
||||||
count = len(self.actions.get(user, list()))
|
count = len(self.__actions.get(user, list()))
|
||||||
mysum += count
|
mysum += count
|
||||||
return mysum
|
return mysum
|
||||||
def get_last_player(self):
|
def get_last_player(self):
|
||||||
return display_username(self.last_player)
|
return display_username(self.__last_player)
|
||||||
def get_actions(self):
|
def get_actions(self):
|
||||||
'''Convert actions into text'''
|
'''Convert actions into text'''
|
||||||
msg = ""
|
msg = ""
|
||||||
for user in self.actions:
|
for user in self.__actions:
|
||||||
count = len(self.actions.get(user, list()))
|
count = len(self.__actions.get(user, list()))
|
||||||
msg = "{}{} - {}项操作\n".format(msg, display_username(user), count)
|
msg = "{}{} - {}项操作\n".format(msg, display_username(user), count)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
@ -153,9 +163,9 @@ def send_keyboard(bot, update, args):
|
||||||
parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(keyboard))
|
parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(keyboard))
|
||||||
|
|
||||||
def send_help(bot, update):
|
def send_help(bot, update):
|
||||||
|
logger.debug("Start from {0}".format(update.message.from_user.id))
|
||||||
msg = update.message
|
msg = update.message
|
||||||
msg.reply_text("这是一个扫雷bot\n\n/mine 开始新游戏")
|
msg.reply_text("这是一个扫雷bot\n\n/mine 开始新游戏")
|
||||||
logger.debug("Start from {0}".format(update.message.from_user.id))
|
|
||||||
|
|
||||||
def send_source(bot, update):
|
def send_source(bot, update):
|
||||||
logger.debug("Source from {0}".format(update.message.from_user.id))
|
logger.debug("Source from {0}".format(update.message.from_user.id))
|
||||||
|
@ -166,7 +176,24 @@ def send_status(bot, update):
|
||||||
count = game_manager.count()
|
count = game_manager.count()
|
||||||
update.message.reply_text('当前进行的游戏: {}'.format(count))
|
update.message.reply_text('当前进行的游戏: {}'.format(count))
|
||||||
|
|
||||||
def update_keyboard(bot, bhash, game, chat_id, message_id):
|
def update_keyboard_request(bot, bhash, game, chat_id, message_id):
|
||||||
|
current_action_timestamp = time.time()
|
||||||
|
if current_action_timestamp - game.last_action <= KBD_MIN_INTERVAL:
|
||||||
|
logger.debug('Rate limit triggered.')
|
||||||
|
game.last_action = current_action_timestamp
|
||||||
|
job_queue.run_once(update_keyboard, KBD_DELAY_SECS,
|
||||||
|
context=(bhash, game, chat_id, message_id, current_action_timestamp))
|
||||||
|
else:
|
||||||
|
game.last_action = current_action_timestamp
|
||||||
|
update_keyboard(bot, None, noqueue=(bhash, game, chat_id, message_id))
|
||||||
|
def update_keyboard(bot, job, noqueue=None):
|
||||||
|
if noqueue:
|
||||||
|
(bhash, game, chat_id, message_id) = noqueue
|
||||||
|
else:
|
||||||
|
(bhash, game, chat_id, message_id, current_action_timestamp) = job.context
|
||||||
|
if current_action_timestamp != game.last_action:
|
||||||
|
logger.debug('New update action requested, abort this one.')
|
||||||
|
return
|
||||||
def gen_keyboard(board):
|
def gen_keyboard(board):
|
||||||
keyboard = list()
|
keyboard = list()
|
||||||
for row in range(board.height):
|
for row in range(board.height):
|
||||||
|
@ -192,7 +219,7 @@ def update_keyboard(bot, bhash, game, chat_id, message_id):
|
||||||
reply_markup=InlineKeyboardMarkup(keyboard))
|
reply_markup=InlineKeyboardMarkup(keyboard))
|
||||||
except TimedOutError:
|
except TimedOutError:
|
||||||
logger.debug('time out in game {}.'.format(bhash))
|
logger.debug('time out in game {}.'.format(bhash))
|
||||||
game.extra["timeout"] += 1
|
game.timeouts += 1
|
||||||
|
|
||||||
def handle_button_click(bot, update):
|
def handle_button_click(bot, update):
|
||||||
msg = update.callback_query.message
|
msg = update.callback_query.message
|
||||||
|
@ -205,7 +232,7 @@ def handle_button_click(bot, update):
|
||||||
data = data.split(' ')
|
data = data.split(' ')
|
||||||
data = [int(i) for i in data]
|
data = [int(i) for i in data]
|
||||||
(bhash, row, col) = data
|
(bhash, row, col) = data
|
||||||
except Exception as err:
|
except:
|
||||||
logger.info('Unknown callback data: {} from user {}'.format(data, user.id))
|
logger.info('Unknown callback data: {} from user {}'.format(data, user.id))
|
||||||
return
|
return
|
||||||
game = game_manager.get_game_from_hash(bhash)
|
game = game_manager.get_game_from_hash(bhash)
|
||||||
|
@ -219,7 +246,7 @@ def handle_button_click(bot, update):
|
||||||
mmap = None
|
mmap = None
|
||||||
board.move((row, col))
|
board.move((row, col))
|
||||||
game.save_action(user, (row, col))
|
game.save_action(user, (row, col))
|
||||||
update_keyboard(bot, bhash, game, chat_id, msg.message_id)
|
update_keyboard_request(bot, bhash, game, chat_id, msg.message_id)
|
||||||
else:
|
else:
|
||||||
mmap = deepcopy(board.map)
|
mmap = deepcopy(board.map)
|
||||||
board.move((row, col))
|
board.move((row, col))
|
||||||
|
@ -228,13 +255,13 @@ def handle_button_click(bot, update):
|
||||||
# if this is the first move, there's no mmap
|
# if this is the first move, there's no mmap
|
||||||
if mmap is not None:
|
if mmap is not None:
|
||||||
game.save_action(user, (row, col))
|
game.save_action(user, (row, col))
|
||||||
update_keyboard(bot, bhash, game, chat_id, msg.message_id)
|
update_keyboard_request(bot, bhash, game, chat_id, msg.message_id)
|
||||||
(s_op, s_is, s_3bv) = board.gen_statistics()
|
(s_op, s_is, s_3bv) = board.gen_statistics()
|
||||||
ops_count = game.actions_sum()
|
ops_count = game.actions_sum()
|
||||||
ops_list = game.get_actions()
|
ops_list = game.get_actions()
|
||||||
last_player = game.get_last_player()
|
last_player = game.get_last_player()
|
||||||
time_used = time.time() - game.start_time
|
time_used = time.time() - game.start_time
|
||||||
timeouts = game.extra["timeout"]
|
timeouts = game.timeouts
|
||||||
if board.state == 2:
|
if board.state == 2:
|
||||||
template = WIN_TEXT_TEMPLATE
|
template = WIN_TEXT_TEMPLATE
|
||||||
else:
|
else:
|
||||||
|
@ -242,11 +269,14 @@ def handle_button_click(bot, update):
|
||||||
myreply = template.format(s_op=s_op, s_is=s_is, s_3bv=s_3bv, ops_count=ops_count,
|
myreply = template.format(s_op=s_op, s_is=s_is, s_3bv=s_3bv, ops_count=ops_count,
|
||||||
ops_list=ops_list, last_player=last_player,
|
ops_list=ops_list, last_player=last_player,
|
||||||
time=round(time_used, 4), timeouts=timeouts)
|
time=round(time_used, 4), timeouts=timeouts)
|
||||||
msg.reply_text(myreply, parse_mode="Markdown")
|
try:
|
||||||
|
msg.reply_text(myreply, parse_mode="Markdown")
|
||||||
|
except TimedOutError:
|
||||||
|
logger.debug('timeout sending report for game {}'.format(bhash))
|
||||||
game_manager.remove(bhash)
|
game_manager.remove(bhash)
|
||||||
elif mmap is not None and (not array_equal(board.map, mmap)):
|
elif mmap is not None and (not array_equal(board.map, mmap)):
|
||||||
game.save_action(user, (row, col))
|
game.save_action(user, (row, col))
|
||||||
update_keyboard(bot, bhash, game, chat_id, msg.message_id)
|
update_keyboard_request(bot, bhash, game, chat_id, msg.message_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue