Files: ed0d0518717fe16a686399588766fb35b3e6e37a / app / page / network / invite-peer.js
5408 bytesRaw
1 | const { h, Value, resolve, onceTrue, when, computed } = require('mutant') |
2 | // const { isInvite } = require('ssb-ref') |
3 | |
4 | function isInvite (code) { |
5 | return typeof code === 'string' && |
6 | code.length > 32 && |
7 | code.startsWith('inv:') && |
8 | code.endsWith('=') |
9 | // TODO find actual peer-invite validator! |
10 | } |
11 | |
12 | module.exports = function InvitePeer ({ connection }) { |
13 | const state = { |
14 | use: { |
15 | invite: Value(), |
16 | opening: Value(false), |
17 | message: Value(null), |
18 | accepting: Value(false), |
19 | result: Value(null) |
20 | }, |
21 | create: { |
22 | input: { |
23 | private: Value(), |
24 | reveal: Value() |
25 | }, |
26 | processing: Value(false), |
27 | time: Value(), |
28 | result: Value() |
29 | } |
30 | } |
31 | |
32 | const body = h('InvitePeer', [ |
33 | h('p', [ |
34 | h('i.fa.fa-warning'), |
35 | ' BETA - peer invites are still being rolled out to pubs and tested.' |
36 | ]), |
37 | h('div.use', [ |
38 | h('textarea', { |
39 | 'placeholder': 'peer invite code', |
40 | 'ev-input': handleInput |
41 | }), |
42 | // MIX : I hate this, it's a mess. There's a state machine emerging, but I don't have time to build it right now |
43 | computed( |
44 | [state.use.invite, state.use.opening, state.use.message, state.use.accepting], |
45 | (invite, opening, message, accepting) => { |
46 | if (opening || accepting) { |
47 | return [ |
48 | h('button', { disabled: 'disabled' }, [ |
49 | h('i.fa.fa-spinner.fa-pulse') |
50 | ]) |
51 | ] |
52 | } |
53 | |
54 | return [ |
55 | message && message.private ? h('div.private', message.private) : '', |
56 | message && message.reveal ? h('div.private', message.reveal) : '', |
57 | message |
58 | ? h('button -primary', { 'ev-click': acceptInvite }, 'accept invitation') |
59 | : invite |
60 | ? h('button -primary', { 'ev-click': openInvite }, 'use invite') |
61 | : h('button', { disabled: 'disabled', title: 'not a valid invite code' }, 'use invite') |
62 | ] |
63 | } |
64 | ), |
65 | computed(state.use.result, result => { |
66 | if (result === null) return |
67 | |
68 | return result |
69 | ? h('i.fa.fa-check') |
70 | : h('i.fa.fa-times') |
71 | }) |
72 | ]), |
73 | h('div.create', [ |
74 | h('p', 'make a new peer invite code:'), |
75 | h('div.form', [ |
76 | h('div.inputs', [ |
77 | h('textarea.private', { |
78 | placeholder: 'private message your friend will see when they open this invite', |
79 | 'ev-input': (ev) => state.create.input.private.set(ev.target.value) |
80 | }), |
81 | h('textarea.reveal', { |
82 | placeholder: 'an introduction message which the community will be able to read when this invite is accepted', |
83 | 'ev-input': (ev) => state.create.input.reveal.set(ev.target.value) |
84 | }) |
85 | ]), |
86 | h('button', { |
87 | 'ev-click': createInvite, |
88 | disabled: state.create.processing |
89 | }, 'create peer-invite') |
90 | ]), |
91 | h('div.result', [ |
92 | when(state.create.processing, [ |
93 | 'creating an peer invite takes some time.', |
94 | h('br'), |
95 | 'time so far: ', |
96 | state.create.time |
97 | ]), |
98 | when(state.create.result, h('div.code', [ |
99 | h('code', state.create.result) |
100 | ])) |
101 | ]) |
102 | ]) |
103 | ]) |
104 | |
105 | function createInvite () { |
106 | state.create.processing.set(true) |
107 | var start = Date.now() |
108 | var SECOND = 1e3 |
109 | var MINUTE = 60 * SECOND |
110 | |
111 | onceTrue(connection, sbot => { |
112 | var interval = setInterval( |
113 | () => { |
114 | const dt = Date.now() - start |
115 | const mins = Math.floor(dt / MINUTE) |
116 | const secs = Math.floor((dt - mins * MINUTE) / SECOND) |
117 | state.create.time.set(`${mins} mins, ${secs} seconds`) |
118 | }, |
119 | SECOND |
120 | ) |
121 | |
122 | const opts = { |
123 | private: resolve(state.create.input.private), |
124 | reveal: resolve(state.create.input.reveal) |
125 | } |
126 | |
127 | sbot.peerInvites.create(opts, (err, invite) => { |
128 | if (err) return console.error(err) |
129 | |
130 | clearInterval(interval) |
131 | state.create.result.set(invite) |
132 | state.create.processing.set(false) |
133 | }) |
134 | }) |
135 | } |
136 | |
137 | function handleInput (ev) { |
138 | state.use.result.set(null) |
139 | const invite = ev.target.value.replace(/^\s*"?/, '').replace(/"?\s*$/, '') |
140 | |
141 | if (!isInvite(invite)) return |
142 | |
143 | ev.target.value = invite |
144 | state.use.invite.set(invite) |
145 | } |
146 | |
147 | function openInvite () { |
148 | state.use.opening.set(true) |
149 | |
150 | onceTrue(connection, server => { |
151 | server.peerInvites.openInvite(resolve(state.use.invite), (err, data) => { |
152 | state.use.opening.set(false) |
153 | if (err) { |
154 | state.use.result.set(false) |
155 | console.error(err) |
156 | return |
157 | } |
158 | |
159 | console.log(err, data) // NOTE no opened arriving ... |
160 | // HACK |
161 | const m = data.opened || { |
162 | private: 'kiaora gorgeous, welcome' |
163 | } |
164 | state.use.message.set(m) |
165 | }) |
166 | }) |
167 | } |
168 | |
169 | function acceptInvite () { |
170 | state.use.accepting.set(true) |
171 | |
172 | onceTrue(connection, server => { |
173 | server.peerInvites.acceptInvite(resolve(state.use.invite), (err, confirm) => { |
174 | state.use.accepting.set(false) |
175 | if (err) { |
176 | state.use.result.set(false) |
177 | console.error(err) |
178 | return |
179 | } |
180 | |
181 | console.log('peerInvites.acceptInvite worked:', confirm) |
182 | state.use.result.set(true) |
183 | }) |
184 | }) |
185 | } |
186 | |
187 | return { |
188 | title: 'peer invites', |
189 | body |
190 | } |
191 | } |
192 |
Built with git-ssb-web