Files: e56dd0fc65220e4f40d8a41f95306b8d8bb09369 / plugins / friends.js
3582 bytesRaw
1 | var G = require('graphreduce') |
2 | var Reduce = require('flumeview-reduce') |
3 | var pull = require('pull-stream') |
4 | var FlatMap = require('pull-flatmap') |
5 | //var mlib = require('ssb-msgs') |
6 | //var pushable = require('pull-pushable') |
7 | var mdm = require('mdmanifest') |
8 | var valid = require('../lib/validators') |
9 | var apidoc = require('../lib/apidocs').friends |
10 | var ref = require('ssb-ref') |
11 | |
12 | // friends plugin |
13 | // methods to analyze the social graph |
14 | // maintains a 'follow' and 'flag' graph |
15 | |
16 | function isFunction (f) { |
17 | return 'function' === typeof f |
18 | } |
19 | |
20 | function isString (s) { |
21 | return 'string' === typeof s |
22 | } |
23 | |
24 | function isFriend (friends, a, b) { |
25 | return friends[a] && friends[b] && friends[a][b] && friends[b][a] |
26 | } |
27 | |
28 | exports.name = 'friends' |
29 | exports.version = '1.0.0' |
30 | exports.manifest = mdm.manifest(apidoc) |
31 | |
32 | exports.init = function (sbot, config) { |
33 | var g = null |
34 | |
35 | var index = sbot._flumeUse('friends', Reduce(1, function (g, rel) { |
36 | if(!g) g = {} |
37 | if(!ref.isFeed(rel.from)) throw new Error('FROM is not id') |
38 | if(!ref.isFeed(rel.to)) { |
39 | console.log('???', rel) |
40 | throw new Error('TO is not id') |
41 | } |
42 | G.addEdge(g, rel.from, rel.to, rel.value) |
43 | return g |
44 | }, function (data) { |
45 | if(data.value.content.type === 'contact' && ref.isFeed(data.value.content.contact)) { |
46 | return { |
47 | from: data.value.author, |
48 | to: data.value.content.contact, |
49 | value: data.value.content.following |
50 | } |
51 | } |
52 | })) |
53 | |
54 | return { |
55 | |
56 | get: function (opts, cb) { |
57 | index.get(opts, cb) |
58 | }, |
59 | |
60 | createFriendStream: valid.source(function (opts) { |
61 | opts = opts || {} |
62 | var live = opts.live === true |
63 | var meta = opts.meta === true |
64 | var start = opts.start || sbot.id |
65 | var first = true |
66 | var reachable = {} |
67 | g = g || {} |
68 | return pull( |
69 | index.stream(opts), |
70 | FlatMap(function (v) { |
71 | //this code handles real time streaming of the hops map. |
72 | function push (to, hops) { |
73 | out.push(meta ? {id: to, hops: hops} : to) |
74 | } |
75 | var out = [] |
76 | if(!v) return [] |
77 | if(v.from && v.to) { |
78 | //add edge from->to (value) |
79 | G.addEdge(g, v.from, v.to, v.value) |
80 | //recalculate the portion of the graph, reachable in opts.hops |
81 | var _reachable = G.hops(g, start, 0, opts.hops || 3, reachable) |
82 | //for each node currently reachable |
83 | for(var k in _reachable) { |
84 | //check if it has _become_ reachable just now. |
85 | //if so add to the set |
86 | if(reachable[k] == null) |
87 | push(k, reachable[k] = _reachable[k]) |
88 | //if this has shortened the path, then update. |
89 | else if(reachable[k] > _reachable[k]) |
90 | reachable[k] = _reachable[k] |
91 | //else, we where already able to reach this node. |
92 | } |
93 | } |
94 | else { |
95 | g = v |
96 | reachable = G.hops(g, start, 0, opts.hops || 3) |
97 | for(var k in reachable) |
98 | push(k, reachable[k]) |
99 | } |
100 | if(first) { |
101 | first = false |
102 | if(live) { |
103 | out.push({sync: true}) |
104 | } |
105 | } |
106 | return out |
107 | }) |
108 | |
109 | ) |
110 | }, 'createFriendStreamOpts?'), |
111 | |
112 | hops: function (opts, cb) { |
113 | opts = opts || {} |
114 | if(isString(opts)) |
115 | opts = {start: opts} |
116 | index.get(null, function (err, g) { |
117 | if(err) cb(err) |
118 | else cb(null, G.hops(g, opts.start || sbot.id, 0, opts.hops || 3)) |
119 | }) |
120 | } |
121 | } |
122 | } |
123 | |
124 | |
125 | |
126 |
Built with git-ssb-web