Invoke multiple getParticipant's at the same time (#580)

This commit is contained in:
Lonami Exo 2018-02-28 17:10:44 +01:00
parent 057c6a0b12
commit 3afd7dca84

View File

@ -1033,9 +1033,9 @@ class TelegramClient(TelegramBareClient):
aggressive (:obj:`bool`, optional): aggressive (:obj:`bool`, optional):
Aggressively looks for all participants in the chat in Aggressively looks for all participants in the chat in
order to get more than 10,000 members (a hard limit order to get more than 10,000 members (a hard limit
imposed by Telegram). Note that this might make over imposed by Telegram). Note that this might take a long
20 times more requests and take over 5 minutes in some time (over 5 minutes), but is able to return over 90,000
cases, but often returns well over 10,000 members. participants on groups with 100,000 members.
This has no effect for groups or channels with less than This has no effect for groups or channels with less than
10,000 members. 10,000 members.
@ -1053,31 +1053,49 @@ class TelegramClient(TelegramBareClient):
all_participants = {} all_participants = {}
if total > 10000 and aggressive: if total > 10000 and aggressive:
searches = tuple(chr(x) for x in range(ord('a'), ord('z') + 1)) requests = [GetParticipantsRequest(
else:
searches = ('',)
for extra_search in searches:
req = GetParticipantsRequest(
channel=entity, channel=entity,
filter=ChannelParticipantsSearch(search + extra_search), filter=ChannelParticipantsSearch(search + chr(x)),
offset=0, offset=0,
limit=0, limit=200,
hash=0 hash=0
) ) for x in range(ord('a'), ord('z') + 1)]
while True: else:
req.limit = min(limit - req.offset, 200) requests = [GetParticipantsRequest(
participants = self(req) channel=entity,
if not participants.users: filter=ChannelParticipantsSearch(search),
offset=0,
limit=200,
hash=0
)]
while requests:
# Only care about the limit for the first request
# (small amount of people, won't be aggressive).
#
# Most people won't care about getting exactly 12,345
# members so it doesn't really matter not to be 100%
# precise with being out of the offset/limit here.
requests[0].limit = min(limit - requests[0].offset, 200)
if requests[0].offset > limit:
break break
results = self(*requests)
for i in reversed(range(len(requests))):
participants = results[i]
if not participants.users:
requests.pop(i)
else:
requests[i].offset += len(participants.users)
for user in participants.users: for user in participants.users:
if len(all_participants) < limit: if len(all_participants) < limit:
all_participants[user.id] = user all_participants[user.id] = user
req.offset += len(participants.users) if limit < float('inf'):
if req.offset > limit: values = all_participants.values()
break else:
values = itertools.islice(all_participants.values(), limit)
users = UserList(all_participants.values()) users = UserList(values)
users.total = total users.total = total
elif isinstance(entity, InputPeerChat): elif isinstance(entity, InputPeerChat):
users = self(GetFullChatRequest(entity.chat_id)).users users = self(GetFullChatRequest(entity.chat_id)).users