Commit 3ff4af2891a16a2ac8dec9e3186a34bc1b842aa6
Merge branch 'master' into sort-network
mix irving committed on 2/7/2017, 11:40:27 AMParent: 83f0a729646d2a27162cb77fe27d448dc3f62568
Parent: a26dc85417ea413b52beecacaa45a025bc07cf51
Files changed
README.md | changed |
manifest.json | changed |
modules_core/sbot.js | changed |
modules_extra/search.js | changed |
package.json | changed |
README.md | ||
---|---|---|
@@ -22,12 +22,13 @@ | ||
22 | 22 … | sbot server |
23 | 23 … | # if you are already running patchwork, that also works. |
24 | 24 … | # (must have at least >= 2.8) |
25 | 25 … | |
26 | -# then in another tab (these must be 3 separate commands) | |
26 … | +# then in another tab (these must be separate commands) | |
27 | 27 … | sbot plugins.install ssb-links |
28 | 28 … | sbot plugins.install ssb-query |
29 | 29 … | sbot plugins.install ssb-ws |
30 … | +sbot plugins.install ssb-fulltext # for faster searches (optional) | |
30 | 31 … | # restart sbot server (go back to previous tab and kill it) |
31 | 32 … | ``` |
32 | 33 … | now clone and run patchbay. |
33 | 34 … | ``` |
manifest.json | ||
---|---|---|
@@ -103,8 +103,11 @@ | ||
103 | 103 … | "push": "async", |
104 | 104 … | "changes": "source", |
105 | 105 … | "createWants": "source" |
106 | 106 … | }, |
107 … | + "fulltext": { | |
108 … | + "search": "source" | |
109 … | + }, | |
107 | 110 … | "links2": { |
108 | 111 … | "read": "source", |
109 | 112 … | "dump": "source" |
110 | 113 … | }, |
modules_core/sbot.js | ||
---|---|---|
@@ -42,8 +42,9 @@ | ||
42 | 42 … | sbot_blobs_add: true, |
43 | 43 … | sbot_links: true, |
44 | 44 … | sbot_links2: true, |
45 | 45 … | sbot_query: true, |
46 … | + sbot_fulltext_search: true, | |
46 | 47 … | sbot_get: true, |
47 | 48 … | sbot_log: true, |
48 | 49 … | sbot_user_feed: true, |
49 | 50 … | sbot_gossip_peers: true, |
@@ -140,8 +141,11 @@ | ||
140 | 141 … | }), |
141 | 142 … | sbot_user_feed: rec.source(function (opts) { |
142 | 143 … | return sbot.createUserStream(opts) |
143 | 144 … | }), |
145 … | + sbot_fulltext_search: rec.source(function (opts) { | |
146 … | + return sbot.fulltext.search(opts) | |
147 … | + }), | |
144 | 148 … | sbot_get: rec.async(function (key, cb) { |
145 | 149 … | if('function' !== typeof cb) |
146 | 150 … | throw new Error('cb must be function') |
147 | 151 … | if(CACHE[key]) cb(null, CACHE[key]) |
modules_extra/search.js | |||
---|---|---|---|
@@ -1,16 +1,17 @@ | |||
1 | 1 … | const h = require('../h') | |
2 | 2 … | const fs = require('fs') | |
3 | -const { Value } = require('@mmckegg/mutant') | ||
3 … | +const { Struct, Value, when, computed } = require('@mmckegg/mutant') | ||
4 | 4 … | const u = require('../util') | |
5 | 5 … | const pull = require('pull-stream') | |
6 | 6 … | const Scroller = require('pull-scroll') | |
7 | 7 … | const TextNodeSearcher = require('text-node-searcher') | |
8 | 8 … | ||
9 | 9 … | exports.needs = { | |
10 | 10 … | build_scroller: 'first', | |
11 | 11 … | message_render: 'first', | |
12 | - sbot_log: 'first' | ||
12 … | + sbot_log: 'first', | ||
13 … | + sbot_fulltext_search: 'first' | ||
13 | 14 … | } | |
14 | 15 … | ||
15 | 16 … | exports.gives = { | |
16 | 17 … | screen_view: true, | |
@@ -55,8 +56,25 @@ | |||
55 | 56 … | searcher.highlight() | |
56 | 57 … | return el | |
57 | 58 … | } | |
58 | 59 … | ||
60 … | +function fallback(reader) { | ||
61 … | + var fallbackRead | ||
62 … | + return function (read) { | ||
63 … | + return function (abort, cb) { | ||
64 … | + read(abort, function next(end, data) { | ||
65 … | + if (end && reader && (fallbackRead = reader(end))) { | ||
66 … | + reader = null | ||
67 … | + read = fallbackRead | ||
68 … | + read(abort, next) | ||
69 … | + } else { | ||
70 … | + cb(end, data) | ||
71 … | + } | ||
72 … | + }) | ||
73 … | + } | ||
74 … | + } | ||
75 … | +} | ||
76 … | + | ||
59 | 77 … | exports.create = function (api) { | |
60 | 78 … | ||
61 | 79 … | return { | |
62 | 80 … | screen_view, | |
@@ -65,31 +83,42 @@ | |||
65 | 83 … | ||
66 | 84 … | function screen_view (path) { | |
67 | 85 … | if (path[0] !== '?') return | |
68 | 86 … | ||
69 | - var query = path.substr(1).trim().split(whitespace) | ||
70 | - var _matches = searchFilter(query) | ||
87 … | + var queryStr = path.substr(1).trim() | ||
88 … | + var query = queryStr.split(whitespace) | ||
89 … | + var matchesQuery = searchFilter(query) | ||
71 | 90 … | ||
72 | - const searched = Value(0) | ||
73 | - const matches = Value(0) | ||
91 … | + const search = Struct({ | ||
92 … | + isLinear: Value(false), | ||
93 … | + linear: Struct({ | ||
94 … | + checked: Value(0) | ||
95 … | + }), | ||
96 … | + fulltext: Struct({ | ||
97 … | + isDone: Value(false) | ||
98 … | + }), | ||
99 … | + matches: Value(0) | ||
100 … | + }) | ||
101 … | + const hasNoFulltextMatches = computed([search.fulltext.isDone, search.matches], | ||
102 … | + (done, matches) => done && matches === 0) | ||
103 … | + | ||
104 … | + | ||
74 | 105 … | const searchHeader = h('Search', [ | |
75 | - h('header', h('h1', query)), | ||
76 | - h('section.details', [ | ||
77 | - h('div.searched', ['Searched: ', searched]), | ||
78 | - h('div.matches', [matches, ' matches']) | ||
79 | - ]) | ||
106 … | + h('header', h('h1', query.join(' '))), | ||
107 … | + when(search.isLinear, | ||
108 … | + h('section.details', [ | ||
109 … | + h('div.searched', ['Searched: ', search.linear.checked]), | ||
110 … | + h('div.matches', [search.matches, ' matches']) | ||
111 … | + ]), | ||
112 … | + h('section.details', [ | ||
113 … | + h('div.searched'), | ||
114 … | + when(hasNoFulltextMatches, h('div.matches', 'No matches')) | ||
115 … | + ]) | ||
116 … | + ) | ||
80 | 117 … | ]) | |
81 | 118 … | var { container, content } = api.build_scroller({ prepend: searchHeader }) | |
82 | 119 … | container.id = path // helps tabs find this tab | |
83 | 120 … | ||
84 | - function matchesQuery (data) { | ||
85 | - searched.set(searched() + 1) | ||
86 | - var m = _matches(data) | ||
87 | - if(m) matches.set(matches() +1 ) | ||
88 | - | ||
89 | - return m | ||
90 | - } | ||
91 | - | ||
92 | 121 … | function renderMsg(msg) { | |
93 | 122 … | var el = api.message_render(msg) | |
94 | 123 … | highlight(el, createOrRegExp(query)) | |
95 | 124 … | return el | |
@@ -101,10 +130,22 @@ | |||
101 | 130 … | Scroller(container, content, renderMsg, true, false) | |
102 | 131 … | ) | |
103 | 132 … | ||
104 | 133 … | pull( | |
105 | - u.next(api.sbot_log, {reverse: true, limit: 500, live: false}), | ||
106 | - pull.filter(matchesQuery), | ||
134 … | + u.next(api.sbot_fulltext_search, {query: queryStr, reverse: true, limit: 500, live: false}), | ||
135 … | + fallback((err) => { | ||
136 … | + if (err === true) { | ||
137 … | + search.fulltext.isDone.set(true) | ||
138 … | + } else if (/^no source/.test(err.message)) { | ||
139 … | + search.isLinear.set(true) | ||
140 … | + return pull( | ||
141 … | + u.next(api.sbot_log, {reverse: true, limit: 500, live: false}), | ||
142 … | + pull.through(() => searched.set(searched()+1)), | ||
143 … | + pull.filter(matchesQuery) | ||
144 … | + ) | ||
145 … | + } | ||
146 … | + }), | ||
147 … | + pull.through(() => search.matches.set(search.matches()+1)), | ||
107 | 148 … | Scroller(container, content, renderMsg, false, false) | |
108 | 149 … | ) | |
109 | 150 … | ||
110 | 151 … | return container |
Built with git-ssb-web