APIStore

Store

An abstract Condensation store.

The ID is a string unique to the store, often loosely describing it, e.g.:

Object Cache
  Hash Verification Store
    https://condensation.io
  file:///srv/store

However, it should be treated as an opaque string, and not be interpreted or parsed. Two store instances with the same ID are interchangeable.

In the Java implementation, all store requests are non-blocking. You are passing a done handler to the request, and one of its functions will be invoked when the request has been executed.

In the JavaScript implementation, all store requests are non-blocking. The request function returns a done object, and one of its functions will be invoked when the request has been executed.

In the Perl implementation, all store requests are blocking. That means, the function waits until the request has been executed, and returns the result.

Instance creation

Every store implementation provides its own constructors.

Store requests

Get

		store.get(hash, keyPair, done);

		class GetDone implements Store.GetDone {
			public void onGetDone(@NonNull CondensationObject object) { ... }
			public void onGetNotFound() { ... }
			public void onGetFailed(@NonNull String error) { ... }
		}
	
		var done = store.get(hash, keyPair);

		done.onDone = function(object) { ... };
		done.onNotFound = function() { ... };
		done.onFailed = function(error) { ... };
	
		my ($object, $error) = $store->get($hash, $keyPair);

		if (defined $error) {
			# request failed
		} elsif (defined $object) {
			# found
		} else {
			# not found
		}
	

Retrieves the desired object from the store.

Under normal conditions, the received object matches the requested hash. Failure to do so points to data corruption or tampering, and should be treated as an unexpected error that requires investigation by an IT specialist.

Unless specified otherwise, stores do not verify the hash of the retrieved object. Use a hash verification store where this makes sense.

The key pair is used to sign the request in case the store requires authentication. If the request fails, a technical error message is returned.

Put

		store.put(hash, object, keyPair, done);

		class PutDone implements Store.PutDone {
			public void onPutDone() { ... }
			public void onPutFailed(@NonNull String error) { ... }
		}
	
		var done = store.put(hash, object, keyPair);

		done.onDone = function() { ... };
		done.onFailed = function(error) { ... };
	
		my $error = $store->put($hash, $object, $keyPair);

		if (defined $error) {
			# request failed
		} else {
			# done
		}
	

Uploads an object onto the store.

The hash must match the object. The key pair is used to sign the request in case the store requires authentication. If the request fails, a technical error message is returned.

Book

		store.book(hash, keyPair, done);

		class BookDone implements Store.BookDone {
			public void onBookDone() { ... }
			public void onBookNotFound() { ... }
			public void onBookFailed(@NonNull String error) { ... }
		}
	
		var done = store.book(hash, keyPair);

		done.onDone = function() { ... };
		done.onNotFound = function() { ... };
		done.onFailed = function(error) { ... };
	
		my ($booked, $error) = $store->book($hash, $keyPair);

		if (defined $error) {
			# request failed
		} elsif ($booked) {
			# booked
		} else {
			# not found (and therefore not booked)
		}
	

Books the object on the store, and returns whether booking succeeded.

The key pair is used to sign the request in case the store requires authentication. If the request fails, a technical error message is returned.

List

		store.list(accountHash, boxLabel, keyPair, done);

		class ListDone implements Store.ListDone {
			public void onListDone(@NonNull Iterable<Hash> hashes) { ... }
			public void onListFailed(@NonNull String error) { ... }
		}
	
		var done = store.list(accountHash, boxLabel, keyPair);

		done.onDone = function(hashes) { ... };
		done.onFailed = function(error) { ... };
	
		my ($hashes, $error) = $store->list($accountHash, $boxLabel, $keyPair);

		if (defined $error) {
			# request failed
		} else {
			for my $hash (@$hashes) { ... }
		}
	

Lists the corresponding box on the store.

The returned hash list may contain duplicates. The key pair is used to sign the request in case the store requires authentication. If the request fails, a technical error message is returned.

Modify

		store.modify(boxAdditions, boxRemovals, keyPair, done);

		class ModifyDone implements Store.ModifyDone {
			public void onModifyDone() { ... }
			public void onModifyFailed(@NonNull String error) { ... }
		}
	
		var done = store.modify(boxAdditions, boxRemovals, keyPair);

		done.onDone = function() { ... };
		done.onFailed = function(error) { ... };
	
		my $error = $store->modify($boxAdditions, $boxRemovals, $keyPair);

		if (defined $error) {
			# request failed
		} else {
			# done
		}
	

Modifies boxes on the store.

The key pair is used to sign the request in case the store requires authentication. If the request fails, a technical error message is returned.

Threading

Stores must always be accessed from the main thread. If necessary, they will offload work onto different threads.

Implementations

Store Availability
HTTP store All platforms
In-memory store All platforms
Hash verification store All platforms
Get from any store All platforms
Folder store Java, Perl
FTP store Perl
SFTP store Perl
Object cache Perl, Java/Android
Split store Perl
Log store Perl

Implementing a store

A minimal store implementation must provide the above store access functions.

The constructor should be lightweight, since store instances are created frequently, and sometimes without actually accessing the store. In most cases, it should just set URL and ID, and perhaps a few other fields. It should not connect to a server, for instance, or carry out other work. A store instance can also be created if the store is temporarily or permanently not available.

On multi-threaded platforms, the store access functions are always called from the main thread, but may obviously carry out their work on separate threads. The done handlers must be called on the main thread.

Since many store instances may be created for the same store, they should avoid keeping internal state. If necessary, state should be managed globally. Stores accessing the network typically manage a connection pool, for example, which ultimately carries out the requests. With this approach, a store instance is merely a lightweight interface to the connection pool:

https://condensation.io https://condensation.io https://viereck.ch Store instances Connection pool Connection tohttps://condensation.io get get Connection tohttps://viereck.ch GET ... HTTP/1.1 put put PUT ... HTTP/1.1

A store implementation may offer additional functions, such as garbage collection or account administration. Such functions are available when the store is instantiated directly, and not through an URL.