git ssb

0+

Piet / ssb-loomio



Tree: c46ad9c39623cd98b6cbb308d0c0870f15ff701c

Files: c46ad9c39623cd98b6cbb308d0c0870f15ff701c / poll / obs / get.js

4985 bytesRaw
1const pull = require('pull-stream')
2const sort = require('ssb-sort')
3const { Struct, Value, Array: MutantArray, computed, resolve } = require('mutant')
4const getContent = require('ssb-msg-content')
5const { isPoll, isPosition, isChooseOnePoll, isPollUpdate, isChooseOnePosition } = require('ssb-poll-schema')
6isPoll.chooseOne = isChooseOnePoll
7isPosition.chooseOne = isChooseOnePosition
8const buildResults = require('../../results/sync/buildResults')
9
10module.exports = function (server) {
11 return function get (key) {
12 const myKey = server.id
13
14 const positions = MutantArray([])
15 const closingTimes = MutantArray([])
16 const sortedClosingTimes = computed(closingTimes, sort)
17 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 })
22 const closesAt = computed(sortedClosingTimes, (times) => {
23 const time = times.pop()
24 return time ? time.value.content.closesAt : ''
25 })
26
27 // This is ugly, would all be done by pollDoc. Refactor in the future.
28 const pollObs = Value({})
29
30 const results = computed(sortedPositions, (positions) => {
31 const resultsErrors = buildResults({ poll: resolve(pollObs), positions })
32 return resultsErrors ? resultsErrors.results : []
33 })
34
35 const errors = computed(sortedPositions, (positions) => {
36 const resultsErrors = buildResults({ poll: resolve(pollObs), positions })
37 if (resultsErrors && resultsErrors.errors) { }
38 return resultsErrors ? resultsErrors.errors : []
39 })
40
41 function PollDoc (poll) {
42 poll = poll || {
43 key: '',
44 value: {
45 author: '',
46 content: {
47 title: '',
48 body: '',
49 channel: '',
50 details: {
51 type: 'UNKNOWN'
52 }
53 },
54 recps: [],
55 mentions: []
56 }
57 }
58
59 return Struct(Object.assign({}, decoratePoll(poll), {
60 sync: false,
61 closesAt,
62 myPosition,
63 positions: sortedPositions,
64 results,
65 errors
66 }))
67 }
68
69 const pollDoc = PollDoc()
70
71 server.get(key, (err, value) => {
72 if (err) return err
73
74 var poll = { key, value }
75 if (!isPoll(poll)) return new Error('scuttle-poll could not get poll, key provided was not a valid poll key')
76
77 // give subscribers a chance to start listening so they don't miss updates.
78 setImmediate(function () {
79 const decoratedPoll = decoratePoll(poll)
80 pollObs.set(decoratedPoll)
81
82 Object.keys(decoratedPoll).forEach(function (key) {
83 pollDoc[key].set(decoratedPoll[key])
84 })
85
86 pull(
87 createBacklinkStream(key, {live: false, old: true}),
88 pull.collect((err, refs) => {
89 if (!err) {
90 const sorted = sort(refs)
91 const decoratedPosition = sorted
92 .filter(isPosition)
93 .map(DecoratePosition(poll))
94
95 positions.set(decoratedPosition)
96 // push in the closing time from the poll object and then update if there are updates published.
97 closingTimes.push(poll)
98
99 setImmediate(() => pollDoc.sync.set(true))
100 }
101 })
102 )
103
104 pull(
105 createBacklinkStream(key, {old: false, live: true}),
106 pull.filter(isPosition),
107 pull.map(DecoratePosition(poll)),
108 pull.drain(positions.push)
109 )
110
111 pull(
112 createBacklinkStream(key, {old: true, live: true}),
113 pull.filter(isPollUpdate),
114 pull.drain(closingTimes.push)
115 )
116 })
117 })
118 return pollDoc
119 }
120
121 function createBacklinkStream (key, opts) {
122 opts = opts || {
123 live: true,
124 old: true
125 }
126
127 var filterQuery = {
128 $filter: {
129 dest: key
130 }
131 }
132
133 return server.backlinks.read(Object.assign({
134 query: [filterQuery],
135 index: 'DTA' // use asserted timestamps
136 }, opts))
137 }
138}
139
140function decoratePoll (rawPoll) {
141 const {
142 author,
143 content: {
144 title,
145 body,
146 channel,
147 details: { type }
148 },
149 recps,
150 mentions
151 } = rawPoll.value
152
153 const poll = Object.assign({}, rawPoll, {
154 type,
155 author,
156 title,
157 body,
158 channel,
159 recps,
160 mentions
161 })
162
163 return poll
164}
165
166function DecoratePosition (poll) {
167 return (position) => decoratePosition({position, poll})
168}
169
170function decoratePosition ({position: rawPosition, poll: rawPoll}) {
171 var position = getContent(rawPosition)
172 var poll = getContent(rawPoll)
173
174 // NOTE this isn't deep enough to be a safe clone
175 var newPosition = Object.assign({}, rawPosition)
176 newPosition.reason = position.reason
177
178 if (isPoll.chooseOne(poll)) {
179 var choiceIndex = position.details.choice
180 newPosition.choice = poll.details.choices[choiceIndex]
181 }
182 return newPosition
183}
184

Built with git-ssb-web