Socket
Socket
Sign inDemoInstall

ssb-conn

Package Overview
Dependencies
94
Maintainers
1
Versions
92
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 5.2.0 to 6.0.0

17

lib/conn-scheduler.d.ts

@@ -8,13 +8,15 @@ export declare class ConnScheduler {

private closed;
private loadedSocialGraph;
private loadedHops;
private lastMessageAt;
private lastRotationAt;
private hasScheduledAnUpdate;
private socialGraph;
private hops;
constructor(ssb: any, config: any);
private loadSocialGraph;
private isCurrentlyDownloading;
private weBlockThem;
private weFollowThem;
private isBlocked;
private isNotBlocked;
private isNotConnected;
private maxWaitToConnect;
private updateTheseConnections;
private maintainConnections;
private updateStagingNow;

@@ -25,8 +27,9 @@ private updateHubNow;

private removeDefunct;
private populateWithSeeds;
private setupPubDiscovery;
private setupBluetoothDiscovery;
private setupLanDiscovery;
private setupRoomAttendantDiscovery;
private setupPubDiscovery;
private cleanUpDB;
start: () => void;
stop: () => void;
}

@@ -13,2 +13,3 @@ "use strict";

const ConnQuery = require("ssb-conn-query");
const { hasNoAttempts, hasOnlyFailedAttempts } = ConnQuery;
const pull = require('pull-stream');

@@ -19,36 +20,24 @@ const Pausable = require('pull-pause');

const onNetwork = require('on-change-network-strict');
const hasNetwork = require('has-network2');
const hasNetworkRightNow = require('has-network2');
const Ref = require('ssb-ref');
const debug = require('debug')('ssb:conn:scheduler');
const SECONDS = 1e3;
const MINUTES = 60e3;
const HOUR = 60 * 60e3;
const RANDOM_MULTIPLIER = 0.8 + Math.random() * 0.4;
let lastCheck = 0;
let lastValue = null;
function hasNetworkDebounced() {
function hasNetwork() {
if (lastCheck + 1e3 < Date.now()) {
lastCheck = Date.now();
lastValue = hasNetwork();
lastValue = hasNetworkRightNow();
}
return lastValue;
}
function isOffline(p) {
if (ip.isLoopback(p[1].host) || p[1].host == 'localhost')
return false;
else
return !hasNetworkDebounced();
}
const canBeConnected = (p) => !isOffline(p);
function isLegacy(peer) {
return hasSuccessfulAttempts(peer) && !hasPinged(peer);
}
function notRoom(peer) {
return peer[1].type !== 'room';
}
function notPub(peer) {
return peer[1].type !== 'pub';
}
function isDefunct(peer) {
return peer[1].defunct === true;
}
function take(n) {
return (arr) => arr.slice(0, Math.max(n, 0));
}
function filter(condition) {
return (arr) => arr.filter(condition);
}
function detectType(peer) {

@@ -68,6 +57,8 @@ const [addr, data] = peer;

return 'room';
if (data.type === 'room-endpoint')
return 'room-attendant';
if (data.type === 'room-attendant')
return 'room-attendant';
if (data.type === 'room-endpoint' || data.type === 'room-attendant') {
if (data.alias)
return 'room-attendant-alias';
else
return 'room-attendant';
}
if (data.source === 'local')

@@ -95,20 +86,89 @@ return 'lan';

}
const { passesExpBackoff, passesGroupDebounce, hasNoAttempts, hasOnlyFailedAttempts, hasPinged, hasSuccessfulAttempts, sortByStateChange, } = ConnQuery;
function shufflePeers(peers) {
return peers.sort(() => Math.random() - 0.5);
const isNotLocalhost = (p) => !ip.isLoopback(p[1].host) && p[1].host !== 'localhost';
function isNotRoom(peer) {
return peer[1].type !== 'room';
}
const MINUTES = 60e3;
const HOUR = 60 * 60e3;
function isRoom(peer) {
return peer[1].type === 'room';
}
function isDefunct(peer) {
return peer[1].defunct === true;
}
function filterOldExcess(excess) {
return (peers) => {
const WAIT_TIME = 2 * MINUTES * RANDOM_MULTIPLIER;
return peers.filter((p) => Date.now() > p[1].hubUpdated + WAIT_TIME / excess);
};
}
function sortByOldestConnection(peers) {
return peers.sort((a, b) => {
return a[1].hubUpdated - b[1].hubUpdated;
});
}
function calculateCooldown(fullPercent, hops) {
return (peers) => {
return peers.map((peer) => {
const [, data] = peer;
const peerType = detectType(peer);
const normalizedFullPercent = Math.max(0.1, fullPercent);
const hop = hops[data.key];
const hopsCooldown = peerType === 'room'
? 1 * SECONDS
: hop === -1
? Infinity
: hop === null || hop === void 0
? 30 * SECONDS
: hop < 0
? -hop * 5 * SECONDS
: hop * SECONDS;
const retryCooldown = 4 * SECONDS + Math.min(64, data.failure || 0) ** 3 * 10 * SECONDS;
let cooldown = (hopsCooldown + retryCooldown) * normalizedFullPercent;
if (hasNoAttempts(peer))
cooldown *= 0.5;
if (Math.random() < 0.3)
cooldown *= 0.5;
if (peerType === 'lan')
cooldown *= 0.7;
if (peerType === 'room-attendant')
cooldown *= 0.8;
if (hasOnlyFailedAttempts(peer))
cooldown *= 3;
data.cooldown = cooldown;
return peer;
});
};
}
function cooledDownEnough(peer) {
var _a, _b;
const [, data] = peer;
const lastAttempt = (_b = (_a = data.stateChange) !== null && _a !== void 0 ? _a : data.hubUpdated) !== null && _b !== void 0 ? _b : 0;
if (data.cooldown === undefined)
return true;
return Date.now() > lastAttempt + data.cooldown;
}
function sortByCooldownAscending(peers) {
return peers.sort((a, b) => {
const [, aData] = a;
const [, bData] = b;
if (aData.cooldown === undefined)
return 1;
if (bData.cooldown === undefined)
return -1;
return aData.cooldown - bData.cooldown;
});
}
let ConnScheduler = class ConnScheduler {
constructor(ssb, config) {
this.weBlockThem = ([_addr, data]) => {
this.isBlocked = (peer) => {
const [, data] = peer;
if (!(data === null || data === void 0 ? void 0 : data.key))
return false;
return this.socialGraph[data.key] === -1;
return this.hops[data.key] === -1;
};
this.weFollowThem = ([_addr, data]) => {
if (!(data === null || data === void 0 ? void 0 : data.key))
return false;
return this.socialGraph[data.key] > 0;
this.isNotBlocked = (peer) => {
return !this.isBlocked(peer);
};
this.isNotConnected = (address) => {
return !this.ssb.conn.hub().getState(address);
};
this.start = () => {

@@ -119,14 +179,3 @@ var _a, _b, _c;

this.closed = false;
for (let peer of this.ssb.conn.dbPeers()) {
const [address, { source, type }] = peer;
if (source === 'local' ||
source === 'bt' ||
type === 'lan' ||
type === 'bt') {
this.ssb.conn.forget(address);
}
if (isDefunct(peer)) {
this.removeDefunct(address);
}
}
this.cleanUpDB();
this.ssbDB2Subscription = (_a = this.ssb.db) === null || _a === void 0 ? void 0 : _a.post((msg) => {

@@ -138,22 +187,18 @@ if (msg.value.author !== this.ssb.id) {

this.loadSocialGraph();
this.populateWithSeeds();
this.setupBluetoothDiscovery();
this.setupLanDiscovery();
this.setupRoomAttendantDiscovery();
this.setupPubDiscovery();
(_b = this.pubDiscoveryPausable) === null || _b === void 0 ? void 0 : _b.resume();
this.setupLanDiscovery();
this.setupBluetoothDiscovery();
this.intervalForUpdate = setInterval(() => this.updateSoon(), 2e3);
if ((_c = this.intervalForUpdate) === null || _c === void 0 ? void 0 : _c.unref)
this.intervalForUpdate.unref();
(_c = (_b = this.intervalForUpdate) === null || _b === void 0 ? void 0 : _b.unref) === null || _c === void 0 ? void 0 : _c.call(_b);
onWakeup(() => {
if (this.closed)
return;
this.ssb.conn.hub().reset();
if (!this.closed)
this.ssb.conn.hub().reset();
});
onNetwork(() => {
if (this.closed)
return;
this.ssb.conn.hub().reset();
if (!this.closed)
this.ssb.conn.hub().reset();
});
pull(this.ssb.conn.hub().listen(), pull.filter((ev) => ev.type === 'disconnected'), pull.drain(() => this.updateSoon(200)));
this.updateSoon();
this.updateNow();
};

@@ -176,20 +221,17 @@ this.stop = () => {

this.lastMessageAt = 0;
this.lastRotationAt = 0;
this.hasScheduledAnUpdate = false;
this.loadedSocialGraph = false;
this.socialGraph = {};
this.loadedHops = false;
this.hops = {};
}
loadSocialGraph() {
var _a, _b;
if (!((_a = this.ssb.friends) === null || _a === void 0 ? void 0 : _a.graphStream)) {
if (!((_a = this.ssb.friends) === null || _a === void 0 ? void 0 : _a.hopStream)) {
debug('Warning: ssb-friends@5 is missing, scheduling is degraded');
this.loadedSocialGraph = true;
this.loadedHops = true;
return;
}
pull((_b = this.ssb.friends) === null || _b === void 0 ? void 0 : _b.graphStream({ live: true, old: true }), pull.drain((g) => {
if (g[this.ssb.id]) {
const prev = this.socialGraph;
const updates = g[this.ssb.id];
this.socialGraph = { ...prev, ...updates };
}
this.loadedSocialGraph = true;
pull((_b = this.ssb.friends) === null || _b === void 0 ? void 0 : _b.hopStream({ live: true, old: true }), pull.drain((h) => {
this.hops = { ...this.hops, ...h };
this.loadedHops = true;
}));

@@ -205,2 +247,4 @@ }

return 30e3;
case 'room-attendant-alias':
return 30e3;
case 'bt':

@@ -214,25 +258,41 @@ return 60e3;

}
updateTheseConnections(test, opts) {
maintainConnections(quota, isDesiredPeer, pool, isPeerRotatable, rotationPeriod) {
const query = this.ssb.conn.query();
const peersUp = query.peersInConnection().filter(test);
const peersDown = query.peersConnectable('db').filter(test);
const { quota, backoffStep, backoffMax, groupMin } = opts;
const peersUp = query.peersConnected().filter(isDesiredPeer);
const peersDown = query
.peersConnectable(pool)
.filter(isDesiredPeer)
.filter(this.isNotBlocked)
.filter(isNotLocalhost)
.filter(([, data]) => data.autoconnect !== false);
const excess = peersUp.length > quota * 2 ? peersUp.length - quota : 0;
const freeSlots = Math.max(quota - peersUp.length, 0);
const fullPercent = 1 - freeSlots / quota;
z(peersUp)
.z(sortByStateChange)
.z(filterOldExcess(excess))
.z(sortByOldestConnection)
.z(take(excess))
.forEach(([addr]) => {
const fuzzyPeriod = (120e3 * (0.5 + Math.random())) / excess;
setTimeout(() => {
.forEach(([addr]) => this.ssb.conn.disconnect(addr));
const ROTATION_PERIOD = (rotationPeriod * RANDOM_MULTIPLIER) / Math.sqrt(peersDown.length);
if (freeSlots === 0 &&
peersDown.length > 0 &&
this.lastRotationAt + ROTATION_PERIOD < Date.now()) {
z(peersUp)
.z(filter(isPeerRotatable !== null && isPeerRotatable !== void 0 ? isPeerRotatable : (() => true)))
.z(filter(([, data]) => {
var _a, _b;
const lastAttempt = (_b = (_a = data.stateChange) !== null && _a !== void 0 ? _a : data.hubUpdated) !== null && _b !== void 0 ? _b : 0;
return lastAttempt + ROTATION_PERIOD < Date.now();
}))
.z(sortByOldestConnection)
.z(take(1))
.forEach(([addr]) => {
this.lastRotationAt = Date.now();
this.ssb.conn.disconnect(addr);
}, fuzzyPeriod);
});
});
}
z(peersDown)
.z((peers) => peers.filter((p) => !this.weBlockThem(p)))
.z((peers) => peers.filter(canBeConnected))
.z((peers) => peers.filter(([, data]) => data.autoconnect !== false))
.z(passesGroupDebounce(groupMin))
.z((peers) => peers.filter(passesExpBackoff(backoffStep, backoffMax)))
.z((peers) => Math.random() <= 0.3 ? shufflePeers(peers) : sortByStateChange(peers))
.z(calculateCooldown(fullPercent, this.hops))
.z(filter(cooledDownEnough))
.z(sortByCooldownAscending)
.z(take(freeSlots))

@@ -245,3 +305,3 @@ .forEach(([addr, data]) => this.ssb.conn.connect(addr, data));

.peersConnectable('db')
.filter((p) => !this.weBlockThem(p))
.filter(this.isNotBlocked)
.filter(([, data]) => data.autoconnect === false)

@@ -252,3 +312,3 @@ .forEach(([addr, data]) => this.ssb.conn.stage(addr, data));

.peersConnectable('staging')
.filter(this.weBlockThem)
.filter(this.isBlocked)
.forEach(([addr]) => this.ssb.conn.unstage(addr));

@@ -269,79 +329,15 @@ this.ssb.conn

updateHubNow() {
var _a;
const conn = this.ssb.conn;
if ((_a = this.config.seed) !== null && _a !== void 0 ? _a : true) {
this.updateTheseConnections((p) => p[1].source === 'seed', {
quota: 3,
backoffStep: 2e3,
backoffMax: 10 * MINUTES,
groupMin: 1e3,
});
}
if (conn.query().peersInConnection().length === 0) {
this.updateTheseConnections(() => true, {
quota: 1,
backoffStep: 1e3,
backoffMax: 6e3,
groupMin: 0,
});
}
this.updateTheseConnections((p) => p[1].type === 'room', {
quota: 5,
backoffStep: 5e3,
backoffMax: 5 * MINUTES,
groupMin: 5e3,
});
this.updateTheseConnections((p) => notRoom(p) && hasPinged(p), {
quota: 2,
backoffStep: 10e3,
backoffMax: 10 * MINUTES,
groupMin: 5e3,
});
this.updateTheseConnections((p) => notRoom(p) && hasNoAttempts(p), {
quota: 2,
backoffStep: 30e3,
backoffMax: 30 * MINUTES,
groupMin: 15e3,
});
this.updateTheseConnections((p) => notRoom(p) && hasOnlyFailedAttempts(p), {
quota: 3,
backoffStep: 1 * MINUTES,
backoffMax: 3 * HOUR,
groupMin: 5 * MINUTES,
});
this.updateTheseConnections((p) => notRoom(p) && isLegacy(p), {
quota: 1,
backoffStep: 4 * MINUTES,
backoffMax: 3 * HOUR,
groupMin: 5 * MINUTES,
});
z(conn
this.maintainConnections(5, isRoom, 'db', (p) => p[1].onlineCount === 0, 2 * MINUTES);
this.maintainConnections(4, isNotRoom, 'dbAndStaging', null, 2 * HOUR);
this.ssb.conn
.query()
.peersConnectable('staging')
.filter(this.weFollowThem)
.filter(notPub))
.z(take(3 -
conn
.query()
.peersInConnection()
.filter(this.weFollowThem)
.filter(notPub).length))
.forEach(([addr, data]) => conn.connect(addr, data));
conn
.query()
.peersInConnection()
.filter(this.weBlockThem)
.forEach(([addr]) => conn.disconnect(addr));
conn
.filter(this.isBlocked)
.forEach(([addr]) => this.ssb.conn.disconnect(addr));
this.ssb.conn
.query()
.peersInConnection()
.filter((p) => conn.hub().getState(p[0]) === 'connecting')
.filter((p) => this.ssb.conn.hub().getState(p[0]) === 'connecting')
.filter((p) => p[1].stateChange + this.maxWaitToConnect(p) < Date.now())
.forEach(([addr]) => conn.disconnect(addr));
conn
.query()
.peersConnected()
.filter((p) => p[1].type !== 'bt' && p[1].type !== 'lan')
.filter((p) => p[1].stateChange + 0.5 * HOUR < Date.now())
.forEach(([addr]) => conn.disconnect(addr));
.forEach(([addr]) => this.ssb.conn.disconnect(addr));
}

@@ -353,4 +349,6 @@ updateNow() {

return;
if (!this.loadedSocialGraph)
if (!this.loadedHops)
return;
if (!hasNetwork())
return;
this.updateStagingNow();

@@ -376,12 +374,76 @@ this.updateHubNow();

}
populateWithSeeds() {
setupBluetoothDiscovery() {
var _a;
const seeds = (_a = this.config.seeds) !== null && _a !== void 0 ? _a : [];
(Array.isArray(seeds) ? seeds : [seeds]).filter(Boolean).forEach((addr) => {
const key = Ref.getKeyFromAddress(addr);
this.ssb.conn.remember(addr, { key, source: 'seed' });
});
if (!((_a = this.ssb.bluetooth) === null || _a === void 0 ? void 0 : _a.nearbyScuttlebuttDevices)) {
debug('Warning: ssb-bluetooth is missing, scheduling is degraded');
return;
}
pull(this.ssb.bluetooth.nearbyScuttlebuttDevices(1000), pull.drain(({ discovered }) => {
if (this.closed)
return;
for (const btPeer of discovered) {
const addr = `bt:${btPeer.remoteAddress.split(':').join('')}` +
'~' +
`shs:${btPeer.id.replace(/^\@/, '').replace(/\.ed25519$/, '')}`;
const data = {
type: 'bt',
note: btPeer.displayName,
key: btPeer.id,
};
if (this.isNotBlocked([addr, data]) && this.isNotConnected(addr)) {
this.ssb.conn.stage(addr, data);
this.updateSoon(100);
}
}
}));
}
setupLanDiscovery() {
var _a, _b;
if (!((_a = this.ssb.lan) === null || _a === void 0 ? void 0 : _a.start) || !((_b = this.ssb.lan) === null || _b === void 0 ? void 0 : _b.discoveredPeers)) {
debug('Warning: ssb-lan is missing, scheduling is degraded');
return;
}
pull(this.ssb.lan.discoveredPeers(), pull.drain(({ address, verified }) => {
const key = Ref.getKeyFromAddress(address);
if (!key)
return;
const data = {
type: 'lan',
key,
verified,
};
if (this.isNotBlocked([address, data]) &&
this.isNotConnected(address)) {
this.ssb.conn.stage(address, data);
this.updateSoon(100);
}
}));
this.ssb.lan.start();
}
setupRoomAttendantDiscovery() {
var _a;
const timer = setTimeout(() => {
var _a;
if (!((_a = this.ssb.roomClient) === null || _a === void 0 ? void 0 : _a.discoveredAttendants)) {
debug('Warning: ssb-room-client@2 is missing, scheduling is degraded');
return;
}
pull(this.ssb.roomClient.discoveredAttendants(), pull.drain((attendant) => {
const addr = attendant.address;
const data = {
type: 'room-attendant',
key: attendant.key,
room: attendant.room,
roomName: attendant.roomName,
};
if (this.isNotBlocked([addr, data]) && this.isNotConnected(addr)) {
this.ssb.conn.stage(addr, data);
this.updateSoon(100);
}
}));
}, 100);
(_a = timer === null || timer === void 0 ? void 0 : timer.unref) === null || _a === void 0 ? void 0 : _a.call(timer);
}
setupPubDiscovery() {
var _a, _b;
var _a, _b, _c;
if (((_a = this.config.conn) === null || _a === void 0 ? void 0 : _a.populatePubs) === false)

@@ -393,3 +455,3 @@ return;

}
setTimeout(() => {
const timer = setTimeout(() => {
var _a, _b;

@@ -407,3 +469,3 @@ if (this.closed)

const key = Ref.getKeyFromAddress(address);
if (this.weBlockThem([address, { key }])) {
if (this.isBlocked([address, { key }])) {
this.ssb.conn.forget(address);

@@ -437,53 +499,30 @@ }

}, 1000);
(_c = timer === null || timer === void 0 ? void 0 : timer.unref) === null || _c === void 0 ? void 0 : _c.call(timer);
}
setupBluetoothDiscovery() {
var _a;
if (!((_a = this.ssb.bluetooth) === null || _a === void 0 ? void 0 : _a.nearbyScuttlebuttDevices)) {
debug('Warning: ssb-bluetooth is missing, scheduling is degraded');
return;
cleanUpDB() {
const roomsWithMembership = new Set();
for (let peer of this.ssb.conn.dbPeers()) {
const [address, { source, type, membership }] = peer;
if (source === 'local' ||
source === 'bt' ||
type === 'lan' ||
type === 'bt') {
this.ssb.conn.forget(address);
}
if (isDefunct(peer)) {
this.removeDefunct(address);
}
if (type === 'room' && membership) {
roomsWithMembership.add(address);
}
}
pull(this.ssb.bluetooth.nearbyScuttlebuttDevices(1000), pull.drain(({ discovered }) => {
if (this.closed)
return;
for (const btPeer of discovered) {
const address = `bt:${btPeer.remoteAddress.split(':').join('')}` +
'~' +
`shs:${btPeer.id.replace(/^\@/, '').replace(/\.ed25519$/, '')}`;
const data = {
type: 'bt',
note: btPeer.displayName,
key: btPeer.id,
};
if (this.weFollowThem([address, data])) {
this.ssb.conn.connect(address, data);
for (let [address, data] of this.ssb.conn.dbPeers()) {
if (data.type === 'room-endpoint' || data.type === 'room-attendant') {
if (data.alias &&
data.roomAddress &&
roomsWithMembership.has(data.roomAddress)) {
this.ssb.conn.forget(address);
}
else {
this.ssb.conn.stage(address, data);
}
}
}));
}
setupLanDiscovery() {
var _a, _b;
if (!((_a = this.ssb.lan) === null || _a === void 0 ? void 0 : _a.start) || !((_b = this.ssb.lan) === null || _b === void 0 ? void 0 : _b.discoveredPeers)) {
debug('Warning: ssb-lan is missing, scheduling is degraded');
return;
}
pull(this.ssb.lan.discoveredPeers(), pull.drain(({ address, verified }) => {
const key = Ref.getKeyFromAddress(address);
if (!key)
return;
const data = {
type: 'lan',
key,
verified,
};
if (this.weFollowThem([address, data])) {
this.ssb.conn.connect(address, data);
}
else {
this.ssb.conn.stage(address, data);
}
}));
this.ssb.lan.start();
}

@@ -490,0 +529,0 @@ };

@@ -8,3 +8,3 @@ import { FeedId } from 'ssb-typescript';

port?: number;
source: 'seed' | 'pub' | 'manual' | 'friends' | 'local' | 'dht' | 'bt' | 'stored';
source: 'pub' | 'manual' | 'friends' | 'local' | 'dht' | 'bt' | 'stored';
error?: string;

@@ -28,4 +28,2 @@ state?: undefined | 'connecting' | 'connected' | 'disconnecting';

export interface Config {
seed?: boolean;
seeds?: Array<string> | string;
conn?: {

@@ -43,3 +41,10 @@ autostart: boolean;

}) => CallableFunction;
hopStream: (opts: {
old: boolean;
live: boolean;
}) => CallableFunction;
}>;
readonly roomClient?: Readonly<{
discoveredAttendants: () => CallableFunction;
}>;
readonly bluetooth?: Readonly<{

@@ -46,0 +51,0 @@ nearbyScuttlebuttDevices: (x: number) => CallableFunction;

{
"name": "ssb-conn",
"description": "SSB plugin for establishing and managing peer connections",
"version": "5.2.0",
"version": "6.0.0",
"homepage": "https://github.com/staltz/ssb-conn",

@@ -6,0 +6,0 @@ "main": "lib/index.js",

@@ -99,3 +99,3 @@ <div style="text-align:center" align="center">

๐Ÿ”น `hubUpdated?: number`: Unix timestamp for when this data object was last updated in ConnHub
๐Ÿ”น `hubUpdated?: number`: Unix timestamp for when this data object was last updated in ConnHub, which means the last time it was connected or attempted

@@ -106,9 +106,9 @@ ๐Ÿ”น `stagingBirth?: number`: Unix timestamp for when this peer was added to ConnStaging

๐Ÿ”น `autoconnect?: boolean`: indicates whether this peer should be considered for connection in the scheduler
๐Ÿ”น `autoconnect?: boolean`: indicates whether this peer should be considered for automatic connection in the scheduler. By the default this field is considered `true` whenever it's undefined, and if you want opt-out of automatic connections for this peer (thus delegating it to a manual choice by the user), then set it to `false`.
๐Ÿ”น `failure?: number`: typically in ConnDB, this is the number of connection errors since the last successful connection
๐Ÿ”น `failure?: number`: typically stored in ConnDB, this is the number of connection errors since the last successful connection
๐Ÿ”น `duration?: object`: typically in ConnDB, this is a [statistics](https://www.npmjs.com/package/statistics) object to measure the duration of connection with this peer
๐Ÿ”น `duration?: object`: typically stored in ConnDB, this is a [statistics](https://www.npmjs.com/package/statistics) object to measure the duration of connection with this peer
๐Ÿ”น `ping?: object`: typically in ConnDB, this is [statistics](https://www.npmjs.com/package/statistics) object of various ping health measurements
๐Ÿ”น `ping?: object`: typically stored in ConnDB, this is [statistics](https://www.npmjs.com/package/statistics) object of various ping health measurements

@@ -119,3 +119,3 @@ ๐Ÿ”น `pool?: 'db' | 'hub' | 'staging'`: this only appears in ConnQuery APIs, and indicates from which pool (ConnDB or ConnHub or ConnStaging) was this peer picked

๐Ÿ”ธ `room?: string`: (only if `type = 'room-endpoint'`) the public key of the [room](https://github.com/staltz/ssb-room) server where this peer is in
๐Ÿ”ธ `room?: string`: (only if `type = 'room-attendant'`) the public key of the [room](https://github.com/staltz/ssb-room) server where this peer is in

@@ -289,14 +289,18 @@ ๐Ÿ”ธ `onlineCount?: number`: (only if `type = 'room'`) the number of room endpoints currently connected to this room

- Listen to a stream of Bluetooth nearby devices, and `stage` them
- Listen to a stream of peers online in Rooms, and `stage` them
**Periodic connections/disconnections:**
- With (5sec) exponential backoff, try to connect to at most 5 room servers
- With (10sec) exponential backoff, try to connect to at most 2 non-room peers that we have connected successfully before
- With (30sec) exponential backoff, try to connect to at most 2 non-room peers that we have never with connected before
- With (1min) exponential backoff, try to connect to at most 3 non-room peers that have we always failed to connect with
- With (4min) exponential backoff, try to connect to at most 1 non-room peer that seem to run a legacy version of the gossip plugin
- Try to maintain connections with 5 room servers
- If we're connected to more than 5, then after some minutes we'll start disconnecting from some rooms
- Try to maintain connections with 4 non-room peers (pubs, room attendants, LAN peers, etc)
- If we're connected to more than 4, then after some minutes we'll start disconnecting from some
- The lower the hops distance of the peer, the higher priority they receive
- The more connection failures the peer has presented, the lower the priority
- Room attendants and LAN peers have slight priority over pubs
- After we've been connected to a peer for many minutes, disconnect from them
and try to connect to different peers, to encourage diversity of connections
In none of the cases above shall we connect to a peer that we block. In addition to the above, the following actions happen automatically every (approximately) 1 second:
- Connect to (at most 3) staged peers we follow
- Disconnect from connected peers that have just been blocked by us

@@ -306,2 +310,3 @@ - Disconnect from peers that have been connected with us for more than 30min

- "Too long" means 30sec for LAN peers
- "Too long" means 30sec for Room attendants
- "Too long" means 1min for Bluetooth peers

@@ -320,2 +325,3 @@ - "Too long" means 5min for DHT invite peers

- Remove database entries for any LAN or Bluetooth peers (these are rediscovered just-in-time)
- Remove room alias addresses if those aliases are in rooms where I have membership

@@ -402,3 +408,3 @@ **Other events:**

- All "pools" (DB, Hub, Staging) are key-value pairs `[address, dataObject]`
- Make scheduling easily customizable but provide an opinionated default
- Make scheduling logic easily swappable but provide an opinionated default

@@ -405,0 +411,0 @@ <ul></ul>

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with โšก๏ธ by Socket Inc