Problem
There’s many social applications where it’s important to be able to signal to another user. For example, in a messaging app, I want to send an “invite-to-chat” with someone I haven’t started a conversation with yet. The nature of decentralized storage (and Gaia) makes things like this non-trivial.
Proposal: Gaia Hub Inboxes
We would add an endpoint to gaia hubs, which is something like the following:
POST /inbox/${destinationAddress}/${fromAddress}
This authenticates with the fromAddress — meaning that the request requires a bearer token to be signed by the fromAddress. The maximum size of these POSTs will be very small (e.g., 160 bytes).
And then there is an associated read endpoint:
GET /inbox/${destinationAddress}?page=${page}
Which will return a paginated list of all received messages from the above endpoint, in the form:
[{ senderAddress: string, contents: string, receivedTime: timestamp }]
Ordered by received time. Furthermore, entries in this are unique by sender – meaning that a sender will only ever be able to keep 160 bytes in the inbox at a time.
Finally, there is also a DELETE
endpoint to clear the inbox:
DELETE /inbox/${destinationAddress}?afterTime=${time}
The GET
and DELETE
endpoints both require authentication with the destinationAddress
Requirements on the Driver Model
The above spec will place one major new requirement on the driver model: The ability to list files / search.
This is virtually already a requirement. The way that the readUrl and writeUrl semantics work requires that a readUrl’s suffix correspond directly to the posted filename. In practice, systems which support that also support listing and searching by name (e.g., production key-value stores like Redis, memcached., cloud storage systems like azure blob storage, s3, and filesystems).
Example Use Case: Blog with Comments
A blog post with comments. Let’s say some user, Alice writes a blog post. The blog application wants to integrate comments from other users (Bob, Cathy) so that when people view the page, they see all the comments together, and only those comments which Alice’s client has integrated.
- Alice publishes blog post. Users read it from:
getFile('blog.json', { username: 'alice.id' })
- Bob and Cathy both write comments, and write them on their Gaia hubs.
putFile('alice-blog-comments.json', { encrypted: false })
- Bob and Cathy both signal to Alice that they left comments:
writeMessage('bob.id:alice-blog-comments.json', { username: 'alice.id' })
writeMessage('alice.id:alice-blog-comments.json', { username: 'alice.id' })
- Alice’s client, on next login (or with automated bot-in-a-box), gets the most recent items from her inbox, fetches the data, and integrates them into
blog.json
:
getMessages({after: lastLogin})
.then((messages) =>
Promise.all(messages.map(msg => {
[author, filename] = msg.content.split(':')
return getFile(filename, { username: author })
}))
.then(messageContents => {
const allComments = schemaValidateSanitize(messageContents)
return putFile('blog.json', { blogEntry: blogEntry,
comments: allComments })
}))