Skip to content

Commit aa015ee

Browse files
committed
WIP: Generic arweave capability
1 parent 2ad5ee9 commit aa015ee

File tree

4 files changed

+31
-178
lines changed

4 files changed

+31
-178
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ name = "arweave-api"
1919
#
2020
dynamic = ["version"]
2121

22-
description = "Arkly Arweave API"
22+
description = "NOT Arkly Arweave API"
2323
readme = "README.md"
2424

2525
# Supported python versions. Optional, but helpful.

src/arweave_api/api.py

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,15 @@
1111

1212
try:
1313
import primary_functions
14-
from middleware import _update_db
1514
from models import Tags
1615
from version import get_version
1716
except ModuleNotFoundError:
1817
try:
1918
from src.arweave_api import primary_functions
20-
from src.arweave_api.middleware import _update_db
2119
from src.arweave_api.models import Tags
2220
from src.arweave_api.version import get_version
2321
except ModuleNotFoundError:
2422
from arweave_api import primary_functions
25-
from arweave_api.middleware import _update_db
2623
from arweave_api.models import Tags
2724
from arweave_api.version import get_version
2825

@@ -33,7 +30,7 @@
3330
TAG_ARWEAVE: Final[str] = "arweave"
3431
TAG_ARWEAVE_WALLET: Final[str] = "arweave wallet"
3532
TAG_ARWEAVE_SEARCH: Final[str] = "arweave search"
36-
TAG_ARKLY: Final[str] = "arkly"
33+
TAG_ARKLY: Final[str] = "packaging"
3734
TAG_MAINTAIN: Final[str] = "maintenance"
3835

3936
# Metadata for each of the tags in the OpenAPI specification. To order
@@ -53,12 +50,12 @@
5350
},
5451
{
5552
"name": TAG_ARKLY,
56-
"description": "Arkly functions on-top of Arweave",
53+
"description": " functions on-top of Arweave",
5754
},
5855
]
5956

6057
app = FastAPI(
61-
title="api.arkly.io",
58+
title="arweave API",
6259
description=API_DESCRIPTION,
6360
version=get_version(),
6461
contact={
@@ -77,14 +74,6 @@
7774
)
7875

7976

80-
@app.middleware("http")
81-
async def update_db(request: Request, call_next):
82-
"""Middleware used to identify which endpoint is being used so that
83-
the database can be updated effectively.
84-
"""
85-
return await _update_db(request, call_next)
86-
87-
8877
@app.get("/", include_in_schema=False)
8978
def redirect_root_to_docs():
9079
"""Redirect a user calling the API root '/' to the API
@@ -198,25 +187,19 @@ async def get_transactions_by_tag_pair(name: str, value: str):
198187
@app.post("/create_transaction/", tags=[TAG_ARKLY])
199188
async def create_transaction(
200189
wallet: UploadFile,
201-
package_file_name: str,
202-
files: List[UploadFile] = File(...),
190+
file: list[UploadFile] = File(...),
191+
mime_type: str = None,
203192
tags: Tags | None = None,
204193
):
205194
"""Create an Arkly package and Arweave transaction."""
206195
return await primary_functions._create_transaction(
207-
wallet, files, package_file_name, tags
196+
wallet=wallet,
197+
files=file,
198+
mime_type=mime_type,
199+
tags=tags,
208200
)
209201

210202

211-
@app.get("/validate_arkly_bag/", tags=[TAG_ARKLY])
212-
async def validate_bag(transaction_id: str, response: Response):
213-
"""Given an Arweave transaction ID, Validate an Arkly link as a bag.
214-
215-
Example Tx: `rYa3ILXqWi_V52xPoG70y2EupPsTtu4MsMmz6DI4fy4`
216-
"""
217-
return await primary_functions._validate_bag(transaction_id, response)
218-
219-
220203
@app.get("/get_version/", tags=[TAG_MAINTAIN])
221204
async def get_version_info():
222205
"""Return API version information to the caller."""

src/arweave_api/middleware.py

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,41 +11,3 @@
1111
from fastapi import Request
1212

1313
logger = logging.getLogger(__name__)
14-
15-
16-
async def _update_db(request: Request, call_next: Callable):
17-
"""Update the database by one per endpoint called."""
18-
path = str(request.scope["path"])
19-
endpoints = [
20-
"/docs",
21-
"/check_balance/",
22-
"/check_last_transaction/",
23-
"/check_transaction_status",
24-
"/create_transaction/",
25-
"/estimate_traansaction_cost",
26-
"/fetch_upload/",
27-
"/validate_arweave_bag/",
28-
]
29-
# Update database endpoint_calls by 1
30-
if path in endpoints:
31-
if path == "/docs":
32-
path = "root"
33-
else:
34-
# Remove first and last character
35-
path = path[1:-1]
36-
try:
37-
connection = psycopg2.connect(
38-
user="arkly", host="/var/run/postgresql/", database="arkly", port=5432
39-
)
40-
cursor = connection.cursor()
41-
update_endpoint_count = """UPDATE endpoint_calls
42-
SET {update_db_endpoint} = {update_db_endpoint} + 1""".format(
43-
update_db_endpoint=path
44-
)
45-
cursor.execute(update_endpoint_count)
46-
connection.commit()
47-
cursor.close()
48-
except psycopg2.DatabaseError as error:
49-
logger.warning("Postgres may not be configured correctly: %s", error)
50-
response = await call_next(request)
51-
return response

src/arweave_api/primary_functions.py

Lines changed: 21 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
from typing import Final, List
2727

2828
import arweave
29-
import bagit
3029
import humanize
3130
import requests
3231
from arweave.arweave_lib import Transaction, arql
@@ -322,55 +321,10 @@ async def _fetch_upload(transaction_id: str) -> FileResponse:
322321
raise HTTPException from err
323322

324323

325-
async def bag_files(path: Path, tag_list=None) -> None:
326-
"""Use python Bagit to bag the files for Arkly-Arweave."""
327-
if not tag_list:
328-
bagit.make_bag(path, {PACKAGING_AGENT_STRING: ARKLY_AGENT})
329-
return
330-
bag_info = {}
331-
for tag in tag_list:
332-
bag_info[f"{tag.name}".replace(" ", "-")] = tag.value
333-
bag_info[PACKAGING_AGENT_STRING] = ARKLY_AGENT
334-
logger.info("writing package with bag-info: %d", bag_info)
335-
bagit.make_bag(path, bag_info)
336-
return
337-
338-
339-
async def _package_content(
340-
files: List[UploadFile] = File(...), package_name: str = None, tag_list: list = None
341-
) -> dict:
342-
"""Package the files submitted to the create_transaction endpoint."""
343-
# Create a folder for the user's wallet.
344-
tmp_dir = tempfile.mkdtemp()
345-
file_path = Path(tmp_dir, package_name)
346-
file_path.mkdir()
347-
348-
logger.info("Location to write object to: %s", file_path)
349-
350-
for file in files:
351-
read_file = await file.read()
352-
output_file = Path(file_path, file.filename)
353-
output_file.write_bytes(read_file)
354-
355-
# Bag these files.
356-
await bag_files(file_path, tag_list)
357-
358-
# Create compressed .tar.gz file
359-
tar_file_name = file_path.with_suffix(".tar.gz")
360-
with tarfile.open(tar_file_name, "w:gz") as tar:
361-
tar.add(file_path, arcname=os.path.basename(file_path))
362-
363-
version_api: Final[str] = "v0"
364-
tar_file_name = tar_file_name.rename(
365-
f"{tar_file_name}".replace(".tar.gz", f"_{version_api}.tar.gz")
366-
)
367-
return tar_file_name
368-
369-
370324
async def _create_transaction(
371325
wallet: UploadFile,
372-
files: List[UploadFile] = File(...),
373-
package_file_name: str = None,
326+
files: list[UploadFile] = File(...),
327+
mime_type: str = None,
374328
tags: Tags = None,
375329
) -> dict:
376330
"""Create an Arkly package and Arweave transaction.
@@ -398,21 +352,29 @@ async def _create_transaction(
398352
except AttributeError:
399353
logger.info("no user-defined tags provided by caller")
400354

401-
# Create a package from files array. Package content will create
402-
# this in a secure temporary directory.
403-
tar_file_name = await _package_content(files, package_file_name, tag_list)
404-
405-
logger.info("Adding version to package: %s", tar_file_name)
406-
logger.info("New path exists: %s", tar_file_name.is_file())
407355
logger.info("Wallet balance before upload: %s", wallet.balance)
408356

409-
with open(tar_file_name, "rb", buffering=0) as file_handler:
357+
tmp_dir = tempfile.mkdtemp()
358+
file_path = Path(tmp_dir, "upload_path")
359+
file_path.mkdir()
360+
361+
logger.info("Location to write object to: %s", file_path)
362+
363+
output_file = None
364+
for file in files:
365+
read_file = await file.read()
366+
output_file = Path(file_path, file.filename)
367+
output_file.write_bytes(read_file)
368+
break
369+
370+
logger.info("attempting to upload: %s", output_file)
371+
372+
with open(output_file, "rb", buffering=0) as file_handler:
410373
new_transaction = Transaction(
411-
wallet, file_handler=file_handler, file_path=tar_file_name
374+
wallet, file_handler=file_handler, file_path=output_file,
412375
)
413376
# Default tags for the tar/gzip file that we create.
414-
new_transaction.add_tag("Content-Type", "application/gzip")
415-
377+
new_transaction.add_tag("Content-Type", mime_type)
416378
for tag in tag_list:
417379
logger.info("Adding tag: %s: %s", tag.name, tag.value)
418380
new_transaction.add_tag(tag.name, tag.value)
@@ -445,60 +407,6 @@ def _get_arweave_urls_from_tx(transaction_id: str) -> dict:
445407
)
446408

447409

448-
async def _validate_bag(transaction_id: str, response: Response) -> dict:
449-
"""Given an Arweave transaction ID, Validate an Arkly link as a bag."""
450-
451-
# Setup retrieval of the data from the given transaction.
452-
transaction_url, arweave_url = _get_arweave_urls_from_tx(transaction_id)
453-
arweave_response = requests.get(arweave_url, allow_redirects=True)
454-
455-
# Create temp file to extract the contents from Arweave to.
456-
tmp_file_handle, tmp_file_path = tempfile.mkstemp()
457-
with open(tmp_file_handle, "wb") as write_tar_gz:
458-
write_tar_gz.write(arweave_response.content)
459-
460-
tmp_dir = tempfile.mkdtemp()
461-
try:
462-
arkly_gzip = tarfile.open(tmp_file_path)
463-
arkly_gzip.extractall(tmp_dir)
464-
except tarfile.ReadError:
465-
response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
466-
return {
467-
"transaction_url": transaction_url,
468-
"file_url": arweave_url,
469-
"valid": "UNKNOWN",
470-
}
471-
472-
try:
473-
bag_name = os.listdir(tmp_dir)[0]
474-
bag_file = Path(tmp_dir) / bag_name
475-
except IndexError:
476-
response.status_code = status.HTTP_404_NOT_FOUND
477-
return {
478-
"transaction_url": transaction_url,
479-
"file_url": arweave_url,
480-
"valid": "UNKNOWN",
481-
}
482-
483-
# Create bag object and validate, and return information from it.
484-
try:
485-
arkly_bag = bagit.Bag(str(bag_file))
486-
return {
487-
"transaction_url": transaction_url,
488-
"file_url": arweave_url,
489-
"valid": f"{arkly_bag.validate()}",
490-
"bag_info": arkly_bag.info,
491-
"bag_name": bag_name,
492-
}
493-
except bagit.BagError:
494-
response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
495-
return {
496-
"transaction_url": transaction_url,
497-
"file_url": arweave_url,
498-
"valid": "UNKNOWN",
499-
}
500-
501-
502410
async def _all_transactions(wallet_addr: str):
503411
"""Retrieve all transactions from a given wallet and return a human
504412
friendly link to enable users to view the transaction.
@@ -537,4 +445,4 @@ async def _retrieve_by_tag_pair(name: str, value: str) -> dict:
537445

538446
async def _get_version_info() -> dict:
539447
"""Return information about the versions used by this API."""
540-
return {"api": get_version(), "agent": ARKLY_AGENT, "bagit": bagit.VERSION}
448+
return {"api": get_version()}

0 commit comments

Comments
 (0)