Skip to content

Consistent SDK Experience #673

@n8mgr

Description

@n8mgr

This is a cross-repo issue about unifying the usage of our SDKs across languages. Importantly, we should still follow idiomatic patterns in the target languages, but the concepts and exposed types should be similar and behave as consistently as possible.

There are effectively three different SDKs at this point with varying degrees of compatibility.

  • indexd_ffi (python, swift, kotlin, react native)
  • indexd (rust)
  • sdk (Go)

As an example of indexd_ffi in Python

### Setup SDK
app_id = b'\x01' * 32 # Example app ID to separate app storage while using the same mnemonic
mnemonic = generate_recovery_phrase()
# An AppKey is a struct with a private `PrivateKey` field. It enforces consistent generation and keeps the private key inaccessible to the developer
app_key = AppKey(mnemonic, app_id)
sdk = Sdk("https://app.sia.storage", app_key)

### Connection
if not await sdk.connected(): # kind of lame that these are all on the SDK type. Should reconsider a "builder" type.
    print("App not connected")
    resp = await sdk.request_app_connection(AppMeta(
        name="python example",
        description= "an example app",
        service_url= "https://example.com",
        logo_url=None,
        callback_url=None,
    ))
    print(f"Please approve connection {resp.response_url}")
    connected = await sdk.wait_for_connect(resp)
    if not connected:
        fatal("user rejected connection")

print("Connected to indexd")

### Upload
with open("hello.txt", "rb") as f:
    # pinned_obj has no public fields, and only exposes some
    # helpers to prevent corruption of the internal state
    # - id() -> str
    # - metadata() -> bytes
    # - size() -> u64
    # - slabs() -> [Slab]
    # - seal(app_key) -> SealedObject
    # - update_metdata([]byte)
    # - updated_at() -> datetime
    pinned_obj = await sdk.upload(f, UploadOptions(
        max_inflight=15,
        data_shards=10,
        parity_shards=20,
        metadata=json.dumps({"example": "value"}).encode(),
        progress_callback=None,
    ))
    print(f"Uploaded with ID: {pinned_obj.id()}")

### Update Object Metadata
pinned_obj.update_metadata(json.dumps({"example": "new value"}).encode())
await sdk.save_object(pinned_obj)

### Event Syncing
# returns [ObjectEvent] which has three fields:
# - object: PinnedObject
# - deleted: bool
# - timestamp: datetime
object_events = await sdk.objects(ObjectsCursor(
    after=datetime.now(timezone.utc) - timedelta(minutes=10),
    key=pinned_obj.id(),
), 100)

### Download
with open("hello_downloaded.txt", "wb") as f:
    await sdk.download(pinned_obj, f, DownloadOptions(
        max_inflight=10,
        offset=0,
        length=None,
        progress_callback=None,
    ))

sealed = pinned_obj.seal(app_key) # now safe to persist

### Sharing
share_link = sdk.share_object(pinned_obj, datetime.now()+timedelta(days=1)) # make a shareable link valid for 1 day
# Importantly, a SharedObject cannot be converted to a SealedObject and
# similar to PinnedObject has no public fields, only helper methods:
# - size() -> u64
# - metadata() -> bytes
shared_obj = await sdk.shared_object(share_link) # get object metadata from share link

await sdk.pin_shared(shared_obj) # pin shared object to this app's storage

# Download the object
with open("hello_downloaded_shared.txt", "wb") as f:
    await sdk.download_shared(shared_obj, f, DownloadOptions(
        max_inflight=10,
        offset=0,
        length=None,
        progress_callback=None,
    ))

Other than just API semantics, logic is also important. Off the top of my head:
-[ ] Uploads and downloads in indexd_ffi will never fail (helps on spotty mobile connections). They will keep retrying until success or the user aborts. Go will error after exhausting its host candidates once.

First task is identifying the patterns we want to keep and what we want to change. Second task is actually implementing them across the SDKs.

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions