export default class Subscription { constructor(store, api, channel) { this.store = store; this.api = api; this.channel = channel; this.channel.setOnChannelError(this.onChannelError.bind(this)); this.firstRoundComplete = false; } start() { if (this.api.ship) { this.firstRound(); } else { console.error('~~~ ERROR: Must set api.ship before operation ~~~'); } this.setupSlog(); } setupSlog() { const slog = new EventSource('/~/slog', { withCredentials: true }); let available = false; slog.onopen = e => { console.log('slog: opened stream'); available = true; } slog.onmessage = e => { this.handleEvent({ txt: e.data }); } slog.onerror = e => { console.error('slog: eventsource error:', e); if (!available) { this.handleEvent({ txt: 'landscape: no printf stream. bad connection or old binary.' }); } else { window.setTimeout(() => { if (slog.readyState !== EventSource.CLOSED) return; console.log('slog: reconnecting...'); this.setupSlog(); }, 10000); } } } delete() { this.channel.delete(); } onChannelError(err) { console.error('event source error: ', err); console.log('initiating new channel'); this.firstRoundComplete = false; setTimeout(2000, () => { this.store.handleEvent({ data: { clear : true } }); this.start(); }); } subscribe(path, app) { this.api.bind(path, 'PUT', this.api.ship, app, this.handleEvent.bind(this), (err) => { console.log(err); this.subscribe(path, app); }, () => { this.subscribe(path, app); }); } firstRound() { this.subscribe('/sole/' + this.api.dojoId, 'dojo'); } handleEvent(diff) { this.store.handleEvent(diff); } }