From 8d88e1d59ced0e573e364283b1b75f4e46048aba Mon Sep 17 00:00:00 2001 From: d4v1d03 Date: Thu, 13 Feb 2025 06:04:17 +0530 Subject: [PATCH 01/13] dag_to_car working Signed-off-by: d4v1d03 --- packages/w3up-python-client/.gitignore | 3 ++ packages/w3up-python-client/README.md | 0 packages/w3up-python-client/config.py | 0 packages/w3up-python-client/dag_to_car.py | 40 ++++++++++++++++++++ packages/w3up-python-client/myfile.txt | 1 + packages/w3up-python-client/requirements.txt | 2 + packages/w3up-python-client/setup.py | 27 +++++++++++++ 7 files changed, 73 insertions(+) create mode 100644 packages/w3up-python-client/.gitignore create mode 100644 packages/w3up-python-client/README.md create mode 100644 packages/w3up-python-client/config.py create mode 100644 packages/w3up-python-client/dag_to_car.py create mode 100644 packages/w3up-python-client/myfile.txt create mode 100644 packages/w3up-python-client/requirements.txt create mode 100644 packages/w3up-python-client/setup.py diff --git a/packages/w3up-python-client/.gitignore b/packages/w3up-python-client/.gitignore new file mode 100644 index 000000000..be4b7a503 --- /dev/null +++ b/packages/w3up-python-client/.gitignore @@ -0,0 +1,3 @@ +.env +*.car +/dag_to_car.egg-info \ No newline at end of file diff --git a/packages/w3up-python-client/README.md b/packages/w3up-python-client/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/w3up-python-client/config.py b/packages/w3up-python-client/config.py new file mode 100644 index 000000000..e69de29bb diff --git a/packages/w3up-python-client/dag_to_car.py b/packages/w3up-python-client/dag_to_car.py new file mode 100644 index 000000000..fc41de138 --- /dev/null +++ b/packages/w3up-python-client/dag_to_car.py @@ -0,0 +1,40 @@ +import subprocess +import sys +import os + +def run_command(command): + try: + result = subprocess.run(command, shell=True, check=True, text=True, capture_output=True) + return result.stdout.strip() + except subprocess.CalledProcessError as e: + print(f"āŒ Error: {e.stderr}") + sys.exit(1) + + +def create_dag_and_car(file_path): + if not os.path.exists(file_path): + print(f"āŒ Error: File '{file_path}' not found.") + sys.exit(1) + + print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") + + # Add file to IPFS DAG and get CID + cid = run_command(f"ipfs add --cid-version=1 --raw-leaves --quieter {file_path}") + print(f"āœ… File added to DAG. CID: {cid}") + + car_file = f"{file_path}.car" + print(f"šŸ“¦ Exporting DAG to CAR file: {car_file}...") + run_command(f"ipfs dag export {cid} > {car_file}") + print(f"āœ… CAR file created: {car_file}") + + return cid, car_file + + +# Main script execution +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python dag_to_car.py ") + sys.exit(1) + + file_path = sys.argv[1] + cid, car_file = create_dag_and_car(file_path) \ No newline at end of file diff --git a/packages/w3up-python-client/myfile.txt b/packages/w3up-python-client/myfile.txt new file mode 100644 index 000000000..911f61af0 --- /dev/null +++ b/packages/w3up-python-client/myfile.txt @@ -0,0 +1 @@ +Test conversion to car file \ No newline at end of file diff --git a/packages/w3up-python-client/requirements.txt b/packages/w3up-python-client/requirements.txt new file mode 100644 index 000000000..d44fe4434 --- /dev/null +++ b/packages/w3up-python-client/requirements.txt @@ -0,0 +1,2 @@ +requests +python-dotenv \ No newline at end of file diff --git a/packages/w3up-python-client/setup.py b/packages/w3up-python-client/setup.py new file mode 100644 index 000000000..28e9917d0 --- /dev/null +++ b/packages/w3up-python-client/setup.py @@ -0,0 +1,27 @@ +from setuptools import setup, find_packages + +setup( + name="dag_to_car", + version="0.1.0", + packages=find_packages(), + install_requires=[ + "requests", + "python-dotenv", + ], + entry_points={ + "console_scripts": [ + "dag-to-car=dag_to_car:main", + ], + }, + author="Amit Pandey", + author_email="a_pandey1@ce.iitr.ac.in", + description="A tool to automate IPFS DAG creation and CAR file generation.", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + python_requires=">=3.6", +) From b243aee99498d029c24e1f89a35e38b3c54704ac Mon Sep 17 00:00:00 2001 From: Amit Pandey <95427130+d4v1d03@users.noreply.github.com> Date: Sun, 16 Feb 2025 10:09:54 +0530 Subject: [PATCH 02/13] "w3cli used" --- packages/w3up-python-client/config.py | 2 + packages/w3up-python-client/dag_to_car.py | 77 +++++++++++++++++--- packages/w3up-python-client/requirements.txt | 2 +- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/packages/w3up-python-client/config.py b/packages/w3up-python-client/config.py index e69de29bb..50ff41a2f 100644 --- a/packages/w3up-python-client/config.py +++ b/packages/w3up-python-client/config.py @@ -0,0 +1,2 @@ +STORACHA_API_URL = "https://w3s.link/api/upload" +SPACE_NAME = "MyStorachaSpace" diff --git a/packages/w3up-python-client/dag_to_car.py b/packages/w3up-python-client/dag_to_car.py index fc41de138..88c001c03 100644 --- a/packages/w3up-python-client/dag_to_car.py +++ b/packages/w3up-python-client/dag_to_car.py @@ -1,6 +1,9 @@ import subprocess import sys import os +import json +import requests +from config import SPACE_NAME def run_command(command): try: @@ -10,31 +13,87 @@ def run_command(command): print(f"āŒ Error: {e.stderr}") sys.exit(1) - def create_dag_and_car(file_path): if not os.path.exists(file_path): print(f"āŒ Error: File '{file_path}' not found.") sys.exit(1) - + print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") - # Add file to IPFS DAG and get CID cid = run_command(f"ipfs add --cid-version=1 --raw-leaves --quieter {file_path}") print(f"āœ… File added to DAG. CID: {cid}") - + car_file = f"{file_path}.car" print(f"šŸ“¦ Exporting DAG to CAR file: {car_file}...") run_command(f"ipfs dag export {cid} > {car_file}") print(f"āœ… CAR file created: {car_file}") - + return cid, car_file +try: + space_data = json.loads(space_output) + space_did = space_data.get("did", "Unknown DID") + print(f"āœ… Space created successfully. DID: {space_did}") +except json.JSONDecodeError: + print(f"āœ… Space created. CLI Output: {space_output}") + space_did = space_output.strip() + + +def create_delegation(): + print("šŸ”‘ Creating delegation...") + delegation = run_command("w3 delegation create") + print("āœ… Delegation created.") + return delegation + +def get_http_auth(): + print("šŸ” Retrieving HTTP authentication details...") + auth_json = run_command("w3 bridge generate-tokens") + auth_data = json.loads(auth_json) + return auth_data["X-Auth-Secret"], auth_data["Authorization"] + +def upload_car_file(car_file, x_auth_secret, authorization): + print(f"šŸ“¤ Uploading CAR file: {car_file} to Storacha HTTP bridge...") + + # Define the URL endpoint for upload + upload_url = "https://w3s.link/api/upload" + headers = { + "X-Auth-Secret": x_auth_secret, + "Authorization": authorization, + "Content-Type": "application/car" + } + + with open(car_file, 'rb') as file: + response = requests.post(upload_url, headers=headers, files={"file": file}) + + if response.status_code == 200: + receipt = response.json() + print("āœ… Upload successful! Client Receipt:") + print(json.dumps(receipt, indent=4)) + return receipt + else: + print(f"āŒ Upload failed: {response.text}") + sys.exit(1) -# Main script execution +# Main execution if __name__ == "__main__": if len(sys.argv) < 2: - print("Usage: python dag_to_car.py ") + print("Usage: python storacha_upload.py ") sys.exit(1) - + file_path = sys.argv[1] - cid, car_file = create_dag_and_car(file_path) \ No newline at end of file + space_name = "MyStorachaSpace" + + cid, car_file = create_dag_and_car(file_path) + + space_did = create_w3_space(space_name) + create_delegation() + + x_auth_secret, authorization = get_http_auth() + + client_receipt = upload_car_file(car_file, x_auth_secret, authorization) + + #Client receipt + receipt_file = "client_receipt.json" + with open(receipt_file, "w") as f: + json.dump(client_receipt, f, indent=4) + print(f"šŸ“œ Client receipt saved to {receipt_file}") diff --git a/packages/w3up-python-client/requirements.txt b/packages/w3up-python-client/requirements.txt index d44fe4434..df7458c25 100644 --- a/packages/w3up-python-client/requirements.txt +++ b/packages/w3up-python-client/requirements.txt @@ -1,2 +1,2 @@ requests -python-dotenv \ No newline at end of file +python-dotenv From 42f972cb7d40551e9811918d2160f34ee384bcdc Mon Sep 17 00:00:00 2001 From: Amit Pandey <95427130+d4v1d03@users.noreply.github.com> Date: Mon, 24 Feb 2025 04:05:03 +0530 Subject: [PATCH 03/13] added the use of http bridge --- packages/w3up-python-client/.gitignore | 3 +- packages/w3up-python-client/README.md | 4 + packages/w3up-python-client/dag_to_car.py | 75 +-------- packages/w3up-python-client/setup.py | 24 ++- .../storacha_http_bridge.py | 153 ++++++++++++++++++ 5 files changed, 184 insertions(+), 75 deletions(-) create mode 100644 packages/w3up-python-client/storacha_http_bridge.py diff --git a/packages/w3up-python-client/.gitignore b/packages/w3up-python-client/.gitignore index be4b7a503..1821834d2 100644 --- a/packages/w3up-python-client/.gitignore +++ b/packages/w3up-python-client/.gitignore @@ -1,3 +1,4 @@ .env *.car -/dag_to_car.egg-info \ No newline at end of file +/dag_to_car.egg-info +/myenv \ No newline at end of file diff --git a/packages/w3up-python-client/README.md b/packages/w3up-python-client/README.md index e69de29bb..043794f78 100644 --- a/packages/w3up-python-client/README.md +++ b/packages/w3up-python-client/README.md @@ -0,0 +1,4 @@ +## Installation Requirements +Before using this script, install `w3cli` globally: +```sh +npm install -g @web3-storage/w3 diff --git a/packages/w3up-python-client/dag_to_car.py b/packages/w3up-python-client/dag_to_car.py index 88c001c03..c209b63b8 100644 --- a/packages/w3up-python-client/dag_to_car.py +++ b/packages/w3up-python-client/dag_to_car.py @@ -1,9 +1,7 @@ import subprocess import sys import os -import json -import requests -from config import SPACE_NAME + def run_command(command): try: @@ -17,83 +15,22 @@ def create_dag_and_car(file_path): if not os.path.exists(file_path): print(f"āŒ Error: File '{file_path}' not found.") sys.exit(1) - + print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") - cid = run_command(f"ipfs add --cid-version=1 --raw-leaves --quieter {file_path}") print(f"āœ… File added to DAG. CID: {cid}") - + car_file = f"{file_path}.car" print(f"šŸ“¦ Exporting DAG to CAR file: {car_file}...") run_command(f"ipfs dag export {cid} > {car_file}") print(f"āœ… CAR file created: {car_file}") - - return cid, car_file - -try: - space_data = json.loads(space_output) - space_did = space_data.get("did", "Unknown DID") - print(f"āœ… Space created successfully. DID: {space_did}") -except json.JSONDecodeError: - print(f"āœ… Space created. CLI Output: {space_output}") - space_did = space_output.strip() - -def create_delegation(): - print("šŸ”‘ Creating delegation...") - delegation = run_command("w3 delegation create") - print("āœ… Delegation created.") - return delegation - -def get_http_auth(): - print("šŸ” Retrieving HTTP authentication details...") - auth_json = run_command("w3 bridge generate-tokens") - auth_data = json.loads(auth_json) - return auth_data["X-Auth-Secret"], auth_data["Authorization"] - -def upload_car_file(car_file, x_auth_secret, authorization): - print(f"šŸ“¤ Uploading CAR file: {car_file} to Storacha HTTP bridge...") - - # Define the URL endpoint for upload - upload_url = "https://w3s.link/api/upload" - headers = { - "X-Auth-Secret": x_auth_secret, - "Authorization": authorization, - "Content-Type": "application/car" - } - - with open(car_file, 'rb') as file: - response = requests.post(upload_url, headers=headers, files={"file": file}) - - if response.status_code == 200: - receipt = response.json() - print("āœ… Upload successful! Client Receipt:") - print(json.dumps(receipt, indent=4)) - return receipt - else: - print(f"āŒ Upload failed: {response.text}") - sys.exit(1) + return cid, car_file -# Main execution if __name__ == "__main__": if len(sys.argv) < 2: - print("Usage: python storacha_upload.py ") + print("Usage: python dag_to_car.py ") sys.exit(1) - + file_path = sys.argv[1] - space_name = "MyStorachaSpace" - cid, car_file = create_dag_and_car(file_path) - - space_did = create_w3_space(space_name) - create_delegation() - - x_auth_secret, authorization = get_http_auth() - - client_receipt = upload_car_file(car_file, x_auth_secret, authorization) - - #Client receipt - receipt_file = "client_receipt.json" - with open(receipt_file, "w") as f: - json.dump(client_receipt, f, indent=4) - print(f"šŸ“œ Client receipt saved to {receipt_file}") diff --git a/packages/w3up-python-client/setup.py b/packages/w3up-python-client/setup.py index 28e9917d0..1c50f79ef 100644 --- a/packages/w3up-python-client/setup.py +++ b/packages/w3up-python-client/setup.py @@ -1,21 +1,35 @@ +import subprocess +import sys from setuptools import setup, find_packages +def check_w3cli(): + """Check if w3cli is installed, otherwise prompt installation.""" + try: + subprocess.run(["w3", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print("āœ… w3cli is already installed.") + except FileNotFoundError: + print("āŒ w3cli not found. Please install it using:\n npm install -g @web3-storage/w3") + sys.exit(1) + +check_w3cli() + setup( - name="dag_to_car", + name="dag_to_car", version="0.1.0", packages=find_packages(), install_requires=[ - "requests", - "python-dotenv", + "requests", + "python-dotenv", ], entry_points={ "console_scripts": [ - "dag-to-car=dag_to_car:main", + "dag-to-car=dag_to_car:main", + "storacha-http-bridge=storacha_http_bridge:main", # Add entry point for storacha_http_bridge.py ], }, author="Amit Pandey", author_email="a_pandey1@ce.iitr.ac.in", - description="A tool to automate IPFS DAG creation and CAR file generation.", + description="A tool to automate IPFS DAG creation, CAR file generation, and Web3 Storage upload.", long_description=open("README.md").read(), long_description_content_type="text/markdown", classifiers=[ diff --git a/packages/w3up-python-client/storacha_http_bridge.py b/packages/w3up-python-client/storacha_http_bridge.py new file mode 100644 index 000000000..df7fa3fcd --- /dev/null +++ b/packages/w3up-python-client/storacha_http_bridge.py @@ -0,0 +1,153 @@ +import os +import subprocess +import requests +import tempfile +import platform +from dotenv import load_dotenv + +load_dotenv() +space_name = os.getenv("SPACE_NAME") +file_path = os.getenv("FILE_PATH") +https_endpoint = os.getenv("HTTPS_ENDPOINT", "https://up.storacha.network/bridge") + +class StorachaClient: + def __init__(self, https_endpoint="https://up.storacha.network/bridge"): + self.https_endpoint = https_endpoint + self.tokens = {} + self.spaces = {} + + def run_command(self, command): + try: + result = subprocess.check_output(command, shell=True, text=True).strip() + return result + except subprocess.CalledProcessError as e: + print(f"āŒ Error: {e.stderr}") + return None + + def space_ls(self): + if platform.system() == "Windows": + space_ls_cmd = "npx w3 space ls" + else: + space_ls_cmd = "w3 space ls" + spaces = {} + try: + results = subprocess.check_output(space_ls_cmd, shell=True) + results = results.decode("utf-8").strip() + results = results.split("\n") + results = [i.replace("\n", "").replace("* ", "") for i in results] + spaces = [i.split(" ") for i in results] + spaces = {i[1]: i[0] for i in spaces} + self.spaces = spaces + except subprocess.CalledProcessError as e: + print("space_ls failed") + import traceback + error = e + error += traceback.format_exc() + print(error) + return ValueError(error) + + return spaces + + def generate_tokens(self, space, permissions=None): + if permissions is None: + permissions = ["--can upload/add", "--can store/add"] + command = f"w3 bridge generate-tokens {space} " + " ".join(permissions) + result = self.run_command(command) + if result: + lines = result.split('\n') + auth_secret = lines[0].split(': ')[1] + authorization = lines[1].split(': ')[1] + self.tokens[space] = { + "X-Auth-Secret header": auth_secret, + "Authorization header": authorization + } + return self.tokens[space] + return None + + def upload_add_https(self, space, file, file_root, shards=None): + if space not in self.tokens: + print(f"āŒ Error: No tokens found for space '{space}'.") + return None + + auth_secret = self.tokens[space]["X-Auth-Secret header"] + authorization = self.tokens[space]["Authorization header"] + method = "upload/add" + + with tempfile.NamedTemporaryFile(suffix=".car", delete=False) as temp: + car_filename = temp.name + if platform.system() == "Windows": + ipfs_car_cmd = f"npx ipfs-car pack {file} --output {car_filename}" + else: + ipfs_car_cmd = f"ipfs-car pack {file} --output {car_filename}" + + try: + ipfs_car_cmd_results = subprocess.run( + ipfs_car_cmd, shell=True, check=True, + stderr=subprocess.PIPE, stdout=subprocess.PIPE + ) + ipfs_car_cmd_output = ipfs_car_cmd_results.stdout.decode("utf-8").strip() + cid = ipfs_car_cmd_output.split('\n')[-1] + except subprocess.CalledProcessError as e: + print(f"āŒ ipfs-car failed: {e.stderr.decode('utf-8')}") + return None + + filename = file.replace(file_root, "").replace("\\", "/") + + if cid: + data = { + "tasks": [ + [ + "upload/add", + space, + { + "root": {"/": cid}, + "shards": shards or [] + } + ] + ] + } + + headers = { + "X-Auth-Secret": auth_secret, + "Authorization": authorization, + "Content-Type": "application/json" + } + + with open(car_filename, 'rb') as car_file: + response = requests.post( + self.https_endpoint, + headers=headers, + data=car_file + ) + + if response.status_code == 200: + return response.json() + else: + print(f"āŒ Upload failed with status code {response.status_code}: {response.text}") + return None + else: + print("āŒ Error: CID not generated.") + return None + +if __name__ == "__main__": + storacha = StorachaClient() + + # List existing spaces + spaces = storacha.space_ls() + if not spaces: + print("āŒ No spaces found.") + exit(1) + + # Generate tokens for the space + space_did = list(spaces.keys())[0] # Selecting the first available space + tokens = storacha.generate_tokens(space_did) + if not tokens: + print("āŒ Failed to generate tokens.") + exit(1) + + # Upload file using upload_add_https + response = storacha.upload_add_https(space_did, file_path, os.path.dirname(file_path)) + if response: + print("āœ… Upload successful:", response) + else: + print("āŒ Upload failed.") From 9d978d91b441eecc65308ff938146d5999fbe022 Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Fri, 28 Feb 2025 17:39:55 +0530 Subject: [PATCH 04/13] test Signed-off-by: Amit Pandey --- packages/w3up-python-client/storacha_http_bridge.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/w3up-python-client/storacha_http_bridge.py b/packages/w3up-python-client/storacha_http_bridge.py index df7fa3fcd..19aa812fd 100644 --- a/packages/w3up-python-client/storacha_http_bridge.py +++ b/packages/w3up-python-client/storacha_http_bridge.py @@ -146,8 +146,8 @@ def upload_add_https(self, space, file, file_root, shards=None): exit(1) # Upload file using upload_add_https - response = storacha.upload_add_https(space_did, file_path, os.path.dirname(file_path)) - if response: - print("āœ… Upload successful:", response) + result = storacha.upload_add_https(space_did, file_path, os.path.dirname(file_path)) + if result: + print(f"āœ… Successfully uploaded file to space. Details: {result}") else: - print("āŒ Upload failed.") + print("āŒ Failed to upload file to space") From 859b057dbbd5e1c7136897069f413e0bf9d71164 Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Sat, 1 Mar 2025 10:04:45 +0530 Subject: [PATCH 05/13] level-1 done Signed-off-by: Amit Pandey --- packages/w3up-python-client/.gitignore | 3 +- packages/w3up-python-client/dag_to_car.py | 1 - packages/w3up-python-client/list.json | 9 + packages/w3up-python-client/requirements.txt | 1 + .../w3up-python-client/storacha_uploader.py | 162 ++++++++++++++++++ 5 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 packages/w3up-python-client/list.json create mode 100644 packages/w3up-python-client/storacha_uploader.py diff --git a/packages/w3up-python-client/.gitignore b/packages/w3up-python-client/.gitignore index 1821834d2..97ec07ed4 100644 --- a/packages/w3up-python-client/.gitignore +++ b/packages/w3up-python-client/.gitignore @@ -1,4 +1,5 @@ .env *.car /dag_to_car.egg-info -/myenv \ No newline at end of file +/myenv +curl.py \ No newline at end of file diff --git a/packages/w3up-python-client/dag_to_car.py b/packages/w3up-python-client/dag_to_car.py index c209b63b8..c52b022b4 100644 --- a/packages/w3up-python-client/dag_to_car.py +++ b/packages/w3up-python-client/dag_to_car.py @@ -2,7 +2,6 @@ import sys import os - def run_command(command): try: result = subprocess.run(command, shell=True, check=True, text=True, capture_output=True) diff --git a/packages/w3up-python-client/list.json b/packages/w3up-python-client/list.json new file mode 100644 index 000000000..69ccc1801 --- /dev/null +++ b/packages/w3up-python-client/list.json @@ -0,0 +1,9 @@ +{ + "tasks": [ + [ + "upload/list", + "did:key:z6MksbhMHBFohHmhhDNkLVSRr9FgSJRU4rHrP74ggr2EiRt7", + {} + ] + ] + } \ No newline at end of file diff --git a/packages/w3up-python-client/requirements.txt b/packages/w3up-python-client/requirements.txt index df7458c25..d8394219b 100644 --- a/packages/w3up-python-client/requirements.txt +++ b/packages/w3up-python-client/requirements.txt @@ -1,2 +1,3 @@ requests python-dotenv +ipfs-car \ No newline at end of file diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py new file mode 100644 index 000000000..7ffef1d8e --- /dev/null +++ b/packages/w3up-python-client/storacha_uploader.py @@ -0,0 +1,162 @@ +import os +import sys +import json +import subprocess +import requests +import tempfile +import platform +from dotenv import load_dotenv + +def run_command(command): + """Run a shell command and return the output.""" + try: + result = subprocess.check_output(command, shell=True, text=True).strip() + return result + except subprocess.CalledProcessError as e: + print(f"āŒ Error: {e}") + return None + +def create_dag_and_car(file_path): + """ + Create a DAG and CAR file from the input file. + Returns the CID and path to the CAR file. + """ + if not os.path.exists(file_path): + print(f"āŒ Error: File '{file_path}' not found.") + sys.exit(1) + + print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") + + # Use ipfs-car to create the CAR file + car_file = f"{file_path}.car" + + if platform.system() == "Windows": + ipfs_car_cmd = f"npx ipfs-car pack {file_path} --output {car_file}" + else: + ipfs_car_cmd = f"ipfs-car pack {file_path} --output {car_file}" + + try: + ipfs_car_cmd_results = subprocess.run( + ipfs_car_cmd, shell=True, check=True, + stderr=subprocess.PIPE, stdout=subprocess.PIPE + ) + ipfs_car_cmd_output = ipfs_car_cmd_results.stdout.decode("utf-8").strip() + cid = ipfs_car_cmd_output.split('\n')[-1] + print(f"āœ… CAR file created: {car_file}") + print(f"āœ… CID: {cid}") + return cid, car_file + except subprocess.CalledProcessError as e: + print(f"āŒ ipfs-car failed: {e.stderr.decode('utf-8')}") + sys.exit(1) + +def create_upload_json(cid, space_did): + """Create the JSON payload for the upload/add operation.""" + # Format the space_did as a proper DID URI if it's not already + if not space_did.startswith("did:"): + space_did = f"did:key:{space_did}" + + data = { + "tasks": [ + [ + "upload/add", + space_did, + { + "root": {"/": cid}, + "shards": [] + } + ] + ] + } + + # Create a temporary JSON file + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as temp: + json.dump(data, temp, indent=2) + temp_json_path = temp.name + + return temp_json_path + +def upload_to_storacha(json_file): + """Upload to Storacha using the HTTP Bridge.""" + # Load environment variables + load_dotenv() + + # Use the correct environment variable names from your .env file + auth_secret = os.getenv("X-AUTH-SECRET-HEADER") + authorization = os.getenv("AUTHORIZATION-HEADER") + endpoint = os.getenv("HTTPS-ENDPOINT", "https://up.storacha.network/bridge") + + # Validate required parameters + if not auth_secret: + raise ValueError("X-Auth-Secret is required in .env file as X-AUTH-SECRET-HEADER") + if not authorization: + raise ValueError("Authorization is required in .env file as AUTHORIZATION-HEADER") + + headers = { + "X-Auth-Secret": auth_secret, + "Authorization": authorization, + "Content-Type": "application/json" + } + + # Read the JSON file + with open(json_file, 'r') as f: + data = f.read() + + # Send the POST request + print(f"šŸ“¤ Uploading to Storacha HTTP Bridge...") + response = requests.post( + endpoint, + headers=headers, + data=data + ) + + # Check if the request was successful + if response.status_code == 200: + print("āœ… Upload successful!") + return response.json() + else: + print(f"āŒ Upload failed with status code {response.status_code}: {response.text}") + return None + +def main(): + # Check if a file path is provided + if len(sys.argv) < 2: + print("āŒ Error: Please provide a file path to upload.") + print("Usage: python storacha_uploader.py ") + sys.exit(1) + + file_path = sys.argv[1] + + # Load environment variables + load_dotenv() + + # Get the SPACE_DID from the .env file + space_did = os.getenv("SPACE_DID") + + if not space_did: + print("āŒ Error: SPACE_DID not found in .env file.") + print("Please add SPACE_DID=your_space_did to your .env file.") + sys.exit(1) + + print(f"šŸ”‘ Using Space DID: {space_did}") + + # Step 1: Create DAG and CAR file + cid, car_file = create_dag_and_car(file_path) + + # Step 2: Create the JSON payload + json_file = create_upload_json(cid, space_did) + + # Step 3: Upload to Storacha + result = upload_to_storacha(json_file) + + # Clean up temporary JSON file + os.unlink(json_file) + + if result: + print(f"āœ… File uploaded successfully to Storacha network.") + print(f"āœ… Access your file at: https://{cid}.ipfs.w3s.link") + print(f"āœ… Response details: {json.dumps(result, indent=2)}") + else: + print("āŒ Upload failed.") + +if __name__ == "__main__": + main() From 3bb1338d947dfac3f845ad5d296944e69e2a1e3a Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Sat, 1 Mar 2025 10:40:09 +0530 Subject: [PATCH 06/13] clean code and readme added Signed-off-by: Amit Pandey --- packages/w3up-python-client/.gitignore | 3 +- packages/w3up-python-client/README.md | 31 +++++++-- packages/w3up-python-client/config.py | 2 - packages/w3up-python-client/dag_to_car.py | 35 ---------- packages/w3up-python-client/package.json | 8 +++ packages/w3up-python-client/requirements.txt | 2 +- packages/w3up-python-client/setup.py | 66 +++++++++++++++---- .../storacha_http_bridge.py | 3 +- .../w3up-python-client/storacha_uploader.py | 21 ------ 9 files changed, 93 insertions(+), 78 deletions(-) delete mode 100644 packages/w3up-python-client/config.py delete mode 100644 packages/w3up-python-client/dag_to_car.py create mode 100644 packages/w3up-python-client/package.json diff --git a/packages/w3up-python-client/.gitignore b/packages/w3up-python-client/.gitignore index 97ec07ed4..d0f07c0d5 100644 --- a/packages/w3up-python-client/.gitignore +++ b/packages/w3up-python-client/.gitignore @@ -1,5 +1,4 @@ .env *.car -/dag_to_car.egg-info +/storacha_uploader.egg-info /myenv -curl.py \ No newline at end of file diff --git a/packages/w3up-python-client/README.md b/packages/w3up-python-client/README.md index 043794f78..45abe0073 100644 --- a/packages/w3up-python-client/README.md +++ b/packages/w3up-python-client/README.md @@ -1,4 +1,27 @@ -## Installation Requirements -Before using this script, install `w3cli` globally: -```sh -npm install -g @web3-storage/w3 +# Storacha Uploader + +A tool to create CAR files and upload content to Storacha decentralized storage. + +## Install + +```bash +# Requires Python 3.6+, Node.js and npm +pip install . +``` + +## Configure + +Create a `.env` file with your credentials: +``` +X-AUTH-SECRET-HEADER=your_auth_secret +AUTHORIZATION-HEADER=your_authorization +SPACE_DID=your_space_did +``` + +## Usage + +```bash +storacha-uploader myfile.txt +``` + +This converts the file to CAR format, uploads it to Storacha, and provides an access link. diff --git a/packages/w3up-python-client/config.py b/packages/w3up-python-client/config.py deleted file mode 100644 index 50ff41a2f..000000000 --- a/packages/w3up-python-client/config.py +++ /dev/null @@ -1,2 +0,0 @@ -STORACHA_API_URL = "https://w3s.link/api/upload" -SPACE_NAME = "MyStorachaSpace" diff --git a/packages/w3up-python-client/dag_to_car.py b/packages/w3up-python-client/dag_to_car.py deleted file mode 100644 index c52b022b4..000000000 --- a/packages/w3up-python-client/dag_to_car.py +++ /dev/null @@ -1,35 +0,0 @@ -import subprocess -import sys -import os - -def run_command(command): - try: - result = subprocess.run(command, shell=True, check=True, text=True, capture_output=True) - return result.stdout.strip() - except subprocess.CalledProcessError as e: - print(f"āŒ Error: {e.stderr}") - sys.exit(1) - -def create_dag_and_car(file_path): - if not os.path.exists(file_path): - print(f"āŒ Error: File '{file_path}' not found.") - sys.exit(1) - - print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") - cid = run_command(f"ipfs add --cid-version=1 --raw-leaves --quieter {file_path}") - print(f"āœ… File added to DAG. CID: {cid}") - - car_file = f"{file_path}.car" - print(f"šŸ“¦ Exporting DAG to CAR file: {car_file}...") - run_command(f"ipfs dag export {cid} > {car_file}") - print(f"āœ… CAR file created: {car_file}") - - return cid, car_file - -if __name__ == "__main__": - if len(sys.argv) < 2: - print("Usage: python dag_to_car.py ") - sys.exit(1) - - file_path = sys.argv[1] - cid, car_file = create_dag_and_car(file_path) diff --git a/packages/w3up-python-client/package.json b/packages/w3up-python-client/package.json new file mode 100644 index 000000000..e06d7d8ff --- /dev/null +++ b/packages/w3up-python-client/package.json @@ -0,0 +1,8 @@ +{ + "name": "storacha-uploader", + "version": "1.0.0", + "description": "Tool for uploading files to Storacha network", + "dependencies": { + "ipfs-car": "^0.9.1" + } +} \ No newline at end of file diff --git a/packages/w3up-python-client/requirements.txt b/packages/w3up-python-client/requirements.txt index d8394219b..c46ba2516 100644 --- a/packages/w3up-python-client/requirements.txt +++ b/packages/w3up-python-client/requirements.txt @@ -1,3 +1,3 @@ requests python-dotenv -ipfs-car \ No newline at end of file +setuptools \ No newline at end of file diff --git a/packages/w3up-python-client/setup.py b/packages/w3up-python-client/setup.py index 1c50f79ef..5494c5c22 100644 --- a/packages/w3up-python-client/setup.py +++ b/packages/w3up-python-client/setup.py @@ -1,36 +1,74 @@ import subprocess import sys +import platform from setuptools import setup, find_packages +def check_ipfs_car(): + print("šŸ” Checking for ipfs-car...") + try: + if platform.system() == "Windows": + result = subprocess.run("npx ipfs-car --version", shell=True, check=True, capture_output=True) + else: + result = subprocess.run("ipfs-car --version", shell=True, check=True, capture_output=True) + print(f"āœ… ipfs-car is already installed: {result.stdout.decode('utf-8').strip()}") + return True + except subprocess.CalledProcessError: + print("āŒ ipfs-car is not installed.") + print("šŸ“¦ Installing ipfs-car globally...") + try: + subprocess.run("npm install -g ipfs-car", shell=True, check=True) + print("āœ… ipfs-car installed successfully.") + return True + except subprocess.CalledProcessError as e: + print(f"āŒ Failed to install ipfs-car: {e}") + print("Please install it manually with: npm install -g ipfs-car") + return False + def check_w3cli(): - """Check if w3cli is installed, otherwise prompt installation.""" + print("šŸ” Checking for w3cli...") try: subprocess.run(["w3", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print("āœ… w3cli is already installed.") + return True except FileNotFoundError: - print("āŒ w3cli not found. Please install it using:\n npm install -g @web3-storage/w3") - sys.exit(1) + print("āŒ w3cli not found.") + print("šŸ“¦ Installing w3cli globally...") + try: + subprocess.run("npm install -g @web3-storage/w3", shell=True, check=True) + print("āœ… w3cli installed successfully.") + return True + except subprocess.CalledProcessError as e: + print(f"āŒ Failed to install w3cli: {e}") + print("Please install it manually with: npm install -g @web3-storage/w3") + return False + +ipfs_car_installed = check_ipfs_car() +w3cli_installed = check_w3cli() -check_w3cli() +if not ipfs_car_installed or not w3cli_installed: + print("\nāš ļø Some dependencies could not be installed automatically.") + print("Please install them manually before using the package.") + print("- ipfs-car: npm install -g ipfs-car") + print("- w3cli: npm install -g @web3-storage/w3") + print("\nContinuing with Python package installation...\n") + +with open('requirements.txt') as f: + requirements = f.read().splitlines() setup( - name="dag_to_car", + name="storacha_uploader", version="0.1.0", packages=find_packages(), - install_requires=[ - "requests", - "python-dotenv", - ], + install_requires=requirements, entry_points={ "console_scripts": [ - "dag-to-car=dag_to_car:main", - "storacha-http-bridge=storacha_http_bridge:main", # Add entry point for storacha_http_bridge.py + "storacha-uploader=storacha_uploader:main", ], }, author="Amit Pandey", author_email="a_pandey1@ce.iitr.ac.in", description="A tool to automate IPFS DAG creation, CAR file generation, and Web3 Storage upload.", - long_description=open("README.md").read(), + long_description=open("README.md").read() if sys.version_info[0] >= 3 else "", long_description_content_type="text/markdown", classifiers=[ "Programming Language :: Python :: 3", @@ -39,3 +77,7 @@ def check_w3cli(): ], python_requires=">=3.6", ) + +print("\nāœ… Setup completed.") +print("šŸ“ Note: Make sure Node.js and npm are installed on your system.") +print("šŸš€ You can now use the 'storacha-uploader' command to upload files to Storacha network.") diff --git a/packages/w3up-python-client/storacha_http_bridge.py b/packages/w3up-python-client/storacha_http_bridge.py index 19aa812fd..67e4281a5 100644 --- a/packages/w3up-python-client/storacha_http_bridge.py +++ b/packages/w3up-python-client/storacha_http_bridge.py @@ -1,4 +1,4 @@ -import os +"""import os import subprocess import requests import tempfile @@ -151,3 +151,4 @@ def upload_add_https(self, space, file, file_root, shards=None): print(f"āœ… Successfully uploaded file to space. Details: {result}") else: print("āŒ Failed to upload file to space") +""" \ No newline at end of file diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py index 7ffef1d8e..62861a96d 100644 --- a/packages/w3up-python-client/storacha_uploader.py +++ b/packages/w3up-python-client/storacha_uploader.py @@ -8,7 +8,6 @@ from dotenv import load_dotenv def run_command(command): - """Run a shell command and return the output.""" try: result = subprocess.check_output(command, shell=True, text=True).strip() return result @@ -17,17 +16,12 @@ def run_command(command): return None def create_dag_and_car(file_path): - """ - Create a DAG and CAR file from the input file. - Returns the CID and path to the CAR file. - """ if not os.path.exists(file_path): print(f"āŒ Error: File '{file_path}' not found.") sys.exit(1) print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") - # Use ipfs-car to create the CAR file car_file = f"{file_path}.car" if platform.system() == "Windows": @@ -51,7 +45,6 @@ def create_dag_and_car(file_path): def create_upload_json(cid, space_did): """Create the JSON payload for the upload/add operation.""" - # Format the space_did as a proper DID URI if it's not already if not space_did.startswith("did:"): space_did = f"did:key:{space_did}" @@ -68,7 +61,6 @@ def create_upload_json(cid, space_did): ] } - # Create a temporary JSON file with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as temp: json.dump(data, temp, indent=2) temp_json_path = temp.name @@ -77,15 +69,12 @@ def create_upload_json(cid, space_did): def upload_to_storacha(json_file): """Upload to Storacha using the HTTP Bridge.""" - # Load environment variables load_dotenv() - # Use the correct environment variable names from your .env file auth_secret = os.getenv("X-AUTH-SECRET-HEADER") authorization = os.getenv("AUTHORIZATION-HEADER") endpoint = os.getenv("HTTPS-ENDPOINT", "https://up.storacha.network/bridge") - # Validate required parameters if not auth_secret: raise ValueError("X-Auth-Secret is required in .env file as X-AUTH-SECRET-HEADER") if not authorization: @@ -97,11 +86,9 @@ def upload_to_storacha(json_file): "Content-Type": "application/json" } - # Read the JSON file with open(json_file, 'r') as f: data = f.read() - # Send the POST request print(f"šŸ“¤ Uploading to Storacha HTTP Bridge...") response = requests.post( endpoint, @@ -109,7 +96,6 @@ def upload_to_storacha(json_file): data=data ) - # Check if the request was successful if response.status_code == 200: print("āœ… Upload successful!") return response.json() @@ -118,7 +104,6 @@ def upload_to_storacha(json_file): return None def main(): - # Check if a file path is provided if len(sys.argv) < 2: print("āŒ Error: Please provide a file path to upload.") print("Usage: python storacha_uploader.py ") @@ -126,10 +111,8 @@ def main(): file_path = sys.argv[1] - # Load environment variables load_dotenv() - # Get the SPACE_DID from the .env file space_did = os.getenv("SPACE_DID") if not space_did: @@ -139,16 +122,12 @@ def main(): print(f"šŸ”‘ Using Space DID: {space_did}") - # Step 1: Create DAG and CAR file cid, car_file = create_dag_and_car(file_path) - # Step 2: Create the JSON payload json_file = create_upload_json(cid, space_did) - # Step 3: Upload to Storacha result = upload_to_storacha(json_file) - # Clean up temporary JSON file os.unlink(json_file) if result: From 799582cfb01886f73d981c7a9f68a15be6694317 Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Mon, 17 Mar 2025 06:27:27 +0530 Subject: [PATCH 07/13] added all the available instructions in the http bridge Signed-off-by: Amit Pandey --- .../w3up-python-client/storacha_uploader.py | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py index 62861a96d..2054e1ba1 100644 --- a/packages/w3up-python-client/storacha_uploader.py +++ b/packages/w3up-python-client/storacha_uploader.py @@ -21,20 +21,20 @@ def create_dag_and_car(file_path): sys.exit(1) print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") - car_file = f"{file_path}.car" - + if platform.system() == "Windows": ipfs_car_cmd = f"npx ipfs-car pack {file_path} --output {car_file}" else: ipfs_car_cmd = f"ipfs-car pack {file_path} --output {car_file}" - + try: ipfs_car_cmd_results = subprocess.run( ipfs_car_cmd, shell=True, check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE ) ipfs_car_cmd_output = ipfs_car_cmd_results.stdout.decode("utf-8").strip() + # Assume the last line is the CID cid = ipfs_car_cmd_output.split('\n')[-1] print(f"āœ… CAR file created: {car_file}") print(f"āœ… CID: {cid}") @@ -43,26 +43,32 @@ def create_dag_and_car(file_path): print(f"āŒ ipfs-car failed: {e.stderr.decode('utf-8')}") sys.exit(1) -def create_upload_json(cid, space_did): - """Create the JSON payload for the upload/add operation.""" +def create_all_instructions_json(cid, space_did): + + #Placeholders (e.g., , ) are used for parameters + # that require additional values. + if not space_did.startswith("did:"): space_did = f"did:key:{space_did}" - data = { + payload = { "tasks": [ - [ - "upload/add", - space_did, - { - "root": {"/": cid}, - "shards": [] - } - ] + ["access/delegate", space_did, {"delegate": ""}], + ["space/info", space_did], + ["space/allocate", space_did, {"allocation": ""}], + ["store/add", space_did, {"root": {"/": cid}, "shards": []}], + ["store/get", space_did, {"root": {"/": cid}}], + ["store/remove", space_did, {"root": {"/": cid}}], + ["store/list", space_did], + ["upload/add", space_did, {"root": {"/": cid}, "shards": []}], + ["upload/list", space_did, {"root": {"/": cid}, "shards": []}], + ["upload/remove", space_did, {"root": {"/": cid}}], + ["usage/report", space_did] ] } with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as temp: - json.dump(data, temp, indent=2) + json.dump(payload, temp, indent=2) temp_json_path = temp.name return temp_json_path @@ -81,7 +87,7 @@ def upload_to_storacha(json_file): raise ValueError("Authorization is required in .env file as AUTHORIZATION-HEADER") headers = { - "X-Auth-Secret": auth_secret, + "X-AUTH-SECRET": auth_secret, "Authorization": authorization, "Content-Type": "application/json" } @@ -104,6 +110,8 @@ def upload_to_storacha(json_file): return None def main(): + load_dotenv() + if len(sys.argv) < 2: print("āŒ Error: Please provide a file path to upload.") print("Usage: python storacha_uploader.py ") @@ -111,10 +119,7 @@ def main(): file_path = sys.argv[1] - load_dotenv() - space_did = os.getenv("SPACE_DID") - if not space_did: print("āŒ Error: SPACE_DID not found in .env file.") print("Please add SPACE_DID=your_space_did to your .env file.") @@ -124,7 +129,7 @@ def main(): cid, car_file = create_dag_and_car(file_path) - json_file = create_upload_json(cid, space_did) + json_file = create_all_instructions_json(cid, space_did) result = upload_to_storacha(json_file) From 2093ead3a38993a7a8cf27ba15059f1093471f57 Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Thu, 20 Mar 2025 07:53:02 +0530 Subject: [PATCH 08/13] fixes after review Signed-off-by: Amit Pandey --- packages/w3up-python-client/README.md | 69 ++++++++ packages/w3up-python-client/setup.py | 6 +- .../storacha_http_bridge.py | 154 ------------------ .../w3up-python-client/storacha_uploader.py | 59 ++----- 4 files changed, 90 insertions(+), 198 deletions(-) delete mode 100644 packages/w3up-python-client/storacha_http_bridge.py diff --git a/packages/w3up-python-client/README.md b/packages/w3up-python-client/README.md index 45abe0073..9f07d9920 100644 --- a/packages/w3up-python-client/README.md +++ b/packages/w3up-python-client/README.md @@ -25,3 +25,72 @@ storacha-uploader myfile.txt ``` This converts the file to CAR format, uploads it to Storacha, and provides an access link. + + +## Instructions to be used over the http bridge + +Below instructions can be used over the http bridge by adidng them to the list.json file. + +```bash +{ + "tasks": [ + /* + [ + "access/delegate", + "did:key:z6Mkabc123", + { "delegate": "" } + ], + [ + "space/info", + "did:key:z6Mkabc123" + ], + [ + "space/allocate", + "did:key:z6Mkabc123", + { "allocation": "" } + ], + [ + "store/add", + "did:key:z6Mkabc123", + { "root": { "/": "" }, "shards": [] } + ], + [ + "store/get", + "did:key:z6Mkabc123", + { "root": { "/": "" } } + ], + [ + "store/remove", + "did:key:z6Mkabc123", + { "root": { "/": "" } } + ], + [ + "store/list", + "did:key:z6Mkabc123" + ], + */ + [ + "upload/add", + "did:key:z6Mkabc123", + { "root": { "/": "" }, "shards": [] } + ] + /* + , + [ + "upload/list", + "did:key:z6Mkabc123", + {} + ], + [ + "upload/remove", + "did:key:z6Mkabc123", + { "root": { "/": "" } } + ], + [ + "usage/report", + "did:key:z6Mkabc123" + ] + */ + ] +} +``` \ No newline at end of file diff --git a/packages/w3up-python-client/setup.py b/packages/w3up-python-client/setup.py index 5494c5c22..b978e4ae6 100644 --- a/packages/w3up-python-client/setup.py +++ b/packages/w3up-python-client/setup.py @@ -34,12 +34,12 @@ def check_w3cli(): print("āŒ w3cli not found.") print("šŸ“¦ Installing w3cli globally...") try: - subprocess.run("npm install -g @web3-storage/w3", shell=True, check=True) + subprocess.run("npm install -g @web3-storage/w3cli", shell=True, check=True) print("āœ… w3cli installed successfully.") return True except subprocess.CalledProcessError as e: print(f"āŒ Failed to install w3cli: {e}") - print("Please install it manually with: npm install -g @web3-storage/w3") + print("Please install it manually with: npm install -g @web3-storage/w3cli") return False ipfs_car_installed = check_ipfs_car() @@ -49,7 +49,7 @@ def check_w3cli(): print("\nāš ļø Some dependencies could not be installed automatically.") print("Please install them manually before using the package.") print("- ipfs-car: npm install -g ipfs-car") - print("- w3cli: npm install -g @web3-storage/w3") + print("- w3cli: npm install -g @web3-storage/w3cli") print("\nContinuing with Python package installation...\n") with open('requirements.txt') as f: diff --git a/packages/w3up-python-client/storacha_http_bridge.py b/packages/w3up-python-client/storacha_http_bridge.py deleted file mode 100644 index 67e4281a5..000000000 --- a/packages/w3up-python-client/storacha_http_bridge.py +++ /dev/null @@ -1,154 +0,0 @@ -"""import os -import subprocess -import requests -import tempfile -import platform -from dotenv import load_dotenv - -load_dotenv() -space_name = os.getenv("SPACE_NAME") -file_path = os.getenv("FILE_PATH") -https_endpoint = os.getenv("HTTPS_ENDPOINT", "https://up.storacha.network/bridge") - -class StorachaClient: - def __init__(self, https_endpoint="https://up.storacha.network/bridge"): - self.https_endpoint = https_endpoint - self.tokens = {} - self.spaces = {} - - def run_command(self, command): - try: - result = subprocess.check_output(command, shell=True, text=True).strip() - return result - except subprocess.CalledProcessError as e: - print(f"āŒ Error: {e.stderr}") - return None - - def space_ls(self): - if platform.system() == "Windows": - space_ls_cmd = "npx w3 space ls" - else: - space_ls_cmd = "w3 space ls" - spaces = {} - try: - results = subprocess.check_output(space_ls_cmd, shell=True) - results = results.decode("utf-8").strip() - results = results.split("\n") - results = [i.replace("\n", "").replace("* ", "") for i in results] - spaces = [i.split(" ") for i in results] - spaces = {i[1]: i[0] for i in spaces} - self.spaces = spaces - except subprocess.CalledProcessError as e: - print("space_ls failed") - import traceback - error = e - error += traceback.format_exc() - print(error) - return ValueError(error) - - return spaces - - def generate_tokens(self, space, permissions=None): - if permissions is None: - permissions = ["--can upload/add", "--can store/add"] - command = f"w3 bridge generate-tokens {space} " + " ".join(permissions) - result = self.run_command(command) - if result: - lines = result.split('\n') - auth_secret = lines[0].split(': ')[1] - authorization = lines[1].split(': ')[1] - self.tokens[space] = { - "X-Auth-Secret header": auth_secret, - "Authorization header": authorization - } - return self.tokens[space] - return None - - def upload_add_https(self, space, file, file_root, shards=None): - if space not in self.tokens: - print(f"āŒ Error: No tokens found for space '{space}'.") - return None - - auth_secret = self.tokens[space]["X-Auth-Secret header"] - authorization = self.tokens[space]["Authorization header"] - method = "upload/add" - - with tempfile.NamedTemporaryFile(suffix=".car", delete=False) as temp: - car_filename = temp.name - if platform.system() == "Windows": - ipfs_car_cmd = f"npx ipfs-car pack {file} --output {car_filename}" - else: - ipfs_car_cmd = f"ipfs-car pack {file} --output {car_filename}" - - try: - ipfs_car_cmd_results = subprocess.run( - ipfs_car_cmd, shell=True, check=True, - stderr=subprocess.PIPE, stdout=subprocess.PIPE - ) - ipfs_car_cmd_output = ipfs_car_cmd_results.stdout.decode("utf-8").strip() - cid = ipfs_car_cmd_output.split('\n')[-1] - except subprocess.CalledProcessError as e: - print(f"āŒ ipfs-car failed: {e.stderr.decode('utf-8')}") - return None - - filename = file.replace(file_root, "").replace("\\", "/") - - if cid: - data = { - "tasks": [ - [ - "upload/add", - space, - { - "root": {"/": cid}, - "shards": shards or [] - } - ] - ] - } - - headers = { - "X-Auth-Secret": auth_secret, - "Authorization": authorization, - "Content-Type": "application/json" - } - - with open(car_filename, 'rb') as car_file: - response = requests.post( - self.https_endpoint, - headers=headers, - data=car_file - ) - - if response.status_code == 200: - return response.json() - else: - print(f"āŒ Upload failed with status code {response.status_code}: {response.text}") - return None - else: - print("āŒ Error: CID not generated.") - return None - -if __name__ == "__main__": - storacha = StorachaClient() - - # List existing spaces - spaces = storacha.space_ls() - if not spaces: - print("āŒ No spaces found.") - exit(1) - - # Generate tokens for the space - space_did = list(spaces.keys())[0] # Selecting the first available space - tokens = storacha.generate_tokens(space_did) - if not tokens: - print("āŒ Failed to generate tokens.") - exit(1) - - # Upload file using upload_add_https - result = storacha.upload_add_https(space_did, file_path, os.path.dirname(file_path)) - if result: - print(f"āœ… Successfully uploaded file to space. Details: {result}") - else: - print("āŒ Failed to upload file to space") -""" \ No newline at end of file diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py index 2054e1ba1..1322b8581 100644 --- a/packages/w3up-python-client/storacha_uploader.py +++ b/packages/w3up-python-client/storacha_uploader.py @@ -43,37 +43,17 @@ def create_dag_and_car(file_path): print(f"āŒ ipfs-car failed: {e.stderr.decode('utf-8')}") sys.exit(1) -def create_all_instructions_json(cid, space_did): - - #Placeholders (e.g., , ) are used for parameters - # that require additional values. - - if not space_did.startswith("did:"): - space_did = f"did:key:{space_did}" - - payload = { - "tasks": [ - ["access/delegate", space_did, {"delegate": ""}], - ["space/info", space_did], - ["space/allocate", space_did, {"allocation": ""}], - ["store/add", space_did, {"root": {"/": cid}, "shards": []}], - ["store/get", space_did, {"root": {"/": cid}}], - ["store/remove", space_did, {"root": {"/": cid}}], - ["store/list", space_did], - ["upload/add", space_did, {"root": {"/": cid}, "shards": []}], - ["upload/list", space_did, {"root": {"/": cid}, "shards": []}], - ["upload/remove", space_did, {"root": {"/": cid}}], - ["usage/report", space_did] - ] - } - - with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as temp: - json.dump(payload, temp, indent=2) - temp_json_path = temp.name +def read_list_json(): + list_json_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "list.json") + if not os.path.exists(list_json_path): + print("āŒ Error: list.json file not found in the current directory.") + sys.exit(1) - return temp_json_path + with open(list_json_path, 'r') as f: + payload = f.read() + return payload -def upload_to_storacha(json_file): +def upload_to_storacha(json_payload): """Upload to Storacha using the HTTP Bridge.""" load_dotenv() @@ -92,22 +72,21 @@ def upload_to_storacha(json_file): "Content-Type": "application/json" } - with open(json_file, 'r') as f: - data = f.read() print(f"šŸ“¤ Uploading to Storacha HTTP Bridge...") response = requests.post( endpoint, headers=headers, - data=data + data=json_payload ) if response.status_code == 200: - print("āœ… Upload successful!") - return response.json() + print("āœ… Upload successful!") + return response.json() else: - print(f"āŒ Upload failed with status code {response.status_code}: {response.text}") - return None + error_message = f"āŒ Upload failed with status code {response.status_code}: {response.text}" + print(error_message) + raise requests.HTTPError(error_message) def main(): load_dotenv() @@ -129,12 +108,10 @@ def main(): cid, car_file = create_dag_and_car(file_path) - json_file = create_all_instructions_json(cid, space_did) - - result = upload_to_storacha(json_file) - - os.unlink(json_file) + json_payload = read_list_json() + result = upload_to_storacha(json_payload) + if result: print(f"āœ… File uploaded successfully to Storacha network.") print(f"āœ… Access your file at: https://{cid}.ipfs.w3s.link") From d026401ef0e596a567cf556f1c9d487b4465e0ec Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Thu, 20 Mar 2025 08:53:15 +0530 Subject: [PATCH 09/13] "fixes done after review" --- packages/w3up-python-client/list.json | 2 +- packages/w3up-python-client/setup.py | 29 ------- .../w3up-python-client/storacha_uploader.py | 79 ++++++++----------- 3 files changed, 32 insertions(+), 78 deletions(-) diff --git a/packages/w3up-python-client/list.json b/packages/w3up-python-client/list.json index 69ccc1801..927378de5 100644 --- a/packages/w3up-python-client/list.json +++ b/packages/w3up-python-client/list.json @@ -6,4 +6,4 @@ {} ] ] - } \ No newline at end of file + } diff --git a/packages/w3up-python-client/setup.py b/packages/w3up-python-client/setup.py index b978e4ae6..8db997523 100644 --- a/packages/w3up-python-client/setup.py +++ b/packages/w3up-python-client/setup.py @@ -3,27 +3,6 @@ import platform from setuptools import setup, find_packages -def check_ipfs_car(): - print("šŸ” Checking for ipfs-car...") - try: - if platform.system() == "Windows": - result = subprocess.run("npx ipfs-car --version", shell=True, check=True, capture_output=True) - else: - result = subprocess.run("ipfs-car --version", shell=True, check=True, capture_output=True) - print(f"āœ… ipfs-car is already installed: {result.stdout.decode('utf-8').strip()}") - return True - except subprocess.CalledProcessError: - print("āŒ ipfs-car is not installed.") - print("šŸ“¦ Installing ipfs-car globally...") - try: - subprocess.run("npm install -g ipfs-car", shell=True, check=True) - print("āœ… ipfs-car installed successfully.") - return True - except subprocess.CalledProcessError as e: - print(f"āŒ Failed to install ipfs-car: {e}") - print("Please install it manually with: npm install -g ipfs-car") - return False - def check_w3cli(): print("šŸ” Checking for w3cli...") try: @@ -42,16 +21,8 @@ def check_w3cli(): print("Please install it manually with: npm install -g @web3-storage/w3cli") return False -ipfs_car_installed = check_ipfs_car() w3cli_installed = check_w3cli() -if not ipfs_car_installed or not w3cli_installed: - print("\nāš ļø Some dependencies could not be installed automatically.") - print("Please install them manually before using the package.") - print("- ipfs-car: npm install -g ipfs-car") - print("- w3cli: npm install -g @web3-storage/w3cli") - print("\nContinuing with Python package installation...\n") - with open('requirements.txt') as f: requirements = f.read().splitlines() diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py index 1322b8581..8c435effd 100644 --- a/packages/w3up-python-client/storacha_uploader.py +++ b/packages/w3up-python-client/storacha_uploader.py @@ -17,16 +17,10 @@ def run_command(command): def create_dag_and_car(file_path): if not os.path.exists(file_path): - print(f"āŒ Error: File '{file_path}' not found.") - sys.exit(1) + raise FileNotFoundError(f"File '{file_path}' not found.") - print(f"šŸ“‚ Adding '{file_path}' to IPFS DAG...") car_file = f"{file_path}.car" - - if platform.system() == "Windows": - ipfs_car_cmd = f"npx ipfs-car pack {file_path} --output {car_file}" - else: - ipfs_car_cmd = f"ipfs-car pack {file_path} --output {car_file}" + ipfs_car_cmd = f"npx ipfs-car pack {file_path} --output {car_file}" if platform.system() == "Windows" else f"ipfs-car pack {file_path} --output {car_file}" try: ipfs_car_cmd_results = subprocess.run( @@ -34,14 +28,12 @@ def create_dag_and_car(file_path): stderr=subprocess.PIPE, stdout=subprocess.PIPE ) ipfs_car_cmd_output = ipfs_car_cmd_results.stdout.decode("utf-8").strip() - # Assume the last line is the CID cid = ipfs_car_cmd_output.split('\n')[-1] - print(f"āœ… CAR file created: {car_file}") - print(f"āœ… CID: {cid}") return cid, car_file except subprocess.CalledProcessError as e: - print(f"āŒ ipfs-car failed: {e.stderr.decode('utf-8')}") - sys.exit(1) + error_msg = f"ipfs-car failed: {e.stderr.decode('utf-8')}" + raise RuntimeError(error_msg) from e + def read_list_json(): list_json_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "list.json") @@ -53,44 +45,37 @@ def read_list_json(): payload = f.read() return payload -def upload_to_storacha(json_payload): +def upload_to_storacha(json_payload, auth_secret, authorization, endpoint): """Upload to Storacha using the HTTP Bridge.""" - load_dotenv() - - auth_secret = os.getenv("X-AUTH-SECRET-HEADER") - authorization = os.getenv("AUTHORIZATION-HEADER") - endpoint = os.getenv("HTTPS-ENDPOINT", "https://up.storacha.network/bridge") - if not auth_secret: - raise ValueError("X-Auth-Secret is required in .env file as X-AUTH-SECRET-HEADER") + raise ValueError("X-Auth-Secret is required.") if not authorization: - raise ValueError("Authorization is required in .env file as AUTHORIZATION-HEADER") - + raise ValueError("Authorization is required.") + headers = { "X-AUTH-SECRET": auth_secret, "Authorization": authorization, "Content-Type": "application/json" } - - print(f"šŸ“¤ Uploading to Storacha HTTP Bridge...") - response = requests.post( - endpoint, - headers=headers, - data=json_payload - ) + print("šŸ“¤ Uploading to Storacha HTTP Bridge...") + response = requests.post(endpoint, headers=headers, data=json_payload) if response.status_code == 200: - print("āœ… Upload successful!") - return response.json() + print("āœ… Upload successful!") + return response.json() else: - error_message = f"āŒ Upload failed with status code {response.status_code}: {response.text}" - print(error_message) - raise requests.HTTPError(error_message) + error_message = f"āŒ Upload failed with status code {response.status_code}: {response.text}" + print(error_message) + raise requests.HTTPError(error_message) def main(): load_dotenv() + auth_secret = os.getenv("X-AUTH-SECRET-HEADER") + authorization = os.getenv("AUTHORIZATION-HEADER") + endpoint = os.getenv("HTTPS-ENDPOINT", "https://up.storacha.network/bridge") + if len(sys.argv) < 2: print("āŒ Error: Please provide a file path to upload.") print("Usage: python storacha_uploader.py ") @@ -106,18 +91,16 @@ def main(): print(f"šŸ”‘ Using Space DID: {space_did}") - cid, car_file = create_dag_and_car(file_path) - - json_payload = read_list_json() - - result = upload_to_storacha(json_payload) - - if result: - print(f"āœ… File uploaded successfully to Storacha network.") - print(f"āœ… Access your file at: https://{cid}.ipfs.w3s.link") - print(f"āœ… Response details: {json.dumps(result, indent=2)}") - else: - print("āŒ Upload failed.") - + try: + cid, car_file = create_dag_and_car(file_path) + json_payload = read_list_json() + result = upload_to_storacha(json_payload, auth_secret, authorization, endpoint) + print(f"āœ… File uploaded successfully to Storacha network.") + print(f"āœ… Access your file at: https://{cid}.ipfs.w3s.link") + print(f"āœ… Response details: {json.dumps(result, indent=2)}") + + except Exception as e: + print(f"āŒ Error: {e}") + sys.exit(1) if __name__ == "__main__": main() From 6112b9dd5342c1994e117c5aee4598773f8faa69 Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Fri, 21 Mar 2025 07:16:43 +0530 Subject: [PATCH 10/13] all fixes done Signed-off-by: Amit Pandey --- packages/w3up-python-client/README.md | 4 ++-- packages/w3up-python-client/storacha_uploader.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/w3up-python-client/README.md b/packages/w3up-python-client/README.md index 9f07d9920..53a197a74 100644 --- a/packages/w3up-python-client/README.md +++ b/packages/w3up-python-client/README.md @@ -13,8 +13,8 @@ pip install . Create a `.env` file with your credentials: ``` -X-AUTH-SECRET-HEADER=your_auth_secret -AUTHORIZATION-HEADER=your_authorization +X_AUTH_SECRET_HEADER=your_auth_secret +AUTHORIZATION_HEADER=your_authorization SPACE_DID=your_space_did ``` diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py index 8c435effd..9072f6d46 100644 --- a/packages/w3up-python-client/storacha_uploader.py +++ b/packages/w3up-python-client/storacha_uploader.py @@ -72,9 +72,9 @@ def upload_to_storacha(json_payload, auth_secret, authorization, endpoint): def main(): load_dotenv() - auth_secret = os.getenv("X-AUTH-SECRET-HEADER") - authorization = os.getenv("AUTHORIZATION-HEADER") - endpoint = os.getenv("HTTPS-ENDPOINT", "https://up.storacha.network/bridge") + auth_secret = os.getenv("X_AUTH_SECRET_HEADER") + authorization = os.getenv("AUTHORIZATION_HEADER") + endpoint = os.getenv("HTTPS_ENDPOINT", "https://up.storacha.network/bridge") if len(sys.argv) < 2: print("āŒ Error: Please provide a file path to upload.") From a2cbd5976e4207b4f9d54c18cbf0f0f4c0239ad0 Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Tue, 25 Mar 2025 16:25:07 +0530 Subject: [PATCH 11/13] fixes Signed-off-by: Amit Pandey --- packages/w3up-python-client/README.md | 2 +- packages/w3up-python-client/storacha_uploader.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/w3up-python-client/README.md b/packages/w3up-python-client/README.md index 53a197a74..207251c11 100644 --- a/packages/w3up-python-client/README.md +++ b/packages/w3up-python-client/README.md @@ -29,7 +29,7 @@ This converts the file to CAR format, uploads it to Storacha, and provides an ac ## Instructions to be used over the http bridge -Below instructions can be used over the http bridge by adidng them to the list.json file. +Below instructions can be used over the http bridge by adding them to the list.json file. ```bash { diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py index 9072f6d46..1daff587c 100644 --- a/packages/w3up-python-client/storacha_uploader.py +++ b/packages/w3up-python-client/storacha_uploader.py @@ -45,7 +45,7 @@ def read_list_json(): payload = f.read() return payload -def upload_to_storacha(json_payload, auth_secret, authorization, endpoint): +def send_request_to_the_bridge(json_payload, auth_secret, authorization, endpoint): """Upload to Storacha using the HTTP Bridge.""" if not auth_secret: raise ValueError("X-Auth-Secret is required.") @@ -94,7 +94,7 @@ def main(): try: cid, car_file = create_dag_and_car(file_path) json_payload = read_list_json() - result = upload_to_storacha(json_payload, auth_secret, authorization, endpoint) + result = send_request_to_the_bridge(json_payload, auth_secret, authorization, endpoint) print(f"āœ… File uploaded successfully to Storacha network.") print(f"āœ… Access your file at: https://{cid}.ipfs.w3s.link") print(f"āœ… Response details: {json.dumps(result, indent=2)}") From 1c87135c8df0b1fa5ca52d962087648976fa286c Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Thu, 27 Mar 2025 17:32:20 +0530 Subject: [PATCH 12/13] changes according to the feedback given Signed-off-by: Amit Pandey --- packages/w3up-python-client/.gitignore | 2 + packages/w3up-python-client/package.json | 8 -- .../w3up-python-client/storacha_uploader.py | 126 +++++++++++------- 3 files changed, 80 insertions(+), 56 deletions(-) delete mode 100644 packages/w3up-python-client/package.json diff --git a/packages/w3up-python-client/.gitignore b/packages/w3up-python-client/.gitignore index d0f07c0d5..54080ef5f 100644 --- a/packages/w3up-python-client/.gitignore +++ b/packages/w3up-python-client/.gitignore @@ -2,3 +2,5 @@ *.car /storacha_uploader.egg-info /myenv +node_modules + diff --git a/packages/w3up-python-client/package.json b/packages/w3up-python-client/package.json deleted file mode 100644 index e06d7d8ff..000000000 --- a/packages/w3up-python-client/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "storacha-uploader", - "version": "1.0.0", - "description": "Tool for uploading files to Storacha network", - "dependencies": { - "ipfs-car": "^0.9.1" - } -} \ No newline at end of file diff --git a/packages/w3up-python-client/storacha_uploader.py b/packages/w3up-python-client/storacha_uploader.py index 1daff587c..2deacc654 100644 --- a/packages/w3up-python-client/storacha_uploader.py +++ b/packages/w3up-python-client/storacha_uploader.py @@ -15,59 +15,63 @@ def run_command(command): print(f"āŒ Error: {e}") return None -def create_dag_and_car(file_path): - if not os.path.exists(file_path): - raise FileNotFoundError(f"File '{file_path}' not found.") - - car_file = f"{file_path}.car" - ipfs_car_cmd = f"npx ipfs-car pack {file_path} --output {car_file}" if platform.system() == "Windows" else f"ipfs-car pack {file_path} --output {car_file}" - - try: - ipfs_car_cmd_results = subprocess.run( - ipfs_car_cmd, shell=True, check=True, - stderr=subprocess.PIPE, stdout=subprocess.PIPE - ) - ipfs_car_cmd_output = ipfs_car_cmd_results.stdout.decode("utf-8").strip() - cid = ipfs_car_cmd_output.split('\n')[-1] - return cid, car_file - except subprocess.CalledProcessError as e: - error_msg = f"ipfs-car failed: {e.stderr.decode('utf-8')}" - raise RuntimeError(error_msg) from e - - -def read_list_json(): - list_json_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "list.json") - if not os.path.exists(list_json_path): - print("āŒ Error: list.json file not found in the current directory.") - sys.exit(1) - - with open(list_json_path, 'r') as f: - payload = f.read() - return payload - def send_request_to_the_bridge(json_payload, auth_secret, authorization, endpoint): - """Upload to Storacha using the HTTP Bridge.""" - if not auth_secret: - raise ValueError("X-Auth-Secret is required.") - if not authorization: - raise ValueError("Authorization is required.") - headers = { - "X-AUTH-SECRET": auth_secret, + "X_AUTH_SECRET": auth_secret, "Authorization": authorization, "Content-Type": "application/json" } - print("šŸ“¤ Uploading to Storacha HTTP Bridge...") response = requests.post(endpoint, headers=headers, data=json_payload) if response.status_code == 200: - print("āœ… Upload successful!") + response_data = response.json() + upload_url = response_data.get('upload_url') + if not upload_url: + raise ValueError("Upload URL not found in the response.") + return upload_url + else: + raise requests.HTTPError(f"Upload registration failed: {response.status_code} {response.text}") + +def upload_car_file(upload_url, car_file_path): + with open(car_file_path, 'rb') as f: + response = requests.put(upload_url, data=f) + if response.status_code not in [200, 201]: + raise requests.HTTPError(f"CAR file upload failed: {response.status_code} {response.text}") + +def upload_add(cid): + payload = { + "tasks": [ + ["upload/add", "did:key:z6Mkabc123", {"root": {"/": cid}, "shards": []}] + ] + } + return send_request(payload) + + +def upload_list(): + payload = { + "tasks": [ + ["upload/list", "did:key:z6Mkabc123", {}] + ] + } + return send_request(payload) + + +def upload_remove(cid): + payload = { + "tasks": [ + ["upload/remove", "did:key:z6Mkabc123", {"root": {"/": cid}}] + ] + } + return send_request(payload) + + +def send_request(payload,endpoint,headers): + response = requests.post(endpoint, headers=headers, json=payload) + if response.status_code == 200: return response.json() else: - error_message = f"āŒ Upload failed with status code {response.status_code}: {response.text}" - print(error_message) - raise requests.HTTPError(error_message) + raise requests.HTTPError(f"Request failed: {response.status_code} {response.text}") def main(): load_dotenv() @@ -77,9 +81,25 @@ def main(): endpoint = os.getenv("HTTPS_ENDPOINT", "https://up.storacha.network/bridge") if len(sys.argv) < 2: - print("āŒ Error: Please provide a file path to upload.") - print("Usage: python storacha_uploader.py ") - sys.exit(1) + print("āŒ Error: Please provide an operation (upload_add, upload_list, upload_remove) and optional CID.") + print("Usage: python storacha_uploader.py ") + sys.exit(1) + + operation = sys.argv[1] + cid = sys.argv[2] if len(sys.argv) > 2 else None + + operations = { + "upload_add": upload_add, + "upload_list": upload_list, + "upload_remove": upload_remove, + } + + if operation in operations: + result = operations[operation](cid if "list" not in operation else None) + print(json.dumps(result, indent=2)) + else: + print(f"Unknown operation: {operation}") + file_path = sys.argv[1] @@ -91,10 +111,20 @@ def main(): print(f"šŸ”‘ Using Space DID: {space_did}") + car_file = f"{file_path}.car" + ipfs_car_cmd = ["ipfs-car", "pack", file_path, "--output", car_file] + try: - cid, car_file = create_dag_and_car(file_path) - json_payload = read_list_json() - result = send_request_to_the_bridge(json_payload, auth_secret, authorization, endpoint) + result = subprocess.run(ipfs_car_cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cid = result.stdout.decode().strip().split('\n')[-1] + print(f"āœ… CAR file created: {car_file} with CID: {cid}") + except subprocess.CalledProcessError as e: + print(f"āŒ Error creating CAR file: {e.stderr.decode().strip()}") + sys.exit(1) + + upload_url = send_request_to_the_bridge(auth_secret, authorization, endpoint) + upload_car_file(upload_url, car_file) + upload_add(cid) print(f"āœ… File uploaded successfully to Storacha network.") print(f"āœ… Access your file at: https://{cid}.ipfs.w3s.link") print(f"āœ… Response details: {json.dumps(result, indent=2)}") From 14ed8b51623a8dfceb57fe7981b25472bc3d070e Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Thu, 3 Apr 2025 19:00:35 +0530 Subject: [PATCH 13/13] added to package.json Signed-off-by: Amit Pandey --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index b0370354b..20a307b84 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,9 @@ }, "dependencies": { "depcheck": "^1.4.3", - "typedoc-plugin-missing-exports": "^2.1.0" + "typedoc-plugin-missing-exports": "^2.1.0", + "@web3-storage/w3cli": "^3.0.1", + "ipfs-car": "^0.9.1" }, "pnpm": { "peerDependencyRules": {