edsu-storage-basic.js

Introduction

StorageBasic wraps a connection to an Edsu server, and provides some higher-level functionality on top of it. It's designed to make things simple if all you want to do is store some bytes and retrieve it later.

new StorageBasic(username, token, name, opts, cbs)

StorageBasic is a class, so it needs to be created with the new keyword. It needs the username of the account where you would like to store/retrieve your data, as well as an owner token with sufficient privileges: i.e. name-get and destructive name-put on the name specified in the next argument.

On the first put, the name provided will be changed to point to a name block with a key that, in turn, points to a meta block. Put another way: StorageBasic stores data via a key, and that key is stored in a named block. You can use any name that you have permissions for, and whichever keys that you like, provided that they are valid keys, and as many as will fit into a single block (around about a thousand, depending on the key character lengths).

The opts is an object with one optional property: idleTriggerS. This is how long the underlying Edsu connection is idle before it is "idled" (dropped and only resumed when there's something to do). If left undefined, a reasonable default will be used. If there is an active subscription, it won't ever be idled.

The cbs (short for callbacks) argument is an object with one (non-optional) property: err. This is called if the connection runs into an error, it is essentially a passthrough of any error that it gets from the underlying Edsu connection, with the same errors and meanings.

Once you create a StorageBasic object, you can then use it to store and retreive data based on keys.

Permissions

generateGrantRequest(name, label, explanation)

This is a static method on the StorageBasic class, which is used in conjunction with edsu-grant.js. It will generate an object suitable to be passed to the edsuGrantRequest() function, as the request argument.

The name parameter is the same name which you plan to use to in the StorageBasic constructor, the label and explanation parameters are what will end up in the grant requests, as described in the edsu- grant.js documentation.

Storing and Retrieving

put(key, bytes, opts)

This method will store the bytes in the second argument, which will then be retrieveable using the key given in the first. The bytes argument must be a Uint8Array, which can be of any size; the key is any string which is a valid ESON key.

The opts argument is either undefined (i.e. omitted from the call), or an object with three optional properties: timeoutMs, noRetry, and maxMergeAttempts. The first two have the same meanings and behaviours as in the namePut() method on the underlying Edsu connection. However, note that the timeout is per operation - their can be many individual name-put operations involved, and the timeout is for each of them, not across the entire operation.

It might be the case that you will go to update a key with new bytes and the name has changed since it was last accessed. If this happens, the code will see if the data pointed to by the key has changed. If not, it will merge the updated key and attempt to put the name again. The maxMergeAttempts property of opts will set the maximum times this will be attempted - if omitted the default of 16 is used.

This method returns a promise, which will resolve to the object { ok: true }, or reject with an error passed through from the underlying namePut() calls.

clobber(key, bytes, opts)

This is the same as the put() method above, except that if the underlying name has been changed since it was last accessed, it will merge the new key regardless of whether that key has changed since it was last seen. The arguments are the same as put() with the exception that the opts argument has the property maxClobberAttempts instead of maxMergeAttempts, with essentially the same meaning.

get(key, opts, cbs)

This method returns the bytes stored via a previous put() or clobber() call at the same key.

The cbs argument can be either undefined, or an object with a single optional property: progress. This is a callback which will be called as events occur during the retreiving of the bytes. It will be called with a single argument, an object with at least the property type, which will be one of 'head-downloaded' or 'block-downloaded'.

head-downloaded If the type of the progress callback argument object is 'head-downloaded', the object might also contain one or both of two additional properties: size and contentsSize. The former is the total size of all the blocks which contain the bytes (including headers), i.e. the amount of bytes that will be transferred, excluding that of any metablocks used. The latter is the total size of the contents of each of those blocks, i.e. the size of the Uint8Array that will eventually be returned from this method. Note that both size and contentsSize are advisory - simply what is recorded in the head block, and so are unverified by this library.
block-downloaded After every (non-metablock) block is retrieved, the progress callback is called with this type. The in addition to the type propery, the object argument will also contain the property block which is the block that has been downloaded. Note that even if the blocks are downloaded out of order, this callback will occur in order, i.e. if you assemble the contents of each block passed in this parameter sequentially, you will have an identical Uint8Array to what is returned at the end of the get() method call.

If a call to the progress callback returns the object with a property cancel that evaluates to "true", the retrieval will be cancelled and the get() call will resolve with { ok: true, cancelled: true } as the argument.

The opts argument can be either undefined, or an object containing one or more of the properties: stream, maxConcurrentGets, timeoutMs, noRetry. The latter two are passed directly to all underlying blockGet() calls, with the same caveats about timeoutMs as with the put() (i.e. it's applied to each individual operation, not to the call as a whole).

The stream property, if interpreted as "true", will cause this method to not return a Uint8Array when it resolves. This is used in conjunction with the progress callback if you only want the data as it comes in, rather than at the end.

This library pipelines the block-get requests in an effort to reduce pauses between block retrievals. The maxConcurrentGets controls how many will be in the pipeline at any one time. The usefulness of this value is related to cancellation - pipelined gets will proceed after the cancellation, potentially wasting bandwidth. If this is omitted, the default of 8 is used.

getJson(key)
putJson(key, obj)
clobberJson(key, obj)

These methods are convenience wrappers over get(), put(), and clobber() respectively. They simply decode or encode the arguments to/from JSON before proceeding, using all the defaults of each call.

Subscriptions

subPut(key, opts, cbs)
subDel(key)
subsClear()
subsList()

These methods manage what are essentially Edsu subscriptions on keys. Under the hood, there's a single actual Edsu subscription on the entire name, and then when that changes the notification is routed to the appropriate callback based on whether the key has changed.

The subPut() method creates a new subscription, or replaces an existing one of the same key. opts should be an empty object, and cbs should be an object with the property notify, which is the method that is called when a change occurs. It will be called with a single argument: an object with the property key, matching the key which given in the subPut() call.

The subDel(), subsClear(), and subsList() methods manage the subs created by subPut() - deleting a single one, deleting all of them, and listing the subscribed keys, respectively.