Home

Awesome

ssb-friends

Calculates the SSB social graph based on "contact" messages (such as follows and blocks), and provides APIs for you to query the social graph.

Based on dynamic-dijkstra module, see its Readme for an in-depth discussion of the algorithm.

Installation

Prerequisites:

npm install --save ssb-friends

Add this secret-stack plugin like this:

 const SecretStack = require('secret-stack')
 const caps = require('ssb-caps')

 const createSsbServer = SecretStack({ caps })
     .use(require('ssb-master'))
     .use(require('ssb-db'))
+    .use(require('ssb-friends'))
     .use(require('ssb-conn'))
     // ...

Usage

In ssb-friends, the relation between any two peers can be in 3 states, and each of those states are expressed by the following numbers (read more in the "Edge weights" section below):

There are APIs for creating follows and blocks (which under the hood will just publish messages of type "contact" on the log), and the are APIs for checking whether A follows or blocks B.

Then, there are social graph APIs such as hops and hopStream, which calculate "social graph distances" from you to other peers.

And there are low-level social graph APIs such as graph and graphStream which just tell you the latest edges in the social graph, without calculating distances.

ssb.friends.follow(feedId, opts, cb) ("async" muxrpc API)

Publishes a contact message asserting your current following state for feedId.

opts must be an object (or null) with these (optional) properties:

ssb.friends.block(feedId, opts, cb) ("async" muxrpc API)

Publishes a contact message asserting your current blocking state for feedId.

opts must be an object (or null) with these (optional) properties:

ssb.friends.isFollowing(opts, cb) ("async" muxrpc API)

Calls back true if opts.source follows opts.dest, false otherwise, where opts.source and opts.dest are strings of SSB Feed IDs.

If you pass opts.details = true, then the callback will respond with the object { response, private }, where response is the boolean indicating the follow relationship, and private is a boolean indicating that the relationship was originally encoded in a private (encrypted) message.

ssb.friends.isBlocking(opts, cb) ("async" muxrpc API)

Calls back true if opts.source blocks opts.dest, false otherwise, where opts.source and opts.dest are strings of SSB Feed IDs.

If you pass opts.details = true, then the callback will respond with the object { response, private }, where response is the boolean indicating the block relationship, and private is a boolean indicating that the relationship was originally encoded in a private (encrypted) message.

ssb.friends.hops([opts,] cb) ("async" muxrpc API)

Retrieves the current hops state, which is an object of the shape

{
  FeedId1: distance, // distance from you in hops
  FeedId2: distance,
  FeedId3: distance,
}

(Advanced) opts is an optional object, which allows you to configure the calculation of the hops distances with the following object fields:

ssb.friends.hopStream([opts]) ("source" muxrpc API)

Return a stream of hops objects {<id>:<dist>,...}, where the first item is the current state (such as what ssb.friends.hops() returns), and any following objects are updates caused by someone in your network following, unfollowing or blocking someone.

Can be configured via an opts argument, although arguably less configurable than ssb.friends.hops() because it only supports the following fields:

ssb.friends.graph(cb) ("async" muxrpc API)

Retrieves the current state of the social graph, which is an object of the shape

{
  FeedId1: {
    FeedId2: value, // a weight for the edge FeedId1 => FeedId2
  },
  FeedId3: {
    FeedId4: value,
    FeedId5: value,
  },
}

The value is a number, where its meaning is described at the top of this README.

ssb.friends.graphStream([opts]) ("source" muxrpc API)

Returns a stream of social graph objects, where each object has the same shape as the output of ssb.friends.graph(). The first object in the stream (only if opts.old is true) reflects the current state of the social graph, and subsequent objects (only if opts.live is true) represent just one updated edge, in the shape { FeedId1: { FeedId2: value } }.

Edge weights

This module is implemented in terms of dynamic-dijkstra (via layered-graph).

Relations between feeds are represented as non-zero numbers, as follows:

In SSB we use 1 to represent a follow, -1 to represent a block, -2 to represent unfollow.

A feed with distance 2 is a "friend of a friend" (we follow someone +1 who follows them +1 which sums up as 2). The distance -2 can mean either blocked by a friend or unfollowed by us.

If a friend follows someone another friend blocks, the friends follow wins, but if you block them directly, that block wins over the friend's follow.

License

MIT