Commit 389fe124a06bd5e7915acd466ce8aaa047d4eaca
initial commit (extracted from patchcore fork)
Matt McKegg committed on 6/12/2017, 1:29:16 AMFiles changed
.gitignore | added |
README.md | added |
index.js | added |
lib/flumeview-links-raw.js | added |
package.json | added |
README.md | ||
---|---|---|
@@ -1,0 +1,9 @@ | ||
1 … | +# ssb-backlinks | |
2 … | + | |
3 … | +[scuttlebot](http://scuttlebutt.nz/) plugin for indexing all link mentions of messages. | |
4 … | + | |
5 … | +Walks all values of a message searching for [ssb-ref](https://github.com/ssbc/ssb-ref) recognized keys. Provides an [ssb-query](https://github.com/dominictarr/ssb-query) style interface. | |
6 … | + | |
7 … | +## License | |
8 … | + | |
9 … | +MIT |
index.js | ||
---|---|---|
@@ -1,0 +1,59 @@ | ||
1 … | +var FlumeQueryLinks = require('./lib/flumeview-links-raw') | |
2 … | +var ref = require('ssb-ref') | |
3 … | +var deepEqual = require('deep-equal') | |
4 … | +var extend = require('xtend') | |
5 … | +var matchChannel = /^#[^\s#]+$/ | |
6 … | + | |
7 … | +var indexes = [ | |
8 … | + { key: 'DTS', value: [['dest'], ['timestamp']] }, | |
9 … | + { key: 'DTY', value: [['dest'], ['value', 'content', 'type'], ['timestamp']] } | |
10 … | +] | |
11 … | + | |
12 … | +var indexVersion = 0 | |
13 … | + | |
14 … | +exports.name = 'backlinks' | |
15 … | +exports.version = require('./package.json').version | |
16 … | +exports.manifest = { | |
17 … | + read: 'source' | |
18 … | +} | |
19 … | + | |
20 … | +exports.init = function (ssb, config) { | |
21 … | + return ssb._flumeUse( | |
22 … | + 'backlinks', | |
23 … | + FlumeQueryLinks(indexes, extractLinks, indexVersion) | |
24 … | + ) | |
25 … | +} | |
26 … | + | |
27 … | +function extractLinks (msg, emit) { | |
28 … | + var links = new Set() | |
29 … | + walk(msg.value.content, function (path, value) { | |
30 … | + // HACK: handle legacy channel mentions | |
31 … | + if (deepEqual(path, ['channel']) && typeof value === 'string' && value.length < 30) { | |
32 … | + value = `#${value.replace(/\s/g, '')}` | |
33 … | + } | |
34 … | + | |
35 … | + // TODO: should add channel matching to ref.type | |
36 … | + if (ref.type(value) || isChannel(value)) { | |
37 … | + links.add(value) | |
38 … | + } | |
39 … | + }) | |
40 … | + links.forEach(link => { | |
41 … | + emit(extend(msg, { | |
42 … | + dest: link | |
43 … | + })) | |
44 … | + }) | |
45 … | +} | |
46 … | + | |
47 … | +function isChannel (value) { | |
48 … | + return typeof value === 'string' && value.length < 30 && matchChannel.test(value) | |
49 … | +} | |
50 … | + | |
51 … | +function walk (obj, fn, prefix) { | |
52 … | + if (obj && typeof obj === 'object') { | |
53 … | + for (var k in obj) { | |
54 … | + walk(obj[k], fn, (prefix || []).concat(k)) | |
55 … | + } | |
56 … | + } else { | |
57 … | + fn(prefix, obj) | |
58 … | + } | |
59 … | +} |
lib/flumeview-links-raw.js | ||
---|---|---|
@@ -1,0 +1,105 @@ | ||
1 … | +// FORKED TO REMOVE FILTERING APPLIED TO INDEXED DATA RESULT | |
2 … | + | |
3 … | +'use strict' | |
4 … | +var pull = require('pull-stream') | |
5 … | +var query = require('flumeview-query/query') | |
6 … | +var select = require('flumeview-query/select') | |
7 … | +var mfr = require('map-filter-reduce') | |
8 … | +var u = require('flumeview-query/util') | |
9 … | +var Flatmap = require('pull-flatmap') | |
10 … | +var FlumeViewLevel = require('flumeview-level') | |
11 … | + | |
12 … | +var isArray = Array.isArray | |
13 … | + | |
14 … | +//sorted index. | |
15 … | + | |
16 … | +//split this into TWO modules. flumeview-links and flumeview-query | |
17 … | +module.exports = function (indexes, links, version) { | |
18 … | + | |
19 … | + if(!links) | |
20 … | + links = function (data, emit) { emit(data) } | |
21 … | + | |
22 … | + function getIndexes (data, seq) { | |
23 … | + var A = [] | |
24 … | + indexes.forEach(function (index) { | |
25 … | + var a = [index.key] | |
26 … | + for(var i = 0; i < index.value.length; i++) { | |
27 … | + var key = index.value[i] | |
28 … | + if(!u.has(key, data)) return | |
29 … | + a.push(u.get(key, data)) | |
30 … | + } | |
31 … | + a.push(seq) | |
32 … | + A.push(a) | |
33 … | + }) | |
34 … | + return A | |
35 … | + } | |
36 … | + | |
37 … | + var create = FlumeViewLevel(version || 1, function (value, seq) { | |
38 … | + var A = [] | |
39 … | + links(value, function (value) { | |
40 … | + A = A.concat(getIndexes(value, seq)) | |
41 … | + }) | |
42 … | + return A | |
43 … | + }) | |
44 … | + | |
45 … | + return function (log, name) { | |
46 … | + | |
47 … | + var index = create(log, name) | |
48 … | + var read = index.read | |
49 … | + | |
50 … | + index.read = function (opts) { | |
51 … | + | |
52 … | + opts = opts || {} | |
53 … | + var _opts = {} | |
54 … | + var q, k | |
55 … | + | |
56 … | + if(isArray(opts.query)) { | |
57 … | + q = opts.query[0].$filter || {} | |
58 … | + } | |
59 … | + else if(opts.query) { | |
60 … | + q = opts.query | |
61 … | + } | |
62 … | + else | |
63 … | + q = {} | |
64 … | + | |
65 … | + var index = select(indexes, q) | |
66 … | + | |
67 … | + if(!index) | |
68 … | + return pull( | |
69 … | + log.stream({ | |
70 … | + values: true, seqs: false, live: opts.live, limit: opts.limit, reverse: opts.reverse | |
71 … | + }), | |
72 … | + Flatmap(function (data) { | |
73 … | + var emit = [] | |
74 … | + links(data, function (a) { | |
75 … | + emit.push(a) | |
76 … | + }) | |
77 … | + return emit | |
78 … | + }) | |
79 … | + ) | |
80 … | + var _opts = query(index, q) | |
81 … | + | |
82 … | + | |
83 … | + _opts.values = false | |
84 … | + _opts.keys = true | |
85 … | + | |
86 … | + _opts.reverse = !!opts.reverse | |
87 … | + _opts.live = opts.live | |
88 … | + _opts.old = opts.old | |
89 … | + _opts.sync = opts.sync | |
90 … | + | |
91 … | + return pull( | |
92 … | + read(_opts), | |
93 … | + pull.map(function (data) { | |
94 … | + if(data.sync) return data | |
95 … | + var o = data.value | |
96 … | + for(var i = 0; i < index.value.length; i++) | |
97 … | + u.set(index.value[i], data.key[i+1], o) | |
98 … | + return o | |
99 … | + }), | |
100 … | + isArray(opts.query) ? mfr(opts.query) : pull.through() | |
101 … | + ) | |
102 … | + } | |
103 … | + return index | |
104 … | + } | |
105 … | +} |
package.json | ||
---|---|---|
@@ -1,0 +1,24 @@ | ||
1 … | +{ | |
2 … | + "name": "ssb-backlinks", | |
3 … | + "description": "scuttlebot plugin for indexing all link mentions of messages", | |
4 … | + "version": "0.0.0", | |
5 … | + "homepage": "https://github.com/ssbc/ssb-backlinks", | |
6 … | + "repository": { | |
7 … | + "type": "git", | |
8 … | + "url": "git://github.com/ssbc/ssb-backlinks.git" | |
9 … | + }, | |
10 … | + "dependencies": { | |
11 … | + "deep-equal": "^1.0.1", | |
12 … | + "flumeview-level": "^2.0.2", | |
13 … | + "flumeview-query": "^3.0.3", | |
14 … | + "map-filter-reduce": "^3.0.3", | |
15 … | + "pull-flatmap": "0.0.1", | |
16 … | + "pull-stream": "^3.6.0", | |
17 … | + "ssb-ref": "^2.7.1", | |
18 … | + "xtend": "^4.0.1" | |
19 … | + }, | |
20 … | + "devDependencies": {}, | |
21 … | + "scripts": {}, | |
22 … | + "author": "Secure Scuttlebutt Consortium", | |
23 … | + "license": "MIT" | |
24 … | +} |
Built with git-ssb-web