git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 4e87fb7f772146e90bc4f79a30bed7079d748a46

Files: 4e87fb7f772146e90bc4f79a30bed7079d748a46 / lib / friends-with-gossip-priority.js

4811 bytesRaw
1var Graphmitter = require('graphmitter')
2var pull = require('pull-stream')
3var mlib = require('ssb-msgs')
4var memview = require('level-memview')
5var pushable = require('pull-pushable')
6var mdm = require('mdmanifest')
7var valid = require('scuttlebot/lib/validators')
8var apidoc = require('scuttlebot/lib/apidocs').friends
9
10// friends plugin
11// methods to analyze the social graph
12// maintains a 'follow' and 'flag' graph
13
14function isFunction (f) {
15 return 'function' === typeof f
16}
17
18function isString (s) {
19 return 'string' === typeof s
20}
21
22function isFriend (friends, a, b) {
23 return friends[a] && friends[b] && friends[a][b] && friends[b][a]
24}
25
26exports.name = 'friends'
27exports.version = '1.0.0'
28exports.manifest = mdm.manifest(apidoc)
29
30exports.init = function (sbot, config) {
31
32 var graphs = {
33 follow: new Graphmitter(),
34 flag: new Graphmitter()
35 }
36
37 // view processor
38 var syncCbs = []
39 function awaitSync (cb) {
40 if (syncCbs) syncCbs.push(cb)
41 else cb()
42 }
43
44 // read/watch the log for changes to the social graph
45 pull(sbot.createLogStream({ live: true }), pull.drain(function (msg) {
46
47 if (msg.sync) {
48 syncCbs.forEach(function (cb) { cb() })
49 syncCbs = null
50
51 if (sbot.gossip) {
52 // prioritize friends
53 var friends = graphs['follow'].toJSON()
54 sbot.gossip.peers().forEach(function(peer) {
55 if (isFriend(friends, sbot.id, peer.key)) {
56 sbot.gossip.add(peer, 'friends')
57 }
58 })
59 }
60
61 return
62 }
63
64 var c = msg.value.content
65 if (c.type == 'contact') {
66 mlib.asLinks(c.contact, 'feed').forEach(function (link) {
67 if ('following' in c) {
68 if (c.following)
69 graphs.follow.edge(msg.value.author, link.link, true)
70 else
71 graphs.follow.del(msg.value.author, link.link)
72
73 }
74 if ('flagged' in c) {
75 if (c.flagged)
76 graphs.flag.edge(msg.value.author, link.link, c.flagged)
77 else
78 graphs.flag.del(msg.value.author, link.link)
79 }
80 })
81 }
82 }))
83
84 return {
85
86 get: valid.sync(function (opts) {
87 var g = graphs[opts.graph || 'follow']
88 if(!g) throw new Error('opts.graph must be provided')
89 return g.get(opts.source, opts.dest)
90 }, 'object?'),
91
92 all: valid.async(function (graph, cb) {
93 if (typeof graph == 'function') {
94 cb = graph
95 graph = null
96 }
97 if (!graph)
98 graph = 'follow'
99 awaitSync(function () {
100 cb(null, graphs[graph] ? graphs[graph].toJSON() : null)
101 })
102 }, 'string?'),
103
104 path: valid.sync(function (opts) {
105 if(isString(opts))
106 opts = {source: sbot.id, dest: opts}
107 return graphs.follow.path(opts)
108
109 }, 'string|object'),
110
111 createFriendStream: valid.source(function (opts) {
112 opts = opts || {}
113 var live = opts.live === true
114 var meta = opts.meta === true
115 var start = opts.start || sbot.id
116 var graph = graphs[opts.graph || 'follow']
117 if(!graph)
118 return pull.error(new Error('unknown graph:' + opts.graph))
119 var cancel, ps = pushable(function () {
120 cancel && cancel()
121 })
122
123 function push (to, hops) {
124 return ps.push(meta ? {id: to, hops: hops} : to)
125 }
126
127 //by default, also emit your own key.
128 if(opts.self !== false)
129 push(start, 0)
130
131 var conf = config.friends || {}
132 cancel = graph.traverse({
133 start: start,
134 hops: opts.hops || conf.hops || 3,
135 max: opts.dunbar || conf.dunbar || 150,
136 each: function (_, to, hops) {
137 if(to !== start) push(to, hops)
138 }
139 })
140
141 if(!live) { cancel(); ps.end() }
142
143 return ps
144 }, 'createFriendStreamOpts?'),
145
146 hops: valid.async(function (start, graph, opts, cb) {
147 if (typeof opts == 'function') { // (start|opts, graph, cb)
148 cb = opts
149 opts = null
150 } else if (typeof graph == 'function') { // (start|opts, cb)
151 cb = graph
152 opts = graph = null
153 }
154 opts = opts || {}
155 if(isString(start)) { // (start, ...)
156 // first arg is id string
157 opts.start = start
158 } else if (start && typeof start == 'object') { // (opts, ...)
159 // first arg is opts
160 for (var k in start)
161 opts[k] = start[k]
162 }
163
164 var conf = config.friends || {}
165 opts.start = opts.start || sbot.id
166 opts.dunbar = opts.dunbar || conf.dunbar || 150
167 opts.hops = opts.hops || conf.hops || 3
168
169 var g = graphs[graph || 'follow']
170 if (!g)
171 return cb(new Error('Invalid graph type: '+graph))
172
173 awaitSync(function () {
174 cb(null, g.traverse(opts))
175 })
176 }, ['feedId', 'string?', 'object?'], ['createFriendStreamOpts'])
177 }
178}
179

Built with git-ssb-web