|
5 | 5 | import ipfshttpclient |
6 | 6 | from aiohttp import ClientSession, ClientTimeout |
7 | 7 |
|
| 8 | +from oracle.oracle.utils import LimitedSizeDict |
8 | 9 | from oracle.settings import ( |
9 | 10 | INFURA_IPFS_CLIENT_ENDPOINT, |
10 | 11 | INFURA_IPFS_CLIENT_PASSWORD, |
|
17 | 18 |
|
18 | 19 | timeout = ClientTimeout(total=60) |
19 | 20 |
|
| 21 | +CACHE_SIZE = 1024 |
| 22 | +IPFS_CACHE = LimitedSizeDict(size_limit=CACHE_SIZE) |
| 23 | + |
20 | 24 |
|
21 | 25 | @backoff.on_exception(backoff.expo, Exception, max_time=900) |
22 | 26 | async def ipfs_fetch(ipfs_hash: str) -> Union[Dict[Any, Any], List[Dict[Any, Any]]]: |
23 | 27 | """Tries to fetch IPFS hash from different sources.""" |
24 | 28 | _ipfs_hash = ipfs_hash.replace("ipfs://", "").replace("/ipfs/", "") |
25 | 29 |
|
26 | | - async with ClientSession(timeout=timeout) as session: |
27 | | - for endpoint in IPFS_FETCH_ENDPOINTS: |
| 30 | + if IPFS_CACHE.get(_ipfs_hash): |
| 31 | + return IPFS_CACHE.get(_ipfs_hash) |
| 32 | + |
| 33 | + async def _fetch(_ipfs_hash): |
| 34 | + async with ClientSession(timeout=timeout) as session: |
| 35 | + for endpoint in IPFS_FETCH_ENDPOINTS: |
| 36 | + try: |
| 37 | + response = await session.get( |
| 38 | + f"{endpoint.rstrip('/')}/ipfs/{_ipfs_hash}" |
| 39 | + ) |
| 40 | + response.raise_for_status() |
| 41 | + return await response.json() |
| 42 | + except BaseException as e: # noqa: E722 |
| 43 | + logger.exception(e) |
| 44 | + pass |
| 45 | + |
| 46 | + if LOCAL_IPFS_CLIENT_ENDPOINT: |
28 | 47 | try: |
29 | | - response = await session.get( |
30 | | - f"{endpoint.rstrip('/')}/ipfs/{_ipfs_hash}" |
31 | | - ) |
32 | | - response.raise_for_status() |
33 | | - return await response.json() |
34 | | - except BaseException as e: # noqa: E722 |
35 | | - logger.exception(e) |
| 48 | + with ipfshttpclient.connect(LOCAL_IPFS_CLIENT_ENDPOINT) as client: |
| 49 | + return client.get_json(_ipfs_hash) |
| 50 | + except ipfshttpclient.exceptions.TimeoutError: |
36 | 51 | pass |
37 | 52 |
|
38 | | - if LOCAL_IPFS_CLIENT_ENDPOINT: |
39 | 53 | try: |
40 | | - with ipfshttpclient.connect(LOCAL_IPFS_CLIENT_ENDPOINT) as client: |
| 54 | + with ipfshttpclient.connect( |
| 55 | + INFURA_IPFS_CLIENT_ENDPOINT, |
| 56 | + username=INFURA_IPFS_CLIENT_USERNAME, |
| 57 | + password=INFURA_IPFS_CLIENT_PASSWORD, |
| 58 | + ) as client: |
41 | 59 | return client.get_json(_ipfs_hash) |
42 | 60 | except ipfshttpclient.exceptions.TimeoutError: |
43 | 61 | pass |
44 | 62 |
|
45 | | - try: |
46 | | - with ipfshttpclient.connect( |
47 | | - INFURA_IPFS_CLIENT_ENDPOINT, |
48 | | - username=INFURA_IPFS_CLIENT_USERNAME, |
49 | | - password=INFURA_IPFS_CLIENT_PASSWORD, |
50 | | - ) as client: |
51 | | - return client.get_json(_ipfs_hash) |
52 | | - except ipfshttpclient.exceptions.TimeoutError: |
53 | | - pass |
| 63 | + data = await _fetch(_ipfs_hash) |
| 64 | + if data: |
| 65 | + IPFS_CACHE[_ipfs_hash] = data |
| 66 | + return data |
54 | 67 |
|
55 | 68 | raise RuntimeError(f"Failed to fetch IPFS data at {_ipfs_hash}") |
0 commit comments