1 |
|
2 | (function() {
|
3 |
|
4 |
|
5 | var CouchDB, EventEmitter2, EventSource, LRU, URL, agent, autoRestart, ec, fromEventSource, http, https, lru_cache, lru_dispose, most, options, sleep, static_cache;
|
6 |
|
7 | LRU = require('lru-cache');
|
8 |
|
9 | ({EventEmitter2} = require('eventemitter2'));
|
10 |
|
11 | http = require('http');
|
12 |
|
13 | https = require('https');
|
14 |
|
15 | lru_dispose = new EventEmitter2({
|
16 | newListener: false,
|
17 | verboseMemoryLeak: true
|
18 | });
|
19 |
|
20 | options = {
|
21 | max: 200,
|
22 | dispose: function(key) {
|
23 | return ev.emit(key);
|
24 | },
|
25 | maxAge: 20 * 60 * 1000
|
26 | };
|
27 |
|
28 | lru_cache = LRU(options);
|
29 |
|
30 | static_cache = new Map();
|
31 |
|
32 | CouchDB = class CouchDB {
|
33 | constructor(uri, use_lru) {
|
34 | if (uri.match(/\/$/)) {
|
35 | this.uri = uri;
|
36 | } else {
|
37 | this.uri = `${uri}/`;
|
38 | }
|
39 | if (use_lru) {
|
40 | this.cache = lru_cache;
|
41 | this.limit = most.fromEvent(this.uri, lru_dispose);
|
42 | } else {
|
43 | this.cache = static_cache;
|
44 | this.limit = most.never();
|
45 | }
|
46 | switch (false) {
|
47 | case !uri.match(/^http:/):
|
48 | this.agent = agent.agent(http.globalAgent);
|
49 | break;
|
50 | case !uri.match(/^https:/):
|
51 | this.agent = agent.agent(https.globalAgent);
|
52 | break;
|
53 | default:
|
54 | this.agent = agent;
|
55 | }
|
56 | return;
|
57 | }
|
58 |
|
59 | put(doc) {
|
60 | var _id, uri;
|
61 | ({_id} = doc);
|
62 | uri = new URL(ec(_id), this.uri);
|
63 | return this.agent.put(uri.toString()).type('json').accept('json').send(doc).then(function({body}) {
|
64 | return body;
|
65 | });
|
66 | }
|
67 |
|
68 | get(_id, {rev} = {}) {
|
69 | var uri;
|
70 | uri = new URL(ec(_id), this.uri);
|
71 | if (rev != null) {
|
72 | uri.searchParams.set('rev', rev);
|
73 | }
|
74 | return this.agent.get(uri.toString()).accept('json').then(function({body}) {
|
75 | return body;
|
76 | });
|
77 | }
|
78 |
|
79 | delete({_id, _rev}) {
|
80 | var uri;
|
81 | uri = new URL(ec(_id), this.uri);
|
82 | if (_rev != null) {
|
83 | uri.searchParams.set('rev', _rev);
|
84 | }
|
85 | return this.agent.delete(uri.toString()).accept('json').then(function({body}) {
|
86 | return body;
|
87 | });
|
88 | }
|
89 |
|
90 | changes(options = {}) {
|
91 | var include_docs, live, s, since, stream, uri;
|
92 | ({live, include_docs, since} = options);
|
93 | if (live == null) {
|
94 | live = true;
|
95 | }
|
96 | if (live !== true) {
|
97 | throw new Error('Only live streaming is supported');
|
98 | }
|
99 | if (this.cache.has(this.uri)) {
|
100 | return this.cache.get(this.uri);
|
101 | }
|
102 | if (since == null) {
|
103 | since = 'now';
|
104 | }
|
105 | uri = new URL('_changes', this.uri);
|
106 | uri.searchParams.set('feed', 'eventsource');
|
107 | uri.searchParams.set('heartbeat', true);
|
108 | uri.searchParams.set('include_docs', include_docs != null ? include_docs : false);
|
109 |
|
110 |
|
111 | s = function() {
|
112 | uri.searchParams.set('since', since);
|
113 | return fromEventSource(new EventSource(uri.toString())).continueWith(function() {
|
114 | console.error('retry', uri.host, uri.pathname, since);
|
115 | return most.never();
|
116 | }).recoverWith(function(error) {
|
117 | var ref;
|
118 | console.error('retry', (ref = error.stack) != null ? ref : error, uri.host, uri.pathname, since);
|
119 | return most.never();
|
120 | });
|
121 | };
|
122 | stream = autoRestart(s).map(function({data}) {
|
123 | return data;
|
124 | }).map(JSON.parse).tap(function({seq}) {
|
125 | if (seq != null) {
|
126 | return since = seq;
|
127 | }
|
128 | }).until(this.limit).multicast();
|
129 | this.cache.set(this.uri, stream);
|
130 | return stream;
|
131 | }
|
132 |
|
133 | };
|
134 |
|
135 | module.exports = CouchDB;
|
136 |
|
137 | ec = encodeURIComponent;
|
138 |
|
139 | most = require('most');
|
140 |
|
141 | EventSource = require('eventsource');
|
142 |
|
143 | ({fromEventSource} = require('most-w3msg'));
|
144 |
|
145 | ({URL} = require('url'));
|
146 |
|
147 | agent = require('superagent');
|
148 |
|
149 |
|
150 | sleep = function(timeout) {
|
151 | return new Promise(function(resolve) {
|
152 | return setTimeout(resolve, timeout);
|
153 | });
|
154 | };
|
155 |
|
156 | autoRestart = function(s) {
|
157 | return most.generate(function*() {
|
158 | return (yield 200);
|
159 | }).startWith(0).map(async function(delay) {
|
160 | await sleep(delay);
|
161 | return s();
|
162 | }).chain(most.fromPromise).switchLatest();
|
163 | };
|
164 |
|
165 | }).call(this);
|