Iceblock SDK

What the core does

Everything here is Built and released, as of v0.71.0 (library 0.9.0), unless it says otherwise. The names are the Rust API: an app could use it directly today, but it’s large, and it changes every release, which is what the facade is for.

Two objects

  • Core (iceblock-core) is one device: its keys, its store, the network’s metadata, and every operation. It has no clock and no sockets of its own: time is passed in, and connections are dialled by a closure. That’s what lets the simulator run many devices in one test.
  • Node (iceblock-node) runs a Core on real networks: it listens (TCP and QUIC on one port), finds devices nearby (mDNS), asks the router for a port forward, keeps up with a relay, and runs replication rounds on a schedule and soon after each change. Node::on_core runs a closure on the core, waiting for a round that holds it to reach a pause rather than blocking.

A host gives the node a Host, which the node asks when a device wants to join (approve), and tells when a nearby device invites this one (invited).

Starting

WhatAPI
Open a device in a data directory, making its keys and a network of its own the first timeCore::open(dir, owner_name)
The same, with keys in another keystore (Android’s, an in-memory one for tests)Core::open_with_keystore
Serve it: listen, discover, syncNode::start(core, port, host), Node::start_configured
Look at a stopped device without changing itCore::open_read_only
What kind of device it is (phone, laptop, server)Core::set_own_kind

On Android, keys are files in the app’s private storage, readable only by the app. On Linux, files under the data directory, readable only by their owner.

Files

Paths are as Iceblock’s Files shows them: the network’s own Collection at the top, and other top-level Collections under @<id>/.

WhatAPI
Add, or change (a new version)add_file, add_file_from (streamed from a file on disk), update_file, update_file_from
Readread_file, read_file_to (streamed), read_range (a byte range, fetching only the blocks it’s in), read_version
Listlist_files, get_file, browse(collection), browse_folders
Move and renamemove_file, move_path (a folder with all in it)
Delete to the trash, restoredelete_file, restore_from_trash, restore_version
Folderscreate_folder, delete_folder
Redundancy per file or Collectionset_level, set_collection_level
Is it all here, or does it need fetchingwhole_here, missing_blocks; Node’s fetch reads from whichever device has it

Every file is encrypted with a key of its own, split into blocks, erasure-coded into shards and spread across the devices; every change is a new version, and old ones are kept for a while. When two devices change a file before they sync, the latest edit becomes the file, and the other is kept as a Conflict copy until the user resolves it.

Comments and reactions on files exist too (comments.rs, reactions.rs), with each comment signed by its writer.

Collections

WhatAPI
Listcollections, top_level_collections
Make, rename, deletecreate_collection(name), rename_collection, delete_collection
Turn a folder into a Collection, link one insplit, link, unlink

A Collection is the unit of sharing, scope and keys: an app device is given whole Collections, and each such Collection has a key chain of its own.

The network’s devices

WhatAPI
Invite one of the network’s own devices: a link and QR codeNode::invite
Join a network with such a link (a fresh device)Core::join
Join, bringing this device’s own network along (it has files)Core::merge_into
Find devices nearby that could join, and invite oneNode::joinable_nearby, Node::invite_nearby
Answer a device asking to join: the trust it gets, or noHost::approve, or answer_join_ask on another of the network’s devices
Trust, scope, presenceset_trust, set_scope, set_presence
Remove a device, re-key the networkremove_device, rekey, rekey_lowering

Trust levels: Full (everything, the network’s keys too), Scoped, for apps (only the Collections in its scope), Metadata-only (sees names and structure, holds encrypted copies, can’t read files), Storage (holds encrypted copies, sees nothing) and Zero.

Groups: sharing with other people

WhatAPI
Make a group, this network its home and Ownercreate_group(name)
Make a Collection of the group’s, or give it one of this network’snew_group_collection_in, give_to_group
Invite: a link, for anyone or one network, approval optionalinvite_to_group(group, role, …)
Join with an invitationjoin_group
Keep up with the group’s rostersync_group (rounds do it)
Roles, removing, leavingset_group_role, set_group_collection_role, remove_from_group, leave_group
Hand the home to another memberhand_group_over, take_group_home
Lend storage to the groupgroup_storage.rs
Owners’ proposals: a Collection out of the grouppropose_group_change, answered by every Owner

Only a Full-trust device can take part in groups (can_group).

Shares and other networks

WhatAPI
Share a file, folder or Collection: a link, with a mode, approval, an expiryNode::share, create_share
Open a share, keep it, pull it up to dateopen_share, keep_received_share, pull_share
Revoke, move recipients to another sharerevoke_share, move_share
Give a whole Collection to another network or a groupoffer_collection, give_to_group
This network’s card, for another to share with itnetwork_card

Share modes: Direct (viewed live from the owner, never stored), One-way (a read-only copy that follows the owner’s), Two-way (both add to it), Gift (copied once, then the recipient’s own) and Roles (held together, each network with a role, as a group’s Collections are).

Apps (Scoped devices)

WhatAPI
Pair as an app: the user picks “an app” when it asks to joinpairing, with the trust Scoped
Adopt an app’s own network: its files carried in, the app Scopedpairing, the approver pulling the app’s network
Ask for a Collection, take the request backrequest_scope, withdraw_scope_request
On the user’s devices: requests, approve, deny once or always, offer, denialsscope_requests, approve_scope_request, deny_scope_request, offer_scope, scope_denials, undeny_scope
What this device is and holdsown_trust, collection_documents

Watching

WhatAPI
Anything saved here: a count that movesCore::saves()
Syncing: whether, and a count that moves when it starts or stopsNode::syncing, Node::sync_changes
Sync now, or one Collection soonNode::sync_now, Node::sync_collection
Notices for the user (a device missing, something at risk, a request)notifications, dismiss_notification

Core::saves() says that something changed, not what. The change feed says what: Core::feed_point(collection) is where a watch starts, and Core::changed_since(collection, point) gives each path whose file changed since, with its record now (or none, if it’s gone), from the documents’ own history, looking at nothing else; or None, to look at the Collection whole, when its Links or hidden Collections changed. The facade’s watch is built on it. Built, in r89 (#766).

Conditions the host passes in

The core can’t always see these, so the host says: on a VPN, on a metered connection or mobile data, on power, battery saver, the default gateway (Core::set_conditions, set_on_vpn). On a metered connection the device doesn’t sync until the user allows it.

Size

Built What an app doesn’t need is left out of iceblock-sdk. Image decoding is the thumbnail worker’s alone (a feature of iceblock-derive, decode, that only the worker turns on); FUSE mounting is a feature of iceblock-node (mount), off for the facade; and an app never runs a relay for its network (set_member_relay(false)). Port mapping stays: it’s how other devices reach the app.