hippius 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hippius-0.1.0.dist-info/METADATA +475 -0
- hippius-0.1.0.dist-info/RECORD +9 -0
- hippius-0.1.0.dist-info/WHEEL +4 -0
- hippius-0.1.0.dist-info/entry_points.txt +4 -0
- hippius_sdk/__init__.py +11 -0
- hippius_sdk/cli.py +658 -0
- hippius_sdk/client.py +246 -0
- hippius_sdk/ipfs.py +985 -0
- hippius_sdk/substrate.py +688 -0
hippius_sdk/client.py
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
"""
|
2
|
+
Main client for the Hippius SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import os
|
6
|
+
from typing import Dict, Any, Optional, List, Union
|
7
|
+
from hippius_sdk.ipfs import IPFSClient
|
8
|
+
from hippius_sdk.substrate import SubstrateClient, FileInput
|
9
|
+
|
10
|
+
|
11
|
+
class HippiusClient:
|
12
|
+
"""
|
13
|
+
Main client for interacting with the Hippius ecosystem.
|
14
|
+
|
15
|
+
Provides IPFS operations, with Substrate functionality for storage requests.
|
16
|
+
"""
|
17
|
+
|
18
|
+
def __init__(
|
19
|
+
self,
|
20
|
+
ipfs_gateway: str = "https://ipfs.io",
|
21
|
+
ipfs_api_url: str = "https://relay-fr.hippius.network",
|
22
|
+
substrate_url: str = None,
|
23
|
+
substrate_seed_phrase: str = None,
|
24
|
+
encrypt_by_default: Optional[bool] = None,
|
25
|
+
encryption_key: Optional[bytes] = None,
|
26
|
+
):
|
27
|
+
"""
|
28
|
+
Initialize the Hippius client.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
ipfs_gateway: IPFS gateway URL for downloading content
|
32
|
+
ipfs_api_url: IPFS API URL for uploading content. Defaults to Hippius relay node.
|
33
|
+
substrate_url: WebSocket URL of the Hippius substrate node
|
34
|
+
substrate_seed_phrase: Seed phrase for Substrate account
|
35
|
+
encrypt_by_default: Whether to encrypt files by default (from .env if None)
|
36
|
+
encryption_key: Encryption key for NaCl secretbox (from .env if None)
|
37
|
+
"""
|
38
|
+
self.ipfs = IPFSClient(
|
39
|
+
gateway=ipfs_gateway,
|
40
|
+
api_url=ipfs_api_url,
|
41
|
+
encrypt_by_default=encrypt_by_default,
|
42
|
+
encryption_key=encryption_key,
|
43
|
+
)
|
44
|
+
|
45
|
+
# Initialize Substrate client
|
46
|
+
try:
|
47
|
+
self.substrate_client = SubstrateClient(
|
48
|
+
url=substrate_url, seed_phrase=substrate_seed_phrase
|
49
|
+
)
|
50
|
+
except Exception as e:
|
51
|
+
print(f"Warning: Could not initialize Substrate client: {e}")
|
52
|
+
self.substrate_client = None
|
53
|
+
|
54
|
+
def upload_file(
|
55
|
+
self, file_path: str, encrypt: Optional[bool] = None
|
56
|
+
) -> Dict[str, Any]:
|
57
|
+
"""
|
58
|
+
Upload a file to IPFS with optional encryption.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
file_path: Path to the file to upload
|
62
|
+
encrypt: Whether to encrypt the file (overrides default)
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
Dict[str, Any]: Dictionary containing file details including:
|
66
|
+
- cid: Content Identifier of the uploaded file
|
67
|
+
- filename: Name of the file
|
68
|
+
- size_bytes: Size of the file in bytes
|
69
|
+
- size_formatted: Human-readable file size
|
70
|
+
- encrypted: Whether the file was encrypted
|
71
|
+
|
72
|
+
Raises:
|
73
|
+
FileNotFoundError: If the file doesn't exist
|
74
|
+
ConnectionError: If no IPFS connection is available
|
75
|
+
ValueError: If encryption is requested but not available
|
76
|
+
"""
|
77
|
+
# Use the enhanced IPFSClient method directly with encryption parameter
|
78
|
+
return self.ipfs.upload_file(file_path, encrypt=encrypt)
|
79
|
+
|
80
|
+
def upload_directory(
|
81
|
+
self, dir_path: str, encrypt: Optional[bool] = None
|
82
|
+
) -> Dict[str, Any]:
|
83
|
+
"""
|
84
|
+
Upload a directory to IPFS with optional encryption.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
dir_path: Path to the directory to upload
|
88
|
+
encrypt: Whether to encrypt files (overrides default)
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
Dict[str, Any]: Dictionary containing directory details including:
|
92
|
+
- cid: Content Identifier of the uploaded directory
|
93
|
+
- dirname: Name of the directory
|
94
|
+
- file_count: Number of files uploaded
|
95
|
+
- total_size_bytes: Total size in bytes
|
96
|
+
- size_formatted: Human-readable total size
|
97
|
+
- encrypted: Whether files were encrypted
|
98
|
+
|
99
|
+
Raises:
|
100
|
+
FileNotFoundError: If the directory doesn't exist
|
101
|
+
ConnectionError: If no IPFS connection is available
|
102
|
+
ValueError: If encryption is requested but not available
|
103
|
+
"""
|
104
|
+
# Use the enhanced IPFSClient method directly with encryption parameter
|
105
|
+
return self.ipfs.upload_directory(dir_path, encrypt=encrypt)
|
106
|
+
|
107
|
+
def download_file(
|
108
|
+
self, cid: str, output_path: str, decrypt: Optional[bool] = None
|
109
|
+
) -> Dict[str, Any]:
|
110
|
+
"""
|
111
|
+
Download a file from IPFS with optional decryption.
|
112
|
+
|
113
|
+
Args:
|
114
|
+
cid: Content Identifier (CID) of the file to download
|
115
|
+
output_path: Path where the downloaded file will be saved
|
116
|
+
decrypt: Whether to decrypt the file (overrides default)
|
117
|
+
|
118
|
+
Returns:
|
119
|
+
Dict[str, Any]: Dictionary containing download details including:
|
120
|
+
- success: Whether the download was successful
|
121
|
+
- output_path: Path where the file was saved
|
122
|
+
- size_bytes: Size of the downloaded file in bytes
|
123
|
+
- size_formatted: Human-readable file size
|
124
|
+
- elapsed_seconds: Time taken for the download
|
125
|
+
- decrypted: Whether the file was decrypted
|
126
|
+
|
127
|
+
Raises:
|
128
|
+
requests.RequestException: If the download fails
|
129
|
+
ValueError: If decryption is requested but fails
|
130
|
+
"""
|
131
|
+
return self.ipfs.download_file(cid, output_path, decrypt=decrypt)
|
132
|
+
|
133
|
+
def cat(
|
134
|
+
self,
|
135
|
+
cid: str,
|
136
|
+
max_display_bytes: int = 1024,
|
137
|
+
format_output: bool = True,
|
138
|
+
decrypt: Optional[bool] = None,
|
139
|
+
) -> Dict[str, Any]:
|
140
|
+
"""
|
141
|
+
Get the content of a file from IPFS with optional decryption.
|
142
|
+
|
143
|
+
Args:
|
144
|
+
cid: Content Identifier (CID) of the file
|
145
|
+
max_display_bytes: Maximum number of bytes to include in the preview
|
146
|
+
format_output: Whether to attempt to decode the content as text
|
147
|
+
decrypt: Whether to decrypt the file (overrides default)
|
148
|
+
|
149
|
+
Returns:
|
150
|
+
Dict[str, Any]: Dictionary containing content details including:
|
151
|
+
- content: Complete binary content of the file
|
152
|
+
- size_bytes: Size of the content in bytes
|
153
|
+
- size_formatted: Human-readable size
|
154
|
+
- is_text: Whether the content seems to be text
|
155
|
+
- text_preview/hex_preview: Preview of the content
|
156
|
+
- decrypted: Whether the file was decrypted
|
157
|
+
"""
|
158
|
+
return self.ipfs.cat(cid, max_display_bytes, format_output, decrypt=decrypt)
|
159
|
+
|
160
|
+
def exists(self, cid: str) -> Dict[str, Any]:
|
161
|
+
"""
|
162
|
+
Check if a CID exists on IPFS.
|
163
|
+
|
164
|
+
Args:
|
165
|
+
cid: Content Identifier (CID) to check
|
166
|
+
|
167
|
+
Returns:
|
168
|
+
Dict[str, Any]: Dictionary containing:
|
169
|
+
- exists: Boolean indicating if the CID exists
|
170
|
+
- cid: The CID that was checked
|
171
|
+
- formatted_cid: Formatted version of the CID
|
172
|
+
- gateway_url: URL to access the content if it exists
|
173
|
+
"""
|
174
|
+
return self.ipfs.exists(cid)
|
175
|
+
|
176
|
+
def pin(self, cid: str) -> Dict[str, Any]:
|
177
|
+
"""
|
178
|
+
Pin a CID to IPFS to keep it available.
|
179
|
+
|
180
|
+
Args:
|
181
|
+
cid: Content Identifier (CID) to pin
|
182
|
+
|
183
|
+
Returns:
|
184
|
+
Dict[str, Any]: Dictionary containing:
|
185
|
+
- success: Boolean indicating if pinning was successful
|
186
|
+
- cid: The CID that was pinned
|
187
|
+
- formatted_cid: Formatted version of the CID
|
188
|
+
- message: Status message
|
189
|
+
"""
|
190
|
+
return self.ipfs.pin(cid)
|
191
|
+
|
192
|
+
def format_cid(self, cid: str) -> str:
|
193
|
+
"""
|
194
|
+
Format a CID for display.
|
195
|
+
|
196
|
+
This is a convenience method that delegates to the IPFSClient.
|
197
|
+
|
198
|
+
Args:
|
199
|
+
cid: Content Identifier (CID) to format
|
200
|
+
|
201
|
+
Returns:
|
202
|
+
str: Formatted CID string
|
203
|
+
"""
|
204
|
+
return self.ipfs.format_cid(cid)
|
205
|
+
|
206
|
+
def format_size(self, size_bytes: int) -> str:
|
207
|
+
"""
|
208
|
+
Format a size in bytes to a human-readable string.
|
209
|
+
|
210
|
+
This is a convenience method that delegates to the IPFSClient.
|
211
|
+
|
212
|
+
Args:
|
213
|
+
size_bytes: Size in bytes
|
214
|
+
|
215
|
+
Returns:
|
216
|
+
str: Human-readable size string (e.g., '1.23 MB', '456.78 KB')
|
217
|
+
"""
|
218
|
+
return self.ipfs.format_size(size_bytes)
|
219
|
+
|
220
|
+
def generate_encryption_key(self) -> str:
|
221
|
+
"""
|
222
|
+
Generate a new random encryption key for use with the SDK.
|
223
|
+
|
224
|
+
Returns:
|
225
|
+
str: Base64-encoded encryption key ready for use in .env file
|
226
|
+
or directly as the encryption_key parameter (after base64 decoding).
|
227
|
+
|
228
|
+
Raises:
|
229
|
+
ImportError: If PyNaCl is not installed
|
230
|
+
"""
|
231
|
+
try:
|
232
|
+
import nacl.utils
|
233
|
+
import nacl.secret
|
234
|
+
import base64
|
235
|
+
|
236
|
+
# Generate a random key
|
237
|
+
key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)
|
238
|
+
|
239
|
+
# Encode to base64 for storage in .env
|
240
|
+
encoded_key = base64.b64encode(key).decode()
|
241
|
+
|
242
|
+
return encoded_key
|
243
|
+
except ImportError:
|
244
|
+
raise ImportError(
|
245
|
+
"PyNaCl is required for encryption. Install it with: pip install pynacl"
|
246
|
+
)
|