Skip to content

Commit ebc33bf

Browse files
committed
🎵 when two become oonneeeee 🎵
1 parent 5fcd8b5 commit ebc33bf

File tree

2 files changed

+40
-53
lines changed

2 files changed

+40
-53
lines changed

‎src/dispatcher.js

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import * as orderedHistory from './orderedHistory'
44

55
import {
66
// action constants
7-
UPDATE_TIMESTAMP,
8-
UPDATE_SOURCE,
7+
UPDATE_ACTION,
98

109
META_TIMESTAMP,
1110
META_SOURCE
@@ -77,16 +76,16 @@ export default class Dispatcher extends Scuttlebutt {
7776

7877
this._isGossipType = this.options.isGossipType
7978

80-
// history of all current updates
81-
// timestamp-source-sorted for time travel and replay
82-
this._updates = []
8379

8480
// redux methods to wrap
8581
this._reduxDispatch = () => {
8682
throw new Error('Are you sure you called wrapDispatch?')
8783
}
8884
this._reduxGetState = () => {
89-
throw new Error('Are you sure you called wrapGetState?')
85+
// throw new Error('Are you sure you called wrapGetState?')
86+
// this must return a default state for the very first history call,
87+
// before .wrapGetState has been applied in the store enhancer.
88+
return []
9089
}
9190
}
9291

@@ -131,44 +130,50 @@ export default class Dispatcher extends Scuttlebutt {
131130
// implemented for scuttlebutt class
132131
applyUpdate(update) {
133132
const [action, timestamp, source] = update,
134-
// add our metadata to the action
135-
localAction = {
136-
...action,
137-
meta: {
138-
...action.meta,
139-
[META_TIMESTAMP]: timestamp,
140-
[META_SOURCE]: source
133+
// copy the object so we can modify its properties later
134+
localAction = { meta: {}, ...action },
135+
dispatch = (shouldApply) => {
136+
if (!shouldApply) {
137+
return
138+
} else if (this._customDispatch) {
139+
this._customDispatch(localAction)
140+
} else {
141+
this._reduxDispatch(localAction)
141142
}
142143
}
143144

144-
// we log all updates to emit in the order we saw them.
145-
// not sure if it's better than replaying in order of timestamp (which might
146-
// cut down on the amount of time travelling done by all peers), but seems
147-
// like the de facto for scuttlebutt models
148-
this._updates.push(update)
149-
150-
// this could be sped up by only sorting as far as the new update
151-
this._updates.sort((a, b) => orderedHistory.sort(
152-
a[UPDATE_TIMESTAMP], b[UPDATE_TIMESTAMP],
153-
a[UPDATE_SOURCE], b[UPDATE_SOURCE]
154-
))
145+
// add our metadata to the action as non-enumerable properties
146+
Object.defineProperty(localAction.meta, META_TIMESTAMP, {
147+
enumerable: false,
148+
value: timestamp
149+
})
150+
Object.defineProperty(localAction.meta, META_SOURCE, {
151+
enumerable: false,
152+
value: source
153+
})
155154

156-
if (this._customDispatch) {
157-
this._customDispatch(localAction)
158-
} else {
159-
this._reduxDispatch(localAction)
160-
}
155+
dispatch(true)
161156

162157
// recieved message succesfully. if false, peers may retry the message.
163158
return true
164159
}
165160

166-
// gossip
161+
// reply to gossip with the latest timestamps for the sources we've seen
167162
// implemented for scuttlebutt class
168163
history(sources) {
169-
return this._updates.filter(function(update) {
170-
return filter(update, sources)
171-
})
164+
// our state (updates[]) has a similar shape to scuttlebutt's own updates.
165+
return this._reduxGetState().reduce((arr, update) => {
166+
if (
167+
update[UPDATE_ACTION]
168+
&& this._isGossipType(update[UPDATE_ACTION].type)
169+
&& filter(update, sources)
170+
) {
171+
// scuttlebutt only wants ACTION, TIMESTAMP, SOURCE, and not: SNAPSHOT
172+
arr.push(update.slice(0, 3))
173+
}
174+
175+
return arr
176+
}, [])
172177
}
173178

174179
// apply an update locally
@@ -186,23 +191,4 @@ export default class Dispatcher extends Scuttlebutt {
186191
super.localUpdate(action)
187192
}
188193
}
189-
190-
// super.localUpdate(this._filterUpdate(action))
191-
// Recurse through the value and attempt to prune unserializable leaf objects.
192-
// A well-structured app won't be dispatching bad actions like this, so
193-
// this might become a dev-only check. also, it's far from foolproof.
194-
_filterUpdate(value) {
195-
if (typeof value !== 'object')
196-
return value
197-
198-
if (value && value.constructor
199-
&& /(^Synthetic|Event$)/.test(value.constructor.name))
200-
return null
201-
202-
const result = {}
203-
for (const prop in value) {
204-
result[prop] = this._filterUpdate(value[prop]);
205-
}
206-
return result
207-
}
208194
}

‎src/server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ function connectRedux(gossip) {
164164
const Redux = require('redux'),
165165
reducer = (state = [], action) => state.concat(action),
166166
store = Redux.createStore(gossip.wrapReducer(reducer), undefined),
167-
dispatch = gossip.wrapDispatch(store.dispatch)
167+
dispatch = gossip.wrapDispatch(store.dispatch),
168+
getState = gossip.wrapGetState(store.getState)
168169

169170
// other things we might want to do ->
170171
// store.subscribe(render)

0 commit comments

Comments
 (0)