Skip to content

Commit 4eb737a

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

File tree

2 files changed

+39
-51
lines changed

2 files changed

+39
-51
lines changed

‎src/dispatcher.js

+37-50
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,16 @@ export default class Dispatcher extends Scuttlebutt {
7777

7878
this._isGossipType = this.options.isGossipType
7979

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

8481
// redux methods to wrap
8582
this._reduxDispatch = () => {
8683
throw new Error('Are you sure you called wrapDispatch?')
8784
}
8885
this._reduxGetState = () => {
89-
throw new Error('Are you sure you called wrapGetState?')
86+
// throw new Error('Are you sure you called wrapGetState?')
87+
// this must return a default state for the very first history call,
88+
// before .wrapGetState has been applied in the store enhancer.
89+
return []
9090
}
9191
}
9292

@@ -131,44 +131,50 @@ export default class Dispatcher extends Scuttlebutt {
131131
// implemented for scuttlebutt class
132132
applyUpdate(update) {
133133
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
134+
// copy the object so we can modify its properties later
135+
localAction = { meta: {}, ...action },
136+
dispatch = (shouldApply) => {
137+
if (!shouldApply) {
138+
return
139+
} else if (this._customDispatch) {
140+
this._customDispatch(localAction)
141+
} else {
142+
this._reduxDispatch(localAction)
141143
}
142144
}
143145

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-
))
146+
// add our metadata to the action as non-enumerable properties
147+
Object.defineProperty(localAction.meta, META_TIMESTAMP, {
148+
enumerable: false,
149+
value: timestamp
150+
})
151+
Object.defineProperty(localAction.meta, META_SOURCE, {
152+
enumerable: false,
153+
value: source
154+
})
155155

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

162158
// recieved message succesfully. if false, peers may retry the message.
163159
return true
164160
}
165161

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

174180
// apply an update locally
@@ -186,23 +192,4 @@ export default class Dispatcher extends Scuttlebutt {
186192
super.localUpdate(action)
187193
}
188194
}
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-
}
208195
}

‎src/server.js

+2-1
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)