23
23
TypeVar ,
24
24
Union ,
25
25
)
26
+ from io import BytesIO
26
27
27
28
import aiohttp
28
29
from aleph_message .models import (
31
32
AlephMessage ,
32
33
ForgetContent ,
33
34
ForgetMessage ,
35
+ ItemHash ,
34
36
ItemType ,
35
37
MessageType ,
36
38
PostContent ,
43
45
)
44
46
from aleph_message .models .execution .base import Encoding
45
47
from aleph_message .status import MessageStatus
46
- from pydantic import ValidationError
48
+ from pydantic import ValidationError , BaseModel
47
49
48
50
from aleph .sdk .types import Account , GenericMessage , StorageEnum
49
-
51
+ from aleph . sdk . utils import copy_async_readable_to_buffer , Writable , AsyncReadable
50
52
from .conf import settings
51
53
from .exceptions import (
52
54
BroadcastError ,
53
55
InvalidMessageError ,
54
56
MessageNotFoundError ,
55
57
MultipleMessagesError ,
58
+ FileTooLarge ,
56
59
)
57
60
from .models import MessagesResponse
58
61
from .utils import check_unix_socket_valid , get_message_type_value
@@ -229,6 +232,12 @@ def get_posts(
229
232
def download_file (self , file_hash : str ) -> bytes :
230
233
return self ._wrap (self .async_session .download_file , file_hash = file_hash )
231
234
235
+ def download_file_ipfs (self , file_hash : str ) -> bytes :
236
+ return self ._wrap (
237
+ self .async_session .download_file_ipfs ,
238
+ file_hash = file_hash ,
239
+ )
240
+
232
241
def watch_messages (
233
242
self ,
234
243
message_type : Optional [MessageType ] = None ,
@@ -609,6 +618,55 @@ async def get_posts(
609
618
resp .raise_for_status ()
610
619
return await resp .json ()
611
620
621
+ async def download_file_to_buffer (
622
+ self ,
623
+ file_hash : str ,
624
+ output_buffer : Writable [bytes ],
625
+ ) -> None :
626
+ """
627
+ Download a file from the storage engine and write it to the specified output buffer.
628
+ :param file_hash: The hash of the file to retrieve.
629
+ :param output_buffer: Writable binary buffer. The file will be written to this buffer.
630
+ """
631
+
632
+ async with self .http_session .get (
633
+ f"/api/v0/storage/raw/{ file_hash } "
634
+ ) as response :
635
+ if response .status == 200 :
636
+ await copy_async_readable_to_buffer (
637
+ response .content , output_buffer , chunk_size = 16 * 1024
638
+ )
639
+ if response .status == 413 :
640
+ ipfs_hash = ItemHash (file_hash )
641
+ if ipfs_hash .item_type == ItemType .ipfs :
642
+ return await self .download_file_ipfs_to_buffer (
643
+ file_hash , output_buffer
644
+ )
645
+ else :
646
+ raise FileTooLarge (f"The file from { file_hash } is too large" )
647
+
648
+ async def download_file_ipfs_to_buffer (
649
+ self ,
650
+ file_hash : str ,
651
+ output_buffer : Writable [bytes ],
652
+ ) -> None :
653
+ """
654
+ Download a file from the storage engine and write it to the specified output buffer.
655
+
656
+ :param file_hash: The hash of the file to retrieve.
657
+ :param output_buffer: The binary output buffer to write the file data to.
658
+ """
659
+ async with aiohttp .ClientSession () as session :
660
+ async with session .get (
661
+ f"https://ipfs.aleph.im/ipfs/{ file_hash } "
662
+ ) as response :
663
+ if response .status == 200 :
664
+ await copy_async_readable_to_buffer (
665
+ response .content , output_buffer , chunk_size = 16 * 1024
666
+ )
667
+ else :
668
+ response .raise_for_status ()
669
+
612
670
async def download_file (
613
671
self ,
614
672
file_hash : str ,
@@ -620,11 +678,24 @@ async def download_file(
620
678
621
679
:param file_hash: The hash of the file to retrieve.
622
680
"""
623
- async with self .http_session .get (
624
- f"/api/v0/storage/raw/{ file_hash } "
625
- ) as response :
626
- response .raise_for_status ()
627
- return await response .read ()
681
+ buffer = BytesIO ()
682
+ await self .download_file_to_buffer (file_hash , output_buffer = buffer )
683
+ return buffer .getvalue ()
684
+
685
+ async def download_file_ipfs (
686
+ self ,
687
+ file_hash : str ,
688
+ ) -> bytes :
689
+ """
690
+ Get a file from the ipfs storage engine as raw bytes.
691
+
692
+ Warning: Downloading large files can be slow.
693
+
694
+ :param file_hash: The hash of the file to retrieve.
695
+ """
696
+ buffer = BytesIO ()
697
+ await self .download_file_ipfs_to_buffer (file_hash , output_buffer = buffer )
698
+ return buffer .getvalue ()
628
699
629
700
async def get_messages (
630
701
self ,
0 commit comments