10
10
import logging
11
11
import re
12
12
import sys
13
- import uuid
14
13
from datetime import datetime , timezone
15
14
from pathlib import Path
16
15
from shutil import copy2 , make_archive
17
16
from subprocess import CalledProcessError
18
17
19
18
import aiohttp
20
19
from aleph_message .models import (
20
+ AlephMessage ,
21
21
InstanceMessage ,
22
22
ItemHash ,
23
+ ItemType ,
23
24
ProgramMessage ,
25
+ StoreMessage ,
24
26
parse_message ,
25
27
)
26
28
from aleph_message .models .execution .instance import RootfsVolume
@@ -133,6 +135,32 @@ async def download_file(url: str, local_path: Path) -> None:
133
135
tmp_path .unlink (missing_ok = True )
134
136
135
137
138
+ async def download_file_from_ipfs_or_connector (ref : str , cache_path : Path , filetype : str ) -> None :
139
+ """Download a file from the IPFS Gateway if possible, else from the vm-connector."""
140
+
141
+ if cache_path .is_file ():
142
+ logger .debug (f"File already exists: { cache_path } " )
143
+ return
144
+
145
+ message : StoreMessage = await get_store_message (ref )
146
+
147
+ if message .content .item_type == ItemType .ipfs :
148
+ # Download IPFS files from the IPFS gateway directly
149
+ cid = message .content .item_hash
150
+ url = f"{ settings .IPFS_SERVER } /{ cid } "
151
+ await download_file (url , cache_path )
152
+ else :
153
+ # Download via the vm-connector
154
+ path_mapping = {
155
+ "runtime" : "/download/runtime" ,
156
+ "code" : "/download/code" ,
157
+ "data" : "/download/data" ,
158
+ }
159
+ path = path_mapping [filetype ]
160
+ url = f"{ settings .CONNECTOR_URL } { path } /{ ref } "
161
+ await download_file (url , cache_path )
162
+
163
+
136
164
async def get_latest_amend (item_hash : str ) -> str :
137
165
if settings .FAKE_DATA_PROGRAM :
138
166
return item_hash
@@ -146,7 +174,26 @@ async def get_latest_amend(item_hash: str) -> str:
146
174
return result or item_hash
147
175
148
176
149
- async def get_message (ref : str ) -> ProgramMessage | InstanceMessage :
177
+ async def load_message (path : Path ) -> AlephMessage :
178
+ """Load a message from the cache on disk."""
179
+ with open (path ) as cache_file :
180
+ msg = json .load (cache_file )
181
+
182
+ if path in (settings .FAKE_DATA_MESSAGE , settings .FAKE_INSTANCE_MESSAGE ):
183
+ # Ensure validation passes while tweaking message content
184
+ msg = fix_message_validation (msg )
185
+
186
+ return parse_message (message_dict = msg )
187
+
188
+
189
+ async def get_message (ref : str ) -> AlephMessage :
190
+ cache_path = (Path (settings .MESSAGE_CACHE ) / ref ).with_suffix (".json" )
191
+ url = f"{ settings .CONNECTOR_URL } /download/message/{ ref } "
192
+ await download_file (url , cache_path )
193
+ return await load_message (cache_path )
194
+
195
+
196
+ async def get_executable_message (ref : str ) -> ProgramMessage | InstanceMessage :
150
197
if ref == settings .FAKE_INSTANCE_ID :
151
198
logger .debug ("Using the fake instance message since the ref matches" )
152
199
cache_path = settings .FAKE_INSTANCE_MESSAGE
@@ -158,23 +205,22 @@ async def get_message(ref: str) -> ProgramMessage | InstanceMessage:
158
205
url = f"{ settings .CONNECTOR_URL } /download/message/{ ref } "
159
206
await download_file (url , cache_path )
160
207
161
- with open (cache_path ) as cache_file :
162
- msg = json .load (cache_file )
208
+ return await load_message (cache_path )
163
209
164
- if cache_path in (settings .FAKE_DATA_MESSAGE , settings .FAKE_INSTANCE_MESSAGE ):
165
- # Ensure validation passes while tweaking message content
166
- msg = fix_message_validation (msg )
167
210
168
- result = parse_message (message_dict = msg )
169
- assert isinstance (result , InstanceMessage | ProgramMessage ), "Parsed message is not executable"
170
- return result
211
+ async def get_store_message (ref : str ) -> StoreMessage :
212
+ message = await get_message (ref )
213
+ if not isinstance (message , StoreMessage ):
214
+ msg = f"Expected a store message, got { message .type } "
215
+ raise ValueError (msg )
216
+ return message
171
217
172
218
173
219
async def get_code_path (ref : str ) -> Path :
174
220
if settings .FAKE_DATA_PROGRAM :
175
221
archive_path = Path (settings .FAKE_DATA_PROGRAM )
176
222
177
- encoding : Encoding = (await get_message (ref = "fake-message" )).content .code .encoding
223
+ encoding : Encoding = (await get_executable_message (ref = "fake-message" )).content .code .encoding
178
224
if encoding == Encoding .squashfs :
179
225
squashfs_path = Path (archive_path .name + ".squashfs" )
180
226
squashfs_path .unlink (missing_ok = True )
@@ -191,8 +237,7 @@ async def get_code_path(ref: str) -> Path:
191
237
raise ValueError (msg )
192
238
193
239
cache_path = Path (settings .CODE_CACHE ) / ref
194
- url = f"{ settings .CONNECTOR_URL } /download/code/{ ref } "
195
- await download_file (url , cache_path )
240
+ await download_file_from_ipfs_or_connector (ref , cache_path , "code" )
196
241
return cache_path
197
242
198
243
@@ -203,8 +248,7 @@ async def get_data_path(ref: str) -> Path:
203
248
return Path (f"{ data_dir } .zip" )
204
249
205
250
cache_path = Path (settings .DATA_CACHE ) / ref
206
- url = f"{ settings .CONNECTOR_URL } /download/data/{ ref } "
207
- await download_file (url , cache_path )
251
+ await download_file_from_ipfs_or_connector (ref , cache_path , "data" )
208
252
return cache_path
209
253
210
254
@@ -224,11 +268,7 @@ async def get_runtime_path(ref: str) -> Path:
224
268
return Path (settings .FAKE_DATA_RUNTIME )
225
269
226
270
cache_path = Path (settings .RUNTIME_CACHE ) / ref
227
- url = f"{ settings .CONNECTOR_URL } /download/runtime/{ ref } "
228
-
229
- if not cache_path .is_file ():
230
- # File does not exist, download it
231
- await download_file (url , cache_path )
271
+ await download_file_from_ipfs_or_connector (ref , cache_path , "runtime" )
232
272
233
273
await check_squashfs_integrity (cache_path )
234
274
await chown_to_jailman (cache_path )
@@ -242,8 +282,10 @@ async def get_rootfs_base_path(ref: ItemHash) -> Path:
242
282
return Path (settings .FAKE_INSTANCE_BASE )
243
283
244
284
cache_path = Path (settings .RUNTIME_CACHE ) / ref
245
- url = f"{ settings .CONNECTOR_URL } /download/runtime/{ ref } "
246
- await download_file (url , cache_path )
285
+
286
+ # if not cache_path.is_file():
287
+ await download_file_from_ipfs_or_connector (ref , cache_path , "runtime" )
288
+
247
289
await chown_to_jailman (cache_path )
248
290
return cache_path
249
291
@@ -364,8 +406,8 @@ async def get_existing_file(ref: str) -> Path:
364
406
return Path (settings .FAKE_DATA_VOLUME )
365
407
366
408
cache_path = Path (settings .DATA_CACHE ) / ref
367
- url = f" { settings . CONNECTOR_URL } /download/ data/ { ref } "
368
- await download_file ( url , cache_path )
409
+ await download_file_from_ipfs_or_connector ( ref , cache_path , " data" )
410
+
369
411
await chown_to_jailman (cache_path )
370
412
return cache_path
371
413
0 commit comments