2016-06-23 15:49:22 +08:00
|
|
|
const Rx = require('rx')
|
|
|
|
const redis = require("redis");
|
2016-06-24 02:45:24 +08:00
|
|
|
|
|
|
|
const SyncPolicy = require('./sync-policy');
|
|
|
|
|
2016-06-24 06:52:45 +08:00
|
|
|
Promise.promisifyAll(redis.RedisClient.prototype);
|
|
|
|
Promise.promisifyAll(redis.Multi.prototype);
|
2016-06-23 15:49:22 +08:00
|
|
|
|
|
|
|
class PubsubConnector {
|
|
|
|
constructor() {
|
|
|
|
this._broadcastClient = null;
|
|
|
|
this._listenClient = null;
|
|
|
|
this._listenClientSubs = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
buildClient() {
|
|
|
|
const client = redis.createClient(process.env.REDIS_URL || null);
|
|
|
|
client.on("error", console.error);
|
|
|
|
return client;
|
|
|
|
}
|
|
|
|
|
|
|
|
broadcastClient() {
|
|
|
|
if (!this._broadcastClient) {
|
|
|
|
this._broadcastClient = this.buildClient();
|
|
|
|
}
|
|
|
|
return this._broadcastClient;
|
|
|
|
}
|
|
|
|
|
|
|
|
channelForAccount(accountId) {
|
|
|
|
return `a-${accountId}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
channelForAccountDeltas(accountId) {
|
2016-06-24 06:52:45 +08:00
|
|
|
return `deltas-${accountId}`;
|
2016-06-23 15:49:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shared channel
|
|
|
|
|
|
|
|
notifyAccountChange(accountId) {
|
|
|
|
const channel = this.channelForAccount(accountId);
|
|
|
|
this.broadcastClient().publish(channel, 'modified');
|
|
|
|
}
|
|
|
|
|
|
|
|
observableForAccountChanges(accountId) {
|
|
|
|
if (!this._listenClient) {
|
|
|
|
this._listenClient = this.buildClient();
|
|
|
|
this._listenClientSubs = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const channel = this.channelForAccount(accountId);
|
|
|
|
return Rx.Observable.create((observer) => {
|
|
|
|
this._listenClient.on("message", (msgChannel, message) => {
|
|
|
|
if (msgChannel !== channel) { return }
|
|
|
|
observer.onNext(message)
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!this._listenClientSubs[channel]) {
|
|
|
|
this._listenClientSubs[channel] = 1;
|
|
|
|
this._listenClient.subscribe(channel);
|
|
|
|
} else {
|
|
|
|
this._listenClientSubs[channel] += 1;
|
|
|
|
}
|
|
|
|
return () => {
|
|
|
|
this._listenClientSubs[channel] -= 1;
|
|
|
|
if (this._listenClientSubs[channel] === 0) {
|
|
|
|
this._listenClient.unsubscribe(channel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Account (delta streaming) channels
|
|
|
|
|
|
|
|
notifyAccountDeltas(accountId, data) {
|
|
|
|
const channel = this.channelForAccountDeltas(accountId);
|
|
|
|
this.broadcastClient().publish(channel, JSON.stringify(data))
|
|
|
|
}
|
|
|
|
|
|
|
|
observableForAccountDeltas(accountId) {
|
|
|
|
return Rx.Observable.create((observer) => {
|
|
|
|
const sub = this.buildClient();
|
|
|
|
sub.on("message", (channel, message) => observer.onNext(message));
|
|
|
|
sub.subscribe(this.channelForAccountDeltas(accountId));
|
|
|
|
return () => {
|
|
|
|
sub.unsubscribe();
|
|
|
|
sub.quit();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2016-06-24 06:46:52 +08:00
|
|
|
|
|
|
|
queueSyncbackTask({taskName, props}) {
|
|
|
|
const channel = this.channelForSyncbackTaskQueue(accountId);
|
|
|
|
this.broadcastClient().publish(channel, JSON.stringify(data))
|
|
|
|
}
|
2016-06-23 15:49:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = new PubsubConnector()
|