Commit 2227f2f14f1094019ceb5e1cb1a8254841c2fe9e
Merge branch 'master' of ssb://%s9mSFATE4RGyJx9wgH22lBrvD4CgUQW4yeguSWWjtqc=.sha256 into evmaster
Ev Bogue committed on 11/3/2016, 9:08:55 PMParent: 5c65269d9872f15ab192ba3b916511db8505843b
Parent: c9a62bb9b4eb9236d7aae1a6487ad19d7affc72d
Files changed
modules/invite.js | changed |
modules/network.js | changed |
modules/notifications.js | changed |
modules/private.js | changed |
modules/public.js | changed |
modules/search-box.js | changed |
modules/setup.js | added |
package.json | changed |
plugs.js | changed |
sbot-api.js | changed |
style.css | changed |
util.js | changed |
modules/invite.js | ||
---|---|---|
@@ -7,36 +7,64 @@ | ||
7 | 7 … | var Progress = require('hyperprogress') |
8 | 8 … | |
9 | 9 … | var plugs = require('../plugs') |
10 | 10 … | var sbot_publish = plugs.first(exports.sbot_publish = []) |
11 … | +var sbot_gossip_connect = plugs.first(exports.sbot_gossip_connect = []) | |
12 … | +var follower_of = plugs.first(exports.follower_of = []) | |
11 | 13 … | |
14 … | +exports.invite_parse = function (invite) { | |
15 … | + return ref.parseInvite(invite) | |
16 … | +} | |
12 | 17 … | |
13 | -//check that invite is | |
14 | -// ws:...~shs:key:seed | |
15 | -function parseMultiServerInvite (invite) { | |
16 | - var redirect = invite.split('#') | |
17 | - if(!redirect.length) return null | |
18 … | +exports.invite_accept = function (invite, onProgress, cb) { | |
19 … | + var data = exports.invite_parse(invite) | |
20 … | + if(!data) return cb(new Error('not a valid invite code:' + invite)) | |
18 | 21 … | |
19 | - var parts = redirect[0].split('~') | |
20 | - .map(function (e) { return e.split(':') }) | |
22 … | + onProgress('connecting...') | |
23 … | + | |
24 … | + sbot_gossip_connect(data.remote, function (err) { | |
25 … | + if(err) console.log(err) | |
26 … | + }) | |
21 | 27 … | |
22 | - if(parts.length !== 2) return null | |
23 | - if(!/^(net|wss?)$/.test(parts[0][0])) return null | |
24 | - if(parts[1][0] !== 'shs') return null | |
25 | - if(parts[1].length !== 3) return null | |
26 | - var p2 = invite.split(':') | |
27 | - p2.pop() | |
28 … | + ssbClient(null, { | |
29 … | + remote: data.invite, | |
30 … | + manifest: { invite: {use: 'async'}, getAddress: 'async' } | |
31 … | + }, function (err, sbot) { | |
32 … | + if(err) return cb(err) | |
33 … | + onProgress('requesting follow...') | |
34 … | + console.log(sbot) | |
35 … | + sbot.invite.use({feed: id}, function (err, msg) { | |
28 | 36 … | |
29 | - return { | |
30 | - invite: redirect[0], | |
31 | - remote: p2.join(':'), | |
32 | - redirect: '#' + redirect.slice(1).join('#') | |
33 | - } | |
37 … | + //if they already follow us, just check we actually follow them. | |
38 … | + if(err) follower_of(id, data.key, function (_err, follows) { | |
39 … | + if(follows) cb(err) | |
40 … | + else next() | |
41 … | + }) | |
42 … | + else next() | |
43 … | + | |
44 … | + function next () { | |
45 … | + onProgress('following...') | |
46 … | + | |
47 … | + //remove the seed from the shs address. | |
48 … | + //then it's correct address. | |
49 … | + //this should make the browser connect to this as remote. | |
50 … | + //we don't want to do this if when using this locally, though. | |
51 … | + if(process.title === 'browser') | |
52 … | + localStorage.remote = data.remote | |
53 … | + | |
54 … | + sbot_publish({ | |
55 … | + type: 'contact', | |
56 … | + contact: data.key, | |
57 … | + following: true, | |
58 … | + }, cb) | |
59 … | + } | |
60 … | + }) | |
61 … | + }) | |
34 | 62 … | } |
35 | 63 … | |
36 | 64 … | exports.screen_view = function (invite) { |
37 | 65 … | |
38 | - var data = parseMultiServerInvite(invite) | |
66 … | + var data = ref.parseInvite(invite) | |
39 | 67 … | if(!data) return |
40 | 68 … | |
41 | 69 … | var progress = Progress(4) |
42 | 70 … | |
@@ -52,47 +80,23 @@ | ||
52 | 80 … | h('button', 'accept', {onclick: attempt}), |
53 | 81 … | progress |
54 | 82 … | ) |
55 | 83 … | |
56 | - function attempt () { | |
57 | - progress.reset().next('connecting...') | |
58 | - | |
59 | - ssbClient(null, { | |
60 | - remote: data.invite, | |
61 | - manifest: { invite: {use: 'async'}, getAddress: 'async' } | |
62 | - }, function (err, sbot) { | |
84 … | + function attempt () { | |
85 … | + exports.invite_accept(invite, function (message) { | |
86 … | + progress.next(message) | |
87 … | + }, function (err) { | |
63 | 88 … | if(err) return progress.fail(err) |
64 | - progress.next('requesting follow...') | |
89 … | + progress.complete() | |
90 … | + //check for redirect | |
91 … | + var parts = location.hash.substring(1).split('#') | |
65 | 92 … | |
66 | - sbot.invite.use({feed: id}, function (err, msg) { | |
67 | - if(err) return progress.fail(err) | |
68 | - progress.next('following...') | |
69 | - | |
70 | - //remove the seed from the shs address. | |
71 | - //then it's correct address. | |
72 | - //this should make the browser connect to this as remote. | |
73 | - //we don't want to do this if when using this locally, though. | |
74 | - if(process.title === 'browser') | |
75 | - localStorage.remote = data.remote | |
76 | - | |
77 | - sbot_publish({ | |
78 | - type: 'contact', | |
79 | - contact: sbot.id, | |
80 | - following: true, | |
81 | - }, function (err) { | |
82 | - if(err) return progress.fail(err) | |
83 | - progress.complete() | |
84 | - //check for redirect | |
85 | - var parts = location.hash.substring(1).split('#') | |
86 | - | |
87 | - //TODO: handle in a consistent way with either hashrouting | |
88 | - //or with tabs... | |
89 | - if(parts[0] === data.invite) | |
90 | - location.hash = data.redirect | |
91 | - else | |
92 | - console.log("NO REDIRECT") | |
93 | - }) | |
94 | - }) | |
93 … | + //TODO: handle in a consistent way with either hashrouting | |
94 … | + //or with tabs... | |
95 … | + if(parts[0] === data.invite) | |
96 … | + location.hash = data.redirect | |
97 … | + else | |
98 … | + console.log("NO REDIRECT") | |
95 | 99 … | }) |
96 | 100 … | } |
97 | 101 … | |
98 | 102 … | // If we are in the browser, |
@@ -102,4 +106,7 @@ | ||
102 | 106 … | return div |
103 | 107 … | } |
104 | 108 … | |
105 | 109 … | |
110 … | + | |
111 … | + | |
112 … | + |
modules/network.js | ||
---|---|---|
@@ -31,20 +31,20 @@ | ||
31 | 31 … | |
32 | 32 … | //pub is running scuttlebot >=8 |
33 | 33 … | //have connected successfully. |
34 | 34 … | function isLongterm (e) { |
35 | - return e.ping && e.ping.rtt.mean > 0 | |
35 … | + return e.ping && e.ping.rtt && e.ping.rtt.mean > 0 | |
36 | 36 … | } |
37 | 37 … | |
38 | 38 … | //pub is running scuttlebot < 8 |
39 | 39 … | //have connected sucessfully |
40 | 40 … | function isLegacy (peer) { |
41 | - return /connect/.test(peer.state) || peer.duration.mean > 0 && !exports.isLongterm(peer) | |
41 … | + return /connect/.test(peer.state) || (peer.duration && peer.duration.mean) > 0 && !isLongterm(peer) | |
42 | 42 … | } |
43 | 43 … | |
44 | 44 … | //tried to connect, but failed. |
45 | 45 … | function isInactive (e) { |
46 | - return e.stateChange && e.duration.mean == 0 | |
46 … | + return e.stateChange && e.duration && e.duration.mean == 0 | |
47 | 47 … | } |
48 | 48 … | |
49 | 49 … | //havn't tried to connect peer yet. |
50 | 50 … | function isUnattempted (e) { |
@@ -117,11 +117,11 @@ | ||
117 | 117 … | ' ', |
118 | 118 … | getType(peer), |
119 | 119 … | ' ', |
120 | 120 … | //TODO: show nicer details, with labels. etc. |
121 | - peer.ping ? duration(peer.ping.rtt.mean) : '', | |
121 … | + peer.ping && peer.ping.rtt ? duration(peer.ping.rtt.mean) : '', | |
122 | 122 … | ' ', |
123 | - peer.ping ? duration(peer.ping.skew.mean) : '', | |
123 … | + peer.ping && peer.ping.skew ? duration(peer.ping.skew.mean) : '', | |
124 | 124 … | h('label', |
125 | 125 … | {title: new Date(peer.stateChange).toString()}, |
126 | 126 … | peer.stateChange && ('(' + human(new Date(peer.stateChange))) + ')') |
127 | 127 … | ), |
@@ -142,24 +142,5 @@ | ||
142 | 142 … | |
143 | 143 … | })() |
144 | 144 … | |
145 | 145 … | return h('div.column.scroll-y', ol) |
146 | - | |
147 | 146 … | } |
148 | - | |
149 | - | |
150 | - | |
151 | - | |
152 | - | |
153 | - | |
154 | - | |
155 | - | |
156 | - | |
157 | - | |
158 | - | |
159 | - | |
160 | - | |
161 | - | |
162 | - | |
163 | - | |
164 | - | |
165 | - |
modules/notifications.js | ||
---|---|---|
@@ -121,9 +121,9 @@ | ||
121 | 121 … | ) |
122 | 122 … | ) |
123 | 123 … | |
124 | 124 … | pull( |
125 | - sbot_log({old: false}), | |
125 … | + u.next(sbot_log, {old: false, limit: 100}), | |
126 | 126 … | unbox(), |
127 | 127 … | notifications(ids), |
128 | 128 … | pull.filter(), |
129 | 129 … | Scroller(div, content, message_render, true, false) |
@@ -147,4 +147,5 @@ | ||
147 | 147 … | |
148 | 148 … | |
149 | 149 … | |
150 | 150 … | |
151 … | + |
modules/private.js | ||
---|---|---|
@@ -54,9 +54,9 @@ | ||
54 | 54 … | h('div.scroller__wrapper', compose, content) |
55 | 55 … | ) |
56 | 56 … | |
57 | 57 … | pull( |
58 | - sbot_log({old: false}), | |
58 … | + u.next(sbot_log, {old: false, limit: 100}), | |
59 | 59 … | unbox(), |
60 | 60 … | Scroller(div, content, message_render, true, false) |
61 | 61 … | ) |
62 | 62 … | |
@@ -83,5 +83,4 @@ | ||
83 | 83 … | })) |
84 | 84 … | } |
85 | 85 … | |
86 | 86 … | |
87 | - |
modules/public.js | ||
---|---|---|
@@ -21,9 +21,9 @@ | ||
21 | 21 … | ) |
22 | 22 … | ) |
23 | 23 … | |
24 | 24 … | pull( |
25 | - sbot_log({old: false}), | |
25 … | + u.next(sbot_log, {old: false, limit: 100}), | |
26 | 26 … | Scroller(div, content, message_render, true, false) |
27 | 27 … | ) |
28 | 28 … | |
29 | 29 … | pull( |
modules/search-box.js | ||
---|---|---|
@@ -10,9 +10,9 @@ | ||
10 | 10 … | var signified = require('../plugs').first(exports.signified = []) |
11 | 11 … | |
12 | 12 … | var builtinTabs = [ |
13 | 13 … | '/public', '/private', '/notifications', |
14 | - '/network', '/query', '/theme', '/versions' | |
14 … | + '/network', '/query', '/versions' | |
15 | 15 … | ].map(function (name) { |
16 | 16 … | return { |
17 | 17 … | title: name, |
18 | 18 … | value: name, |
modules/setup.js | ||
---|---|---|
@@ -1,0 +1,145 @@ | ||
1 … | + | |
2 … | +var h = require('hyperscript') | |
3 … | +var pull = require('pull-stream') | |
4 … | + | |
5 … | +var plugs = require('../plugs') | |
6 … | + | |
7 … | +var avatar_edit = plugs.first(exports.avatar_edit = []) | |
8 … | +var invite_parse = plugs.first(exports.invite_parse = []) | |
9 … | +var invite_accept = plugs.first(exports.invite_accept = []) | |
10 … | +var sbot_progress = plugs.first(exports.sbot_progress = []) | |
11 … | +var sbot_query = plugs.first(exports.sbot_query = []) | |
12 … | +var avatar = plugs.first(exports.avatar = []) | |
13 … | + | |
14 … | +//maybe this could show the pubs, or | |
15 … | +//if someone locally follows you, | |
16 … | +//it could show the second degree pubs? | |
17 … | + | |
18 … | +//maybe show the network as animated graph? | |
19 … | + | |
20 … | +function followers_query (id) { | |
21 … | + return [{$filter: { | |
22 … | + value: {content: { | |
23 … | + type: "contact", | |
24 … | + contact: id, | |
25 … | + following: true, | |
26 … | +// autofollow: true | |
27 … | + }} | |
28 … | + }}] | |
29 … | +} | |
30 … | + | |
31 … | +//test whether we are connected to the ssb network. | |
32 … | +exports.setup_is_fresh_install = function (cb) { | |
33 … | + //test by checking whether you have any friends following you? | |
34 … | + pull( | |
35 … | + sbot_query({query: followers_query(id), limit: 1, live: false}), | |
36 … | + pull.collect(function (err, ary) { | |
37 … | + cb(err, !!ary.length) | |
38 … | + }) | |
39 … | + ) | |
40 … | +} | |
41 … | + | |
42 … | +function invite_form () { | |
43 … | + var accept = h('button', 'enter code', {disabled: true, onclick: function () { | |
44 … | + invite_accept(input.value, function (msg) { | |
45 … | + status.textContent = msg | |
46 … | + }, function (err) { | |
47 … | + if(err) { | |
48 … | + accept.textContent = 'error:'+(err.message || err.stack || error.type) | |
49 … | + console.error(err) | |
50 … | + } | |
51 … | + else { | |
52 … | + input.value = '' | |
53 … | + accept.textContent = 'success!' | |
54 … | + } | |
55 … | + }) | |
56 … | + }}) | |
57 … | + | |
58 … | + function parseInput () { | |
59 … | + if(!input.value) { | |
60 … | + accept.disabled = true | |
61 … | + accept.textContent = 'enter code' | |
62 … | + } | |
63 … | + else if(!invite_parse(input.value)) { | |
64 … | + accept.disabled = true | |
65 … | + accept.textContent = 'invalid code' | |
66 … | + } | |
67 … | + else { | |
68 … | + accept.disabled = false | |
69 … | + accept.textContent = 'accept' | |
70 … | + } | |
71 … | + } | |
72 … | + | |
73 … | + var input = h('input.wide', {placeholder: 'invite code', oninput: parseInput, onchange: parseInput}) | |
74 … | + | |
75 … | + return h('div.invite-form.row', input, accept) | |
76 … | +} | |
77 … | + | |
78 … | +exports.progress_bar = function () { | |
79 … | + var liquid = h('div.hyperprogress__liquid', '.') | |
80 … | + var bar = h('div.hyperprogress__bar', liquid) | |
81 … | + liquid.style.width = '0%' | |
82 … | + | |
83 … | + pull( | |
84 … | + sbot_progress(), | |
85 … | + pull.drain(function (e) { | |
86 … | + liquid.style.width = Math.round((e.progress/e.total)*100)+'%' | |
87 … | + }) | |
88 … | + ) | |
89 … | + | |
90 … | + return bar | |
91 … | +} | |
92 … | + | |
93 … | +//show the first 5 followers, and how they join you to the network. | |
94 … | +//so this will show if a local peer follows you. | |
95 … | + | |
96 … | +//when you join the network, I want this to show as people follow you. | |
97 … | +//that could be when a pub accepts the invite, or when a local peer accepts. | |
98 … | + | |
99 … | +exports.setup_joined_network = function (id) { | |
100 … | + var followers = h('div.column') | |
101 … | + var label = h('label', 'not connected to a network') | |
102 … | + var joined = h('div.setup__joined', label,followers) | |
103 … | + | |
104 … | + pull( | |
105 … | + sbot_query({query: followers_query(id), limit: 5, live: true, sync: false}), | |
106 … | + pull.drain(function (follower) { | |
107 … | + if(follower.sync) return | |
108 … | + label.textContent = 'connected to network via...' | |
109 … | + followers.appendChild( | |
110 … | + avatar(follower.value.author, 'thumbnail') | |
111 … | + ) | |
112 … | + }) | |
113 … | + ) | |
114 … | + | |
115 … | + return joined | |
116 … | +} | |
117 … | + | |
118 … | +exports.screen_view = function (path) { | |
119 … | + | |
120 … | + if(path !== '/setup') return | |
121 … | + | |
122 … | + var id = require('../keys').id | |
123 … | + | |
124 … | + //set up an avatar | |
125 … | + | |
126 … | + | |
127 … | + var status = h('span') | |
128 … | + var invite = h('input', {placeholder: 'invite code'}) | |
129 … | + return h('div.scroller', h('div.scroller__wrapper', | |
130 … | + h('h1', 'welcome to patchbay!'), | |
131 … | + h('div', | |
132 … | + 'please choose avatar image and name', | |
133 … | + avatar_edit(id) | |
134 … | + ), | |
135 … | + h('h2', 'join network'), | |
136 … | + invite_form(), | |
137 … | + //show avatars of anyone on the same local network. | |
138 … | + //show realtime changes in your followers, especially for local. | |
139 … | + | |
140 … | + exports.progress_bar(), | |
141 … | + exports.setup_joined_network(require('../keys').id) | |
142 … | + )) | |
143 … | +} | |
144 … | + | |
145 … | + |
package.json | ||
---|---|---|
@@ -1,8 +1,8 @@ | ||
1 | 1 … | { |
2 | 2 … | "name": "patchbay", |
3 | 3 … | "description": "a pluggable patchwork", |
4 | - "version": "3.5.1", | |
4 … | + "version": "4.0.1", | |
5 | 5 … | "homepage": "https://github.com/dominictarr/patchbay", |
6 | 6 … | "repository": { |
7 | 7 … | "type": "git", |
8 | 8 … | "url": "git://github.com/dominictarr/patchbay.git" |
@@ -41,8 +41,9 @@ | ||
41 | 41 … | "ssb-feed": "^2.2.1", |
42 | 42 … | "ssb-keys": "^6.1.0", |
43 | 43 … | "ssb-markdown": "^3.0.0", |
44 | 44 … | "ssb-mentions": "^0.1.0", |
45 … | + "ssb-ref": "^2.6.2", | |
45 | 46 … | "ssb-sort": "^1.0.0", |
46 | 47 … | "suggest-box": "^2.2.1", |
47 | 48 … | "text-node-searcher": "^1.1.0", |
48 | 49 … | "visualize-buffer": "0.0.0" |
plugs.js | ||
---|---|---|
@@ -2,10 +2,9 @@ | ||
2 | 2 … | |
3 | 3 … | exports.first = function first(plug) { |
4 | 4 … | return function () { |
5 | 5 … | var args = [].slice.call(arguments) |
6 | - args.unshift(plug) | |
7 | - return u.firstPlug.apply(null, args) | |
6 … | + return u.firstPlug(plug, args) | |
8 | 7 … | } |
9 | 8 … | } |
10 | 9 … | |
11 | 10 … | exports.map = function (plug) { |
@@ -17,4 +16,5 @@ | ||
17 | 16 … | } |
18 | 17 … | } |
19 | 18 … | |
20 | 19 … | |
20 … | + |
sbot-api.js | ||
---|---|---|
@@ -151,17 +151,14 @@ | ||
151 | 151 … | }) |
152 | 152 … | }), |
153 | 153 … | sbot_whoami: rec.async(function (cb) { |
154 | 154 … | sbot.whoami(cb) |
155 … | + }), | |
156 … | + sbot_progress: rec.source(function () { | |
157 … | + return sbot.replicate.changes() | |
155 | 158 … | }) |
156 | 159 … | } |
157 | 160 … | } |
158 | 161 … | |
159 | 162 … | |
160 | 163 … | |
161 | 164 … | |
162 | - | |
163 | - | |
164 | - | |
165 | - | |
166 | - | |
167 | - |
style.css | ||
---|---|---|
@@ -79,8 +79,12 @@ | ||
79 | 79 … | white-space: pre-wrap; |
80 | 80 … | word-wrap: break-word; |
81 | 81 … | } |
82 | 82 … | |
83 … | +.wide { | |
84 … | + width: 100%; | |
85 … | +} | |
86 … | + | |
83 | 87 … | p { |
84 | 88 … | margin-top: .35ex; |
85 | 89 … | } |
86 | 90 … | |
@@ -382,19 +386,8 @@ | ||
382 | 386 … | .error { |
383 | 387 … | background: red; |
384 | 388 … | } |
385 | 389 … | |
386 | -/* themes */ | |
387 | - | |
388 | -.theme { | |
389 | - margin-left: 1ex; | |
390 | -} | |
391 | - | |
392 | -.themes__form { | |
393 | - margin: 1ex; | |
394 | -} | |
395 | - | |
396 | - | |
397 | 390 … | /* tabs */ |
398 | 391 … | |
399 | 392 … | .header { |
400 | 393 … | background: #f5f5f5; |
@@ -468,4 +461,15 @@ | ||
468 | 461 … | bottom: 0; |
469 | 462 … | left: 0; |
470 | 463 … | z-index: 1; |
471 | 464 … | } |
465 … | + | |
466 … | +/* progress bar */ | |
467 … | + | |
468 … | +.hyperprogress__bar { | |
469 … | + background: darkgrey; | |
470 … | +} | |
471 … | +.hyperprogress__liquid { | |
472 … | + background: lightblue; | |
473 … | +} | |
474 … | + | |
475 … | + |
util.js | ||
---|---|---|
@@ -57,13 +57,12 @@ | ||
57 | 57 … | ) |
58 | 58 … | }) |
59 | 59 … | } |
60 | 60 … | |
61 | -exports.firstPlug = function (plugs) { | |
61 … | +exports.firstPlug = function (plugs, args) { | |
62 | 62 … | if(!Array.isArray(plugs)) throw new Error('plugs must be an array') |
63 | - var args = [].slice.call(arguments) | |
64 | - var plugs = args.shift() | |
65 | 63 … | return exports.first(plugs, function (fn) { |
66 | 64 … | return fn.apply(null, args) |
67 | 65 … | }) |
68 | 66 … | } |
69 | 67 … | |
68 … | + |
Built with git-ssb-web