Skip to content
Thomas Schwotzer edited this page Aug 4, 2020 · 105 revisions

Asynchronous Semantic Ad-hoc Protocol (ASAP).

I try to explain in a little movie why we think that building applications on ad-hoc networks are better than sliced bread: ASAP - Motivation. There is also a German version: ASAP - Introduction (German)

(Some older scatches can be found here: ASAP Intro (some sketches (German))

Assumptions: Highly dynamic (owner based) ad-hoc network

Mobile devices can create ad-hoc networks based on short range protocols. There are number of routing protocols. Most of them recognize changes in network topology and adjust their routing tables accordingly. Devices leaving the network are forgotten sooner or later.

We are interested in a different scenario. We assume mobile devices to be owned by human users. Their devices can establish ad-hoc connections whenever they met. Devices (Users) leaving ad-hoc networks are very likely be seen again. The ASAP protocol is based on those assumptions. Use this library if they hold for your project as well.

General usage

ASAP assumes that your application produces messages. ASAP can store and disseminate messages. A lot of application communication patterns can be broken down to message exchange. Apparently, messenger applications are the best example. But even communication within a distributed calender app can be understood and implemented as message exchange: Each change is described in a message which is to be sent to all particiants of that app.

fully decentralized system

Consequent usage of the command pattern can lead to a server free (and maybe fully distributed application). Writing centralized apps is even more simple.

Usage and terminology

There is a little movie that tries to explain the core concepts and basic example.

Another movie explains example code which can be found in the test folder of this project.

This movies illustrates the routing features of ASAP with a little triangle scenario.

ASAP Peer

ASAP based apps are considered to be self-contained. Data, application and communication logic is within the application. ASAP apps are not meant to be complex apps. We implemented a messenger app, a public key infrastructure, a smart contract app but have no plans to implement system like weather predication. Rule of thumb: ASAP is good for

  • small data sets
  • apps which gather data in a very distributed manner like IoT apps
  • apps with (small but) sensitive data with demands for strong privacy
  • robust apps which can or should run on Internet but also ad-hoc networks
  • apps which want to avoid a server as single point of failure / point to be spied.
  • apps who like / need / require full control over their communication networks.

An ASAP app is also called an ASAP Peer. Quite often, an ASAP app / peer is owned / used / can be attached to a human user. It is good practice to name an ASAP peer after its owner if their is any.

Following code sniplet illustrates creation of an ASAP peer which stores its data in a file system.

public static final String PEERS_ROOT_FOLDER = "asapPeersRoot";
...
String name = "Alice";
ASAPChunkReceivedListener asapChunkReceivedListener = null; // explained later

ASAPPeer asapPeer = ASAPPeerFS.createASAPPeer(name, // peer name
                PEERS_ROOT_FOLDER + "/" + name, // peer folder
                asapChunkReceivedListener);

See javadoc of ASAPPeer for more details.

The following text will be undergo a lektorship soon... Better stick to the movies until than. thank you.

ASAPStorage

An ASAP storage runs with your application on the same machine. Your application can issue messages and store them with ASAP. ASAP takes care of message dissemination. There can be different implementations of an ASAPStorage. Version 1 supports file system persistency. A storage reference can be retrieved with this code:

ASAPStorage appStorage = ASAPEngineFS.getASAPStorage(APP_OWNER_NAME, APP_FOLDER);

ASAPStorage is an interface, see ASAPStorage javadoc

Adding a message / URI

Adding a message to the local storage is easy:

appStorage.add("http://myMessenger.sample", "AppMessage");

A message is kept as string (next release will support bytes as well). The first URI parameter is optional (and can be null). It is strongly recommended to use it, though. That URI describes what that message is about and/or what application should deal with it.

ASAP simply transfers messages. Message recipients could use a hint what application should deal with a received message. Just define a URI and use it for your application.

appStorage.addRecipient("http://myMessenger.sample", "PeerX");

adds a recipient to an URI. From now on, your local ASAP engine send messages (with that URI) to PeerX whenever the have established an ad-hoc network.

Chunk management

Messages are stored in ASAPChunks. A chunk is uniquely addressed with three parameters:

  1. URI
  2. Message issuer
  3. Era

First parameters is obvious: Each message is issued to ASAP with a URI.

Second parameter describes the issuer. One issuer is your application. Its name was described when getting the ASAPStorage object in the first place.

ASAP gets also messages from other peers. Thuse, each ASAPStorage has two major parts:

  1. one part keeps messages which are produced from the local application (your application)
  2. another part hold messages which are received from others via an ad-hoc communication

ASAPChunkStorage localStorage = appStorage.getChunkStorage();

produces a reference on the local storage, see getChunkStorage()

ASAPChunkStorage incommingStorage = appStorage.getIncomingChunkStorage("PeerX");

produces a reference on the storage which stores messages received from a peer called PeerX, see getIncomingChunkStorage()

appStorage.getSender(); produces a list of peer names from which messages arrived.

Era

Let's come back to the parameter which describe a chunk. The final parameter describes the era. An era is simply described by a number. That era is incremented whenever the communication topology changes. A topology changes if

  • a new connection could be established to another peer
  • a connection is lost.

Developers don't have to deal with era management. ASAPStorage offers methods to get the different era numbers, see documentation. It even offers a method to increase a new era. You shouldn't use this method if you are not completely sure what you are doing. It's barly required for most applications.

A ChunkStorage offers methods for chunk management. Chunks can be dropped and it can be checked if a chunk exists.

ASAPChunkCache

Dealing with eras is boring and error prone. We will see that most apps don't even have to deal with chunks at all. But even so, we have a least a way to ignore that era handling.

The ChunkCache is wrapper around chunks of same uri and same issuer. In can be produced by calling a method on a ChunkStorage:

ASAPChunkCache chunks = localStorage.getASAPChunkCache("http://myMessenger.sample", toEra) ;

Remember: Each chunk cache belongs to an issuer. The localStorage is the local application ChunkStorage. The URI filters messages as usual. The second parameter describes the oldest era we are interested in.

We want to produce a list of all messages issued by our application back to the olders era we.

We can call:

ASAPChunkCache chunks = localStorage.getASAPChunkCache("http://myMessenger.sample", appStorage.getOldestEra());

The ChunkCache offers methods to produce such message list, see javadoc.

You should use the era methods in ASAPStorage to calculate or get era numbers.

ASAP engine

ASAP is a protocol. The ASAP library implements that protocol engine. That library does not implement ad-hoc network etablishment. This is up to your application. You should also check out sibling projects. We used ASAP to build decentralized applications for Android. There is working code in other repositories.

ASAPEngine asapEngine = ASAPEngineFS.getASAPEngine(APP_OWNER_NAME, APP_FOLDER);

creates an ASAPEngine object. Whenever a new connection is established, your app should call:

asapEngine.handleConnection(inputStream, outputStream)

An InputStream and an OutputStream is required as parameter. The engine will now:

  1. increase era.
  2. send all messages which are ought to be sent to the other peer
  3. receive messages. Messages are stored in the incomming chunk storage

Apps can also get full control of incomming message handling:

Implement a ChunkReceiver and use it as third parameter in

asapEngine.handleConnection(inputStream, outputStream, yourChunkReceiver)

In that case, incomming messages are not stored by this library. You have full control of message handling.

Working example

A working example can be found here: point-to-point example multihop example

Clone this wiki locally