|
32 | 32 | from io import StringIO, BytesIO |
33 | 33 | from mimetypes import MimeTypes |
34 | 34 | from pathlib import Path |
35 | | -from typing import Union, List, Optional, Callable, AsyncGenerator, Type |
| 35 | +from typing import Union, List, Optional, Callable, AsyncGenerator, Type, Tuple |
36 | 36 |
|
37 | 37 | import pyrogram |
38 | 38 | from pyrogram import __version__, __license__ |
39 | 39 | from pyrogram import enums |
40 | 40 | from pyrogram import raw |
41 | 41 | from pyrogram import utils |
42 | 42 | from pyrogram.crypto import aes |
43 | | -from pyrogram.errors import CDNFileHashMismatch, AuthBytesInvalid |
| 43 | +from pyrogram.errors import CDNFileHashMismatch, AuthBytesInvalid, ChannelInvalid, PersistentTimestampInvalid, \ |
| 44 | + PersistentTimestampOutdated |
44 | 45 | from pyrogram.errors import ( |
45 | 46 | SessionPasswordNeeded, |
46 | 47 | VolumeLocNotFound, ChannelPrivate, |
@@ -186,7 +187,7 @@ class Client(Methods): |
186 | 187 | Defaults to False, because ``getpass`` (the library used) is known to be problematic in some |
187 | 188 | terminal environments. |
188 | 189 |
|
189 | | - max_concurrent_transmissions (``bool``, *optional*): |
| 190 | + max_concurrent_transmissions (``int``, *optional*): |
190 | 191 | Set the maximum amount of concurrent transmissions (uploads & downloads). |
191 | 192 | A value that is too high may result in network related issues. |
192 | 193 | Defaults to 1. |
@@ -576,14 +577,14 @@ async def handle_updates(self, updates): |
576 | 577 | pts = getattr(update, "pts", None) |
577 | 578 | pts_count = getattr(update, "pts_count", None) |
578 | 579 |
|
579 | | - if pts: |
| 580 | + if pts and not self.skip_updates: |
580 | 581 | await self.storage.update_state( |
581 | 582 | ( |
582 | | - utils.get_channel_id(channel_id) if channel_id else self.me.id, |
| 583 | + utils.get_channel_id(channel_id) if channel_id else 0, |
583 | 584 | pts, |
584 | 585 | None, |
585 | 586 | updates.date, |
586 | | - None |
| 587 | + updates.seq |
587 | 588 | ) |
588 | 589 | ) |
589 | 590 |
|
@@ -617,15 +618,16 @@ async def handle_updates(self, updates): |
617 | 618 |
|
618 | 619 | self.dispatcher.updates_queue.put_nowait((update, users, chats)) |
619 | 620 | elif isinstance(updates, (raw.types.UpdateShortMessage, raw.types.UpdateShortChatMessage)): |
620 | | - await self.storage.update_state( |
621 | | - ( |
622 | | - self.me.id, |
623 | | - updates.pts, |
624 | | - None, |
625 | | - updates.date, |
626 | | - None |
| 621 | + if not self.skip_updates: |
| 622 | + await self.storage.update_state( |
| 623 | + ( |
| 624 | + 0, |
| 625 | + updates.pts, |
| 626 | + None, |
| 627 | + updates.date, |
| 628 | + None |
| 629 | + ) |
627 | 630 | ) |
628 | | - ) |
629 | 631 |
|
630 | 632 | diff = await self.invoke( |
631 | 633 | raw.functions.updates.GetDifference( |
@@ -653,6 +655,92 @@ async def handle_updates(self, updates): |
653 | 655 | elif isinstance(updates, raw.types.UpdatesTooLong): |
654 | 656 | log.info(updates) |
655 | 657 |
|
| 658 | + async def recover_gaps(self) -> Tuple[int, int]: |
| 659 | + states = await self.storage.update_state() |
| 660 | + |
| 661 | + message_updates_counter = 0 |
| 662 | + other_updates_counter = 0 |
| 663 | + |
| 664 | + if not states: |
| 665 | + log.info("No states found, skipping recovery.") |
| 666 | + return message_updates_counter, other_updates_counter |
| 667 | + |
| 668 | + for state in states: |
| 669 | + id, local_pts, _, local_date, _ = state |
| 670 | + |
| 671 | + prev_pts = 0 |
| 672 | + |
| 673 | + while True: |
| 674 | + try: |
| 675 | + diff = await self.invoke( |
| 676 | + raw.functions.updates.GetChannelDifference( |
| 677 | + channel=await self.resolve_peer(id), |
| 678 | + filter=raw.types.ChannelMessagesFilterEmpty(), |
| 679 | + pts=local_pts, |
| 680 | + limit=10000, |
| 681 | + force=False |
| 682 | + ) if id < 0 else |
| 683 | + raw.functions.updates.GetDifference( |
| 684 | + pts=local_pts, |
| 685 | + date=local_date, |
| 686 | + qts=0 |
| 687 | + ) |
| 688 | + ) |
| 689 | + except (ChannelPrivate, ChannelInvalid, PersistentTimestampOutdated, PersistentTimestampInvalid): |
| 690 | + break |
| 691 | + |
| 692 | + if isinstance(diff, raw.types.updates.DifferenceEmpty): |
| 693 | + break |
| 694 | + elif isinstance(diff, raw.types.updates.DifferenceTooLong): |
| 695 | + break |
| 696 | + elif isinstance(diff, raw.types.updates.Difference): |
| 697 | + local_pts = diff.state.pts |
| 698 | + elif isinstance(diff, raw.types.updates.DifferenceSlice): |
| 699 | + local_pts = diff.intermediate_state.pts |
| 700 | + local_date = diff.intermediate_state.date |
| 701 | + |
| 702 | + if prev_pts == local_pts: |
| 703 | + break |
| 704 | + |
| 705 | + prev_pts = local_pts |
| 706 | + elif isinstance(diff, raw.types.updates.ChannelDifferenceEmpty): |
| 707 | + break |
| 708 | + elif isinstance(diff, raw.types.updates.ChannelDifferenceTooLong): |
| 709 | + break |
| 710 | + elif isinstance(diff, raw.types.updates.ChannelDifference): |
| 711 | + local_pts = diff.pts |
| 712 | + |
| 713 | + users = {i.id: i for i in diff.users} |
| 714 | + chats = {i.id: i for i in diff.chats} |
| 715 | + |
| 716 | + for message in diff.new_messages: |
| 717 | + message_updates_counter += 1 |
| 718 | + self.dispatcher.updates_queue.put_nowait( |
| 719 | + ( |
| 720 | + raw.types.UpdateNewMessage( |
| 721 | + message=message, |
| 722 | + pts=local_pts, |
| 723 | + pts_count=-1 |
| 724 | + ), |
| 725 | + users, |
| 726 | + chats |
| 727 | + ) |
| 728 | + ) |
| 729 | + |
| 730 | + for update in diff.other_updates: |
| 731 | + other_updates_counter += 1 |
| 732 | + self.dispatcher.updates_queue.put_nowait( |
| 733 | + (update, users, chats) |
| 734 | + ) |
| 735 | + |
| 736 | + if isinstance(diff, (raw.types.updates.Difference, raw.types.updates.ChannelDifference)): |
| 737 | + break |
| 738 | + |
| 739 | + await self.storage.update_state(id) |
| 740 | + |
| 741 | + log.info("Recovered %s messages and %s updates.", message_updates_counter, other_updates_counter) |
| 742 | + return message_updates_counter, other_updates_counter |
| 743 | + |
656 | 744 | async def load_session(self): |
657 | 745 | await self.storage.open() |
658 | 746 |
|
|
0 commit comments