2019-04-21 14:56:14 +03:00
|
|
|
import datetime
|
|
|
|
|
|
|
|
from .tl import types
|
|
|
|
|
|
|
|
|
|
|
|
class StateCache:
|
|
|
|
"""
|
|
|
|
In-memory update state cache, defaultdict-like behaviour.
|
|
|
|
"""
|
2019-04-22 13:24:45 +03:00
|
|
|
def __init__(self, initial, loggers):
|
2019-04-21 14:56:14 +03:00
|
|
|
# We only care about the pts and the date. By using a tuple which
|
|
|
|
# is lightweight and immutable we can easily copy them around to
|
|
|
|
# each update in case they need to fetch missing entities.
|
2019-04-22 13:24:45 +03:00
|
|
|
self._logger = loggers[__name__]
|
2019-04-21 14:56:14 +03:00
|
|
|
if initial:
|
|
|
|
self._pts_date = initial.pts, initial.date
|
|
|
|
else:
|
|
|
|
self._pts_date = 1, datetime.datetime.now()
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
self.__dict__.clear()
|
|
|
|
self._pts_date = (1, 1)
|
|
|
|
|
|
|
|
# TODO Call this when receiving responses too...?
|
|
|
|
def update(
|
|
|
|
self,
|
|
|
|
update,
|
|
|
|
*,
|
|
|
|
channel_id=None,
|
2019-05-01 17:37:54 +03:00
|
|
|
has_pts=frozenset(x.CONSTRUCTOR_ID for x in (
|
2019-04-21 14:56:14 +03:00
|
|
|
types.UpdateNewMessage,
|
|
|
|
types.UpdateDeleteMessages,
|
|
|
|
types.UpdateReadHistoryInbox,
|
|
|
|
types.UpdateReadHistoryOutbox,
|
|
|
|
types.UpdateWebPage,
|
|
|
|
types.UpdateReadMessagesContents,
|
|
|
|
types.UpdateEditMessage,
|
|
|
|
types.updates.State,
|
|
|
|
types.updates.DifferenceTooLong,
|
|
|
|
types.UpdateShortMessage,
|
|
|
|
types.UpdateShortChatMessage,
|
|
|
|
types.UpdateShortSentMessage
|
2019-05-01 17:37:54 +03:00
|
|
|
)),
|
|
|
|
has_date=frozenset(x.CONSTRUCTOR_ID for x in (
|
2019-04-21 14:56:14 +03:00
|
|
|
types.UpdateUserPhoto,
|
|
|
|
types.UpdateEncryption,
|
|
|
|
types.UpdateEncryptedMessagesRead,
|
|
|
|
types.UpdateChatParticipantAdd,
|
|
|
|
types.updates.DifferenceEmpty,
|
|
|
|
types.UpdateShortMessage,
|
|
|
|
types.UpdateShortChatMessage,
|
|
|
|
types.UpdateShort,
|
|
|
|
types.UpdatesCombined,
|
|
|
|
types.Updates,
|
|
|
|
types.UpdateShortSentMessage,
|
2019-05-01 17:37:54 +03:00
|
|
|
)),
|
|
|
|
has_channel_pts=frozenset(x.CONSTRUCTOR_ID for x in (
|
2019-04-21 14:56:14 +03:00
|
|
|
types.UpdateChannelTooLong,
|
|
|
|
types.UpdateNewChannelMessage,
|
|
|
|
types.UpdateDeleteChannelMessages,
|
|
|
|
types.UpdateEditChannelMessage,
|
|
|
|
types.UpdateChannelWebPage,
|
|
|
|
types.updates.ChannelDifferenceEmpty,
|
|
|
|
types.updates.ChannelDifferenceTooLong,
|
|
|
|
types.updates.ChannelDifference
|
2019-05-01 17:37:54 +03:00
|
|
|
))
|
2019-04-21 14:56:14 +03:00
|
|
|
):
|
|
|
|
"""
|
|
|
|
Update the state with the given update.
|
|
|
|
"""
|
2019-05-01 17:37:54 +03:00
|
|
|
cid = update.CONSTRUCTOR_ID
|
|
|
|
if cid in has_pts:
|
|
|
|
if cid in has_date:
|
|
|
|
self._pts_date = update.pts, update.date
|
|
|
|
else:
|
|
|
|
self._pts_date = update.pts, self._pts_date[1]
|
|
|
|
elif cid in has_date:
|
2019-04-21 14:56:14 +03:00
|
|
|
self._pts_date = self._pts_date[0], update.date
|
|
|
|
|
2019-05-01 17:37:54 +03:00
|
|
|
if cid in has_channel_pts:
|
2019-04-21 14:56:14 +03:00
|
|
|
if channel_id is None:
|
|
|
|
channel_id = self.get_channel_id(update)
|
|
|
|
|
|
|
|
if channel_id is None:
|
2019-04-22 13:24:45 +03:00
|
|
|
self._logger.info(
|
|
|
|
'Failed to retrieve channel_id from %s', update)
|
2019-04-21 14:56:14 +03:00
|
|
|
else:
|
|
|
|
self.__dict__[channel_id] = update.pts
|
|
|
|
|
|
|
|
def get_channel_id(
|
2019-04-22 13:24:45 +03:00
|
|
|
self,
|
2019-04-21 14:56:14 +03:00
|
|
|
update,
|
2019-05-01 17:37:54 +03:00
|
|
|
has_channel_id=frozenset(x.CONSTRUCTOR_ID for x in (
|
2019-04-21 14:56:14 +03:00
|
|
|
types.UpdateChannelTooLong,
|
|
|
|
types.UpdateDeleteChannelMessages,
|
|
|
|
types.UpdateChannelWebPage
|
2019-05-01 17:37:54 +03:00
|
|
|
)),
|
|
|
|
has_message=frozenset(x.CONSTRUCTOR_ID for x in (
|
2019-04-21 14:56:14 +03:00
|
|
|
types.UpdateNewChannelMessage,
|
|
|
|
types.UpdateEditChannelMessage
|
2019-05-01 17:37:54 +03:00
|
|
|
))
|
2019-04-21 14:56:14 +03:00
|
|
|
):
|
2019-05-01 17:37:54 +03:00
|
|
|
"""
|
|
|
|
Gets the **unmarked** channel ID from this update, if it has any.
|
|
|
|
|
|
|
|
Fails for ``*difference`` updates, where ``channel_id``
|
|
|
|
is supposedly already known from the outside.
|
|
|
|
"""
|
|
|
|
cid = update.CONSTRUCTOR_ID
|
|
|
|
if cid in has_channel_id:
|
2019-04-21 14:56:14 +03:00
|
|
|
return update.channel_id
|
2019-05-01 17:37:54 +03:00
|
|
|
elif cid in has_message:
|
2019-04-22 13:24:45 +03:00
|
|
|
if update.message.to_id is None:
|
|
|
|
self._logger.info('Update has None to_id %s', update)
|
|
|
|
else:
|
|
|
|
return update.message.to_id.channel_id
|
|
|
|
|
|
|
|
return None
|
2019-04-21 14:56:14 +03:00
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
"""
|
2019-05-01 17:37:54 +03:00
|
|
|
If `item` is ``None``, returns the default ``(pts, date)``.
|
|
|
|
|
|
|
|
If it's an **unmarked** channel ID, returns its ``pts``.
|
2019-04-21 14:56:14 +03:00
|
|
|
"""
|
|
|
|
if item is None:
|
|
|
|
return self._pts_date
|
|
|
|
else:
|
|
|
|
return self.__dict__.get(item, 1)
|