ui: Small EventSource additions (#5978)

1. EventSources now pass themselves thorugh to the run function as a
second argument. This enables the use of arrow functions along with the
EventSources API
`(configuration, source) => source.close()`. Order of arguments could
potentially be switched at a later date.
2. BlockingEventSources now let you pass an 'event' through at
instantation time. If you do this, the event will immediately be dispatched
once the EventSource is opened. The usecase for this is for 'unfreezing' cached
BlockingEvents. This makes it easier to provide a cache for
BlockingEventSources by caching its data rather than the entire
BlockingEventSource itself.

```
new BlockingEventSource(
  (config, source) => { /* something */ },
  {
    cursor: 1024, // this would also come from a cache
    currentEvent: getFromSomeSortOfCache(eventSourceId) //this is the new bit
  }
);

// more realistically

new BlockingEventSource(
  (config, source) => { return data.findSomething(slug, config) },
  getFromSomeSortOfCache(eventSourceId)
);

```
This commit is contained in:
John Cowen 2019-06-20 10:23:36 +01:00 committed by John Cowen
parent 32387fdbcf
commit 01d1b3c139
2 changed files with 21 additions and 7 deletions

View File

@ -70,10 +70,11 @@ export default function(EventSource, backoff = create5xxBackoff()) {
*/
return class extends EventSource {
constructor(source, configuration = {}) {
const { currentEvent, ...config } = configuration;
super(configuration => {
const { createEvent, ...superConfiguration } = configuration;
return source
.apply(this, [superConfiguration])
.apply(this, [superConfiguration, this])
.catch(backoff)
.then(result => {
if (result instanceof Error) {
@ -103,7 +104,19 @@ export default function(EventSource, backoff = create5xxBackoff()) {
this.previousEvent = this.currentEvent;
return throttledResolve(result);
});
}, configuration);
}, config);
if (typeof currentEvent !== 'undefined') {
this.currentEvent = currentEvent;
}
// only on initialization
// if we already have an currentEvent set via configuration
// dispatch the event so things are populated immediately
this.addEventListener('open', e => {
const currentEvent = e.target.getCurrentEvent();
if (typeof currentEvent !== 'undefined') {
this.dispatchEvent(currentEvent);
}
});
}
// if we are having these props, at least make getters
getCurrentEvent() {

View File

@ -5,7 +5,7 @@ export const defaultRunner = function(target, configuration, isClosed) {
}
// TODO Consider wrapping this is a promise for none thenable returns
return target.source
.bind(target)(configuration)
.bind(target)(configuration, target)
.then(function(res) {
return defaultRunner(target, configuration, isClosed);
});
@ -36,7 +36,7 @@ export default function(
this.readyState = 2;
this.source =
typeof source !== 'function'
? function(configuration) {
? function(configuration, target) {
this.close();
return P.resolve();
}
@ -45,7 +45,7 @@ export default function(
P.resolve()
.then(() => {
// if we are already closed, don't do anything
if (this.readyState !== 0) {
if (this.readyState > 1) {
return;
}
this.readyState = 1; // open
@ -68,13 +68,14 @@ export default function(
close() {
// additional readyState 3 = CLOSING
switch (this.readyState) {
case 0: // CONNECTING
case 2: // CLOSED
this.readyState = 2; // CLOSED
// it's already CLOSED , do nothing
break;
default:
this.readyState = 3; // CLOSING
}
// non-standard
return this;
}
};
}