git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 454dc73d98065ea261663450ba6c7433954706bd

Files: 454dc73d98065ea261663450ba6c7433954706bd / lib / friends-with-sync.js

4913 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 if (live) {
128 awaitSync(function () {
129 ps.push({sync: true})
130 })
131 }
132
133 //by default, also emit your own key.
134 if(opts.self !== false)
135 push(start, 0)
136
137 var conf = config.friends || {}
138 cancel = graph.traverse({
139 start: start,
140 hops: opts.hops || conf.hops || 3,
141 max: opts.dunbar || conf.dunbar || 150,
142 each: function (_, to, hops) {
143 if(to !== start) push(to, hops)
144 }
145 })
146
147 if(!live) { cancel(); ps.end() }
148
149 return ps
150 }, 'createFriendStreamOpts?'),
151
152 hops: valid.async(function (start, graph, opts, cb) {
153 if (typeof opts == 'function') { // (start|opts, graph, cb)
154 cb = opts
155 opts = null
156 } else if (typeof graph == 'function') { // (start|opts, cb)
157 cb = graph
158 opts = graph = null
159 }
160 opts = opts || {}
161 if(isString(start)) { // (start, ...)
162 // first arg is id string
163 opts.start = start
164 } else if (start && typeof start == 'object') { // (opts, ...)
165 // first arg is opts
166 for (var k in start)
167 opts[k] = start[k]
168 }
169
170 var conf = config.friends || {}
171 opts.start = opts.start || sbot.id
172 opts.dunbar = opts.dunbar || conf.dunbar || 150
173 opts.hops = opts.hops || conf.hops || 3
174
175 var g = graphs[graph || 'follow']
176 if (!g)
177 return cb(new Error('Invalid graph type: '+graph))
178
179 awaitSync(function () {
180 cb(null, g.traverse(opts))
181 })
182 }, ['feedId', 'string?', 'object?'], ['createFriendStreamOpts'])
183 }
184}
185

Built with git-ssb-web