git ssb

1+

Daan Patchwork / patchwork



Tree: a40d71e4d68bf04bb03d8040fbf7614880514dc8

Files: a40d71e4d68bf04bb03d8040fbf7614880514dc8 / lib / plugins / index.js

6572 bytesRaw
1const Heartbeat = require('./heartbeat')
2const Subscriptions = require('./subscriptions')
3const Progress = require('./progress')
4const Search = require('./search')
5const RecentFeeds = require('./recent-feeds')
6const LiveBacklinks = require('./live-backlinks')
7const pull = require('pull-stream')
8const pCont = require('pull-cont/source')
9
10const plugins = {
11 likes: require('./likes'),
12 backlinks: require('./backlinks'),
13 profile: require('./profile'),
14 suggest: require('ssb-suggest'),
15 publicFeed: require('./public-feed'),
16 subscriptions2: require('./subscriptions2'),
17 thread: require('./thread'),
18 privateFeed: require('./private-feed'),
19 mentionsFeed: require('./mentions-feed'),
20 gatherings: require('./gatherings'),
21 networkFeed: require('./network-feed'),
22 channelFeed: require('./channel-feed'),
23 participatingFeed: require('./participating-feed'),
24 channels: require('./channels'),
25 contacts: require('./contacts')
26}
27
28const ref = require('ssb-ref')
29
30exports.name = 'patchwork'
31exports.version = require('../../package.json').version
32exports.manifest = {
33 subscriptions: 'source',
34 linearSearch: 'source',
35 privateSearch: 'source',
36
37 progress: 'source',
38 recentFeeds: 'source',
39 heartbeat: 'source',
40
41 getSubscriptions: 'async',
42
43 liveBacklinks: {
44 subscribe: 'sync',
45 unsubscribe: 'sync',
46 stream: 'source'
47 },
48
49 disconnect: 'async'
50}
51
52for (const key in plugins) {
53 exports.manifest[key] = plugins[key].manifest
54}
55
56exports.init = function (ssb, config) {
57 const progress = Progress(ssb)
58 const subscriptions = Subscriptions(ssb)
59 const search = Search(ssb)
60 const recentFeeds = RecentFeeds(ssb)
61 const replicating = new Set()
62
63 const patchwork = {
64 heartbeat: Heartbeat(),
65 subscriptions: subscriptions.stream,
66 progress: progress.stream,
67 recentFeeds: recentFeeds.stream,
68 linearSearch: search.linear,
69 privateSearch: search.privateLinear,
70 getSubscriptions: subscriptions.get,
71 liveBacklinks: LiveBacklinks(ssb),
72
73 disconnect: function (addr, cb) {
74 ssb.conn.disconnect(addr, cb)
75 return true
76 }
77 }
78
79 for (const key in plugins) {
80 patchwork[key] = plugins[key].init(ssb, config)
81 }
82
83 // CONNECTIONS
84 // refuse connections from blocked peers
85 ssb.auth.hook(function (fn, args) {
86 const self = this
87 patchwork.contacts.isBlocking({ source: ssb.id, dest: args[0] }, function (_, blocked) {
88 if (blocked) {
89 args[1](new Error('Client is blocked'))
90 } else {
91 fn.apply(self, args)
92 }
93 })
94 })
95
96 // manually populate peer table from {type: 'pub'} messages
97 // exclude blocked pubs, only accept broadcasts from people within 2 hops
98 // wait 10 seconds after start before doing it to ease initial load
99 // (gossip.autoPopulate is disabled in config)
100 setTimeout(() => {
101 const discovered = new Set()
102 patchwork.contacts.raw.get((err, graph) => {
103 if (err) return
104 pull(
105 ssb.messagesByType({ type: 'pub', live: true, keys: false }),
106 pull.drain(function (value) {
107 if (value.sync && config.gossip && config.gossip.prune) {
108 // clean up pubs announced by peers more than 2 hops away if `--gossip.prune=true`
109 ssb.conn.query().peersConnectable('db').forEach(([addr, data]) => {
110 if (!discovered.has(data.key) && data.type === 'pub') {
111 ssb.conn.forget(addr)
112 }
113 })
114 }
115
116 if (!value.content) return
117 const address = value.content.address
118 if (replicating.has(value.author) && address && ref.isFeed(address.key)) {
119 // ignore blocked pubs
120 const blocking = graph && graph[ssb.id] && graph[ssb.id][address.key] === false
121 if (blocking) return
122 // make multiserver address as a string
123 let msAddr
124 try {
125 msAddr = ref.toMultiServerAddress(address)
126 } catch (err) {
127 return
128 }
129 // do not override room entries even if people declared them to be pubs
130 const oldEntry = ssb.conn.db().get(msAddr)
131 if (oldEntry && oldEntry.type === 'room') return
132 // add pub to the CONN database
133 discovered.add(address.key)
134 ssb.conn.remember(msAddr, { type: 'pub', key: address.key, autoconnect: true })
135 }
136 })
137 )
138 })
139 }, 10e3)
140
141 // REPLICATION
142 // keep replicate up to date with replicateStream (replacement for ssb-friends)
143 pull(
144 patchwork.contacts.replicateStream({ live: true }),
145 pull.drain(state => {
146 for (const feedId in state) {
147 // track replicating for use by pub announcement filtering
148 if (state[feedId] === true) replicating.add(feedId)
149 else replicating.delete(feedId)
150
151 // request (or unrequest) the feed
152 ssb.replicate.request(feedId, state[feedId] === true)
153 }
154 })
155 )
156
157 // update ebt with latest block info
158 pull(
159 patchwork.contacts.raw.stream({ live: true }),
160 pull.drain((data) => {
161 if (!data) return
162 for (const from in data) {
163 for (const to in data[from]) {
164 const value = data[from][to]
165 ssb.ebt.block(from, to, value === false)
166 }
167 }
168 })
169 )
170
171 // use blocks in legacy replication (adapted from ssb-friends for legacy compat)
172 ssb.createHistoryStream.hook(function (fn, args) {
173 const opts = args[0]
174 const peer = this
175 return pCont(cb => {
176 // wait till the index has loaded.
177 patchwork.contacts.raw.get((_, graph) => {
178 // don't allow the replication if the feed being requested blocks the requester
179 const requesterId = peer.id
180 const feedId = opts.id
181 if (graph && feedId !== requesterId && graph[feedId] && graph[feedId][requesterId] === false) {
182 cb(null, function (abort, cb) {
183 // just give them the cold shoulder
184 // `abort` and `cb` are passed to avoid a pull-cont error
185 })
186 } else {
187 cb(null, pull(
188 fn.apply(peer, args),
189 // break off this feed if they suddenly block the recipient.
190 pull.take(function (msg) {
191 // handle when createHistoryStream is called with keys: true
192 if (!msg.content && msg.value.content) msg = msg.value
193 if (msg.content.type !== 'contact') return true
194 return !(
195 msg.content.blocking && msg.content.contact === peer.id
196 )
197 })
198 ))
199 }
200 })
201 })
202 })
203
204 return patchwork
205}
206

Built with git-ssb-web