Migrate from gossip to ssb-standard-conn
TO DO
-
ssb-legacy-conn: replace utils::find
with Array.find -
ssb-legacy-conn: use TypeScript -
create ssb-conn-db package -
ssb-legacy-conn: use ssb-conn-db instead of atomic-file -
ssb-legacy-conn: make sure local
peers are not stored in conn-db -
create ssb-conn-hub package -
ssb-legacy-conn: use ssb-conn-hub -
ssb-legacy-conn: get rid of peers
, instead cross conn-db data with conn-hub data -
ssb-conn-hub: add debug() logs -
ssb-conn-staging: create this -
ssb-conn-db: add debug() logs -
ssb-legacy-conn: match ssb-gossip 1.0.10 -
Consider Aljoscha's thoughts: %h7rjRPQ8KBhm7k3BGoK2TV6eIraVBiUnG5ecSvL4HEk=.sha256
(peer sampling service) -
ssb-legacy-conn and conn-hub: make ConnHub.close() that shuts things down -
ssb-legacy-conn: extract init.js and schedule.js further above in the abstraction hierarchy -
ssb-conn-query: refactor this out of gossip::schedule.js -
ssb-legacy-conn: use ssb-conn-query -
ssb-conn-db: should record birth field -
ssb-conn-hub: live pull-stream for entries() -
ssb-conn-staging: live pull-stream for entries() -
ssb-conn: register plugin gossip
as an alias forconn
and implement at least.gossip.ping
for anonymous remote peers -
create ssb-conn within ssb-legacy-conn, rearchitect -
Manyverse: rearchitect all 'peer' metadata to be [string, data]
, starting from SSB driver -
Manyverse: make sure LAN peers work as expected -
Manyverse: make sure Bluetooth peers work as expected -
UX Manyverse: peers 'connecting' look different than peers 'connected' -
Manyverse: make sure pubs work as expected -
ssb-conn-staging: add field {updated: timestamp}
to all KVs -
ssb-conn-staging: when connecting OR connected, unstage -
UX Manyverse: selecting a connected peer opens a popup (open profile, disconnect) -
UX Manyverse: selecting a staged peer opens a popup (open profile, connect, connect-then-follow) -
Manyverse: make sure DHT peers work as expected -
ssb-conn: create this -
ssb-conn scheduler: call ssb.bluetooth.nearby to stage peers, and periodically unstage them -
ssb-conn scheduler: never connect to a blocked peer -
ssb-conn scheduler: auto-connect to staged peers that we follow -
ssb-local2: create this (Notice issue #271 (closed)), to expose a pull-stream source of LAN peers, broadcast also hash of the caps -
ssb-conn scheduler: drain ssb-local2 stream and put {type, key}
in staging, periodically unstage -
ssb-conn scheduler: autopurge old staged peers using stagingUpdated
fields from staging -
Move ssb-conn out of ssb-legacy-conn, make ssb-conn a dependency in ssb-legacy-conn -
ssb-legacy-conn: simplify as much as possible
SSB Gossip Rewrite
Goals
- Simplify (untangle the implementation)
- Modularize (split it into 4+ modules)
- Generalize (use multiserver addresses and never assume host:port shape)
- Customization via distros (i.e. instead of using lots of config fields in ssb-config, make it easy for developers to recombine and package their own gossip plugin)
- Small (each of the modules should be about 200 lines of code each, in contrast current ssb-gossip is 700+ LOC)
Non-goals
(Things that could be done, and would be nice, but are not yet an actual problem, and by doing these we may introduce a new class unknown of problems)
- Replace
atomic-file
with another database - Generalizing this work to non-SSB contexts
Proposed design
SSB CONN (Connections over Numerous Networks) as a stack of modules:
graph BT
ssb-conn-query --> ssb-legacy-conn
ssb-conn-db --> ssb-legacy-conn
ssb-conn-db --> ssb-conn-query
ssb-conn-hub --> ssb-conn-query
ssb-conn-staging --> ssb-conn-query
ssb-conn-hub --> ssb-conn-staging
ssb-conn-staging --> ssb-legacy-conn
ssb-conn-hub --> ssb-legacy-conn
subgraph ssb-gossip alternatives
ssb-legacy-conn
ssb-conn
end
ssb-conn-db
Takes care of persisting data concerning connections.
Contract
Needs
- Path where the local database should be stored
atomic-file
Provides
- CRUD API, key-value style where string address is the key
-
multiserver-address
validation of the given addresses upon insert - Simple query APIs such as "best peer(s) under certain criteria"
- Possibility to store peers that don't have a public crypto identity (e.g. rooms)
- API to listen to changes to the DB
- Important if a
ssb-gossip
plugin wants to always attempt connect upon DB insertion
- Important if a
ssb-conn-hub
Takes care of managing connections active during runtime.
Contract
Needs
- pull-ping
Provides
- API to connect to a specific peer (returns promise)
- API to disconnect from a specific peer (returns promise)
- API to list all currently connected peers (returns promise of array)
- API to listen to changes to the set of currently connected peers
- like
gossip.changes
- like
- API to enable/disable a mode (a type of peer)
- API to listen to modes being switched on/off
- API to live detect the status
- Offline: OFF (all connectivity modes are turned off)
- Standby: ON (some connectivity modes are on), DISCONNECTED, and IDLE
- Seeking: ON, DISCONNECTED, and BUSY
- Online: ON, CONNECTED to some
ssb-conn-utils
Provides common connection-establishing tactics and algorithms. Perhaps this should be a Wiki with many independent utils modules?
Contract
Needs
- ssb-conn-db
- ssb-conn-hub
Provides
- API to reconnect all
- API to select peers based on criteria
- API to connect to one peer that matches a criteria
- For example,
gossip/schedule.js::connect()
function - Perhaps this is just
utils::select()
followed by ahub::connect()
?
- For example,
- API to connect with exponential capped backoff upon errors
- Listen to Hub events (such as connect/disconnect) and store health stats and ping to the db
- API to disconnect one peer that matches a criteria
ssb-example-gossip
Template project showing how to setup your own ssb-gossip. Draft:
function ssbCONN(connDB, connHub) {
connHub.onStatusChange((status) => {
onSomeEvent(() => {
utils.connectToMany(someCriteria)
})
})
connHub.onConnect(() => {
if (connHub.amount > MAX) {
utils.disconnectOne(someCriteria)
}
})
return pluginAPI
}
ssb-legacy-gossip
Mimics as much as possible the current ssb-gossip
plugin.
Mapping the current gossip plugin
Features
Exports
-
add: sync
- insert a peer's address to the local gossip db
-
remove: sync
- remove a peer's address from the local gossip db
-
enable: sync
- Enable a type (local/global/seed) of connections to happen
-
disable: sync
- Disable a type (local/global/seed) of connections from happening
-
connect: async
- connect to a given address, AND add it to the local gossip db
-
peers: sync
- Fetch all currently connected peers
-
changes: source
- Listen to changes to set of currently connected peers
-
reconnect: sync
- Nuke current connections and try to connect to any peers
-
ping: duplex
- Used internally to measure latency and clock skew
Imports
-
has-network
- To detect whether the current network interfaces give us any connection beyond the local device
on-change-network
on-wakeup
-
ip
- To detect whether an IP address is private, or whether it is loopback
-
statistics
- To calculate stats on duration to connect
-
atomic-file
- As the database
Behavioral
- Reconnect on network interface changes
- Observe network interfaces, and when they change, call
reconnect
- Observe network interfaces, and when they change, call
- Reconnect on computer waking up from sleep mode
- Send heartbeats to self, and if some are missing, it means computer slept
- Analyze good peers to connect to
- Based on ping stats
- Based on whether they have been responding to our attempts
- On startup, read the SSB log for messages type "pub", and attempt connection
- Schedule new connections upon startup
- Schedule new connections periodically
- Do not allow connections to exceed a maximum number, from config
- Periodically save in-memory peers to the local gossip database
- Scheduling connections always has a random delay
- To prevent deadlock dancing with a remote peer following the same periodic rythym
- Some peer types (e.g. local) are not loaded from db
- On incoming (expected) connection, setup ping, update db, setup teardown logic
- All peers must have a
key
(public identity)
Course of action
Basically, create ssb-legacy-gossip and literally just import ssb-gossip as is, then gradually write the other pieces, replacing parts as we go. In other words gradual migration, not sudden rewrite. See the top of this issue for a task list.
The idea is to use ssb-legacy-gossip in Manyverse, and gradually rewrite the internals, always using ssb-legacy-gossip in production. Once ssb-legacy-gossip is fully rewritten and conforms to the previous behavior, we can start building ssb-standard-gossip with new behavior.
ssb-standard-gossip can introduce:
- Impossibility to connect with a blocked peer
- Connect based on hops distance (see
%PyiK5ksJlFD+cZCj5OZo7o7OdZxf6LaopOiwK75Ib1s=.sha256
) - Exponential capped backoff on a per node basis
- As a utility in
ssb-conn-utils
? - As an option given to
ssb-conn-hub::connect(opts)
?
- As a utility in
- Configurability of ssb-standard-gossip through ssb-config (while allowing other ssb-gossip implementations to ignore or not those configs)
- Etc
For reference, these are the instances where high-level who-to-connect logic is coded:
- ssb-friends will replicate all friends https://github.com/ssbc/ssb-friends/issues/26
- add local peers to gossip: https://github.com/ssbc/ssb-server/blob/master/plugins/local.js#L52-L63
-
ssb-replicate
also has policy to always replicate local peers: https://github.com/ssbc/ssb-replicate/blob/master/legacy.js#L194-L200 it would be better if that was handled by local plugin, so that this happened when replicating on ebt also. The reason it's like this is because legacy replication predates this policy of separating how from what. - add pub messages to gossip: https://github.com/ssbc/ssb-gossip/blob/master/init.js#L15-L27
- add
address
messages to gossip: https://github.com/ssbc/ssb-device-address/blob/master/index.js#L35-L64 (this should supercedepub
messages)
References: