git ssb

0+

Piet / ssb-loomio



Commit 5f55ad219f72d734cb27efc4d543d507f1fd04ae

latest

Piet Geursen committed on 5/26/2018, 11:19:58 AM
Parent: 9792bede1cbfa9f873cc29f78a3b82929b371767

Files changed

package-lock.jsonchanged
package.jsonchanged
poll/async/get.jschanged
poll/obs/get.jschanged
results/sync/buildResults.jschanged
test/poll/obs/get.test.jschanged
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 195008 bytes
New file size: 195263 bytes
package.jsonView
@@ -28,9 +28,13 @@
2828 "libnested": "^1.2.1",
2929 "lodash.clonedeep": "^4.5.0",
3030 "mutant": "^3.22.1",
3131 "pull-async": "^1.0.0",
32+ "pull-cat": "^1.1.11",
33+ "pull-concat": "^1.1.1",
34+ "pull-defer": "^0.2.2",
3235 "pull-notify": "^0.1.1",
36+ "pull-scan": "^1.0.0",
3337 "pull-stream": "^3.6.2",
3438 "ssb-msg-content": "^1.0.1",
3539 "ssb-msg-schemas": "^6.3.0",
3640 "ssb-poll-schema": "^1.6.1",
poll/async/get.jsView
@@ -117,9 +117,9 @@
117117 .filter(msg => isPosition(msg) && !isPosition[type](msg))
118118 .map(position => {
119119 return {
120120 type: ERROR_POSITION_TYPE,
121- message: `Position responses need to be off the ${type} type for this poll`,
121+ message: `Position responses need to be of the ${type} type for this poll`,
122122 position
123123 }
124124 })
125125
poll/obs/get.jsView
@@ -1,59 +1,29 @@
11 const pull = require('pull-stream')
2-const PullNotify = require('pull-notify')
32 const sort = require('ssb-sort')
43 const { Struct, Value, Array: MutantArray, computed, resolve } = require('mutant')
54 const getContent = require('ssb-msg-content')
65 const { isPoll, isPosition, isChooseOnePoll, isPollUpdate, isChooseOnePosition } = require('ssb-poll-schema')
76 isPoll.chooseOne = isChooseOnePoll
87 isPosition.chooseOne = isChooseOnePosition
98 const buildResults = require('../../results/sync/buildResults')
109 const { CHOOSE_ONE } = require('../../types')
11-
12-// PollDoc is a mutant that initially only has the value sync false
13-// Which things need to be observabel?
14-// - Positions
15-// - Errors (these are the position errors that are not valid positions that should still be displayed somehow)
16-// - ClosesAt
17-// - Results (but that's computed from positions & closing time.
18-//
19-// Things that are not observable and can all live in one Value which will get set just once.:
20-// - title, author, body, channel, mentions, recps, the original poll message.
21-// {
22-// sync: boolean, (initially false until the value gets set)
23-// poll: MutantValue({
24-// title: '',
25-// author: '',
26-// body: '',
27-// channel: '',
28-// mentions: '',
29-// recps: '',
30-// value: {...poll msg}
31-// }),
32-// closesAt: MutantValue('date string'),
33-// positions: MutantArray(), (sorted in causal order)
34-// results: MutantStruct(),A computed obs of positions
35-// errors
36-// }
37-// The shape of this object is different to the one returned by async.get. Ugh.
38-
3910 module.exports = function (server) {
4011 return function get (key) {
4112 const myKey = server.id
4213
4314 const positions = MutantArray([])
44- const myPositions = MutantArray([])
4515 const closingTimes = MutantArray([])
4616 const sortedClosingTimes = computed(closingTimes, sort)
4717 const sortedPositions = computed(positions, sort)
18+ const myPosition = computed(sortedPositions, (positions) => {
19+ const myPositions = positions.filter(position => position.value.author === myKey)
20+ return myPositions.pop()
21+ })
4822 const closesAt = computed(sortedClosingTimes, (times) => {
4923 const time = times.pop()
5024 return time ? time.value.content.closesAt : ''
5125 })
52- const myPosition = computed(myPositions, (positions) => {
53- const sortedPositions = sort(positions)
54- return sortedPositions.pop()
55- })
5626
5727 const poll = Value({})
5828 const results = computed(sortedPositions, (positions) => {
5929 const resultsErrors = buildResults({ poll: resolve(poll), positions })
@@ -61,9 +31,10 @@
6131 })
6232
6333 const errors = computed(sortedPositions, (positions) => {
6434 const resultsErrors = buildResults({ poll: resolve(poll), positions })
65- return resultsErrors ? resultsErrors.errors : {}
35+ if (resultsErrors && resultsErrors.errors) { }
36+ return resultsErrors ? resultsErrors.errors : []
6637 })
6738
6839 const pollDoc = Struct({
6940 sync: false,
@@ -84,67 +55,60 @@
8455 // give subscribers a chance to start listening so they don't miss updates.
8556 setImmediate(function () {
8657 pollDoc.poll.set(decoratePoll(poll))
8758
88- const refs = PullNotify()
89-
9059 pull(
91- createBacklinkStream(key),
92- pull.drain(refs)
93- )
60+ createBacklinkStream(key, {live: false, old: true}),
61+ pull.collect((err, refs) => {
62+ if (!err) {
63+ const sorted = sort(refs)
64+ const decoratedPosition = sorted
65+ .filter(isPosition)
66+ .map(DecoratePosition(poll))
9467
95- // don't sync obs until we got sync from the stream to save some renders.
96- pull(
97- refs.listen(),
98- pull.filter(ref => ref.sync),
99- pull.drain(() => {
100- // allow the other streams to update their observables before sync goes true
101- setImmediate(() => pollDoc.sync.set(true))
68+ positions.set(decoratedPosition)
69+ // push in the closing time from the poll object and then update if there are updates published.
70+ closingTimes.push(poll)
71+
72+ // don't sync obs until we got sync from the stream to save some renders.
73+ setImmediate(() => pollDoc.sync.set(true))
74+ }
10275 })
10376 )
10477
10578 pull(
106- refs.listen(),
107- pull.filter(isPosition[CHOOSE_ONE]), // TODO: this shouldn't be hard coded
108- pull.map(position => {
109- return decoratePosition({position, poll})
110- }),
111- pull.drain((position) => {
112- positions.push(position)
113- })
79+ createBacklinkStream(key, {old: false, live: true}),
80+ pull.filter(isPosition),
81+ pull.map(DecoratePosition(poll)),
82+ pull.drain(positions.push)
11483 )
11584
116- // push in the closing time from the poll object and then update if there are updates published.
117- closingTimes.push(poll)
11885 pull(
119- refs.listen(),
86+ createBacklinkStream(key, {old: false, live: true}),
12087 pull.filter(isPollUpdate),
121- pull.drain(at => closingTimes.push(at))
88+ pull.drain(closingTimes.push)
12289 )
123-
124- pull(
125- refs.listen(),
126- pull.filter(isPosition[CHOOSE_ONE]),
127- pull.filter(position => position.value.author === myKey),
128- pull.drain(mine => myPositions.push(mine))
129- )
13090 })
13191 })
13292 return pollDoc
13393 }
13494
135- function createBacklinkStream (key) {
95+ function createBacklinkStream (key, opts) {
96+ opts = opts || {
97+ live: true,
98+ old: true
99+ }
100+
136101 var filterQuery = {
137102 $filter: {
138103 dest: key
139104 }
140105 }
141106
142- return server.backlinks.read({
107+ return server.backlinks.read(Object.assign({
143108 query: [filterQuery],
144- live: true,
145109 index: 'DTA' // use asserted timestamps
146- })
110+ }, opts))
147111 }
148112 }
149113
150114 function decoratePoll (rawPoll) {
@@ -172,8 +136,12 @@
172136
173137 return poll
174138 }
175139
140+function DecoratePosition (poll) {
141+ return (position) => decoratePosition({position, poll})
142+}
143+
176144 function decoratePosition ({position: rawPosition, poll: rawPoll}) {
177145 var position = getContent(rawPosition)
178146 var poll = getContent(rawPoll)
179147
results/sync/buildResults.jsView
@@ -1,8 +1,9 @@
11 const getContent = require('ssb-msg-content')
2-const { isChooseOnePoll } = require('ssb-poll-schema')
2+const { isChooseOnePoll, isPosition } = require('ssb-poll-schema')
33 const PositionChoiceError = require('../../errors/sync/positionChoiceError')
44 const PositionLateError = require('../../errors/sync/positionLateError')
5+const PositionTypeError = require('../../errors/sync/positionTypeError')
56
67 // Expects `poll` and `position` objects passed in to be of shape:
78 // {
89 // key,
@@ -36,8 +37,14 @@
3637 return positions.reduce(function (acc, position) {
3738 const { author } = position.value
3839 const { choice } = getContent(position).details
3940
41+ if (isInvalidType({position, poll})) {
42+ console.log('got an aninvalid position type')
43+ acc.errors.push(PositionTypeError({position}))
44+ return acc
45+ }
46+
4047 if (isInvalidChoice({position, poll})) {
4148 acc.errors.push(PositionChoiceError({position}))
4249 return acc
4350 }
@@ -63,12 +70,20 @@
6370 }
6471 })
6572 }
6673
74+function isInvalidType ({position, poll}) {
75+ // TODO:this is super fragile. We should be using a parsed or decorated poll
76+ const pollType = poll.value.content.details.type
77+ return !isPosition[pollType](position)
78+}
79+
6780 function isInvalidChoice ({position, poll}) {
6881 const { choice } = position.value.content.details
82+ // TODO:this is super fragile. We should be using a parsed or decorated poll
6983 return choice >= poll.value.content.details.choices.length
7084 }
7185
7286 function isPositionLate ({position, poll}) {
87+ // TODO:this is super fragile. We should be using a parsed or decorated poll
7388 return position.value.timestamp > poll.value.content.closesAt
7489 }
test/poll/obs/get.test.jsView
@@ -10,8 +10,9 @@
1010 const server = Server()
1111
1212 const katie = server.createFeed()
1313 const piet = server.createFeed()
14+const me = server.whoami()
1415
1516 const pollContent = ChooseOnePoll({
1617 title: "what's our mascott team?",
1718 choices: ['prairie dog', 'kea', 'hermit crab'],
@@ -21,9 +22,9 @@
2122 const agesAway = nDaysTime(100)
2223 const soSoon = nDaysTime(1)
2324
2425 test('poll.obs.get', t => {
25- t.plan(16)
26+ t.plan(17)
2627 piet.publish(pollContent, (err, poll) => {
2728 t.error(err)
2829 const pollDoc = getPoll(server)(poll.key)
2930
@@ -60,21 +61,30 @@
6061 })
6162
6263 pollDoc.results(function (results) {
6364 if (results[1].voters[katie.id] && results[2].voters[piet.id]) {
65+ // we hit this test twice. Not super nice but not worth fixing now.
6466 t.ok(true, 'results eventually are correct')
6567 }
6668 })
6769
70+ pollDoc.errors(function (errors) {
71+ console.log('got an error', errors)
72+ })
73+
6874 pull(
6975 pull.values([
7076 { author: katie, opts: { poll, choice: 1, reason: 'they are sick!' } },
71- { author: piet, opts: { poll, choice: 2, reason: 'scuttles 4life' } }
77+ { author: piet, opts: { poll, choice: 2, reason: 'scuttles 4life' } },
78+ { author: piet, opts: { poll, choice: 2, reason: 'INVALID' } }
7279 ]),
7380 pull.asyncMap((t, cb) => {
7481 // NOTE: piet.get does not exist, so have to build using the master server
7582 ChooseOnePosition(server)(t.opts, (err, position) => {
7683 if (err) return cb(err)
84+ if (position.reason === 'INVALID') {
85+ position.details.choice = 1000
86+ }
7787 t.position = position
7888 cb(null, t)
7989 })
8090 }),

Built with git-ssb-web