1 | 'use strict'
|
2 |
|
3 | const EventEmitter = require('events').EventEmitter
|
4 | const util = require('util')
|
5 |
|
6 | const assert = require('assert-plus')
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | const PagedControl = require('../controls/paged_results_control.js')
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | function SearchPager (opts) {
|
35 | assert.object(opts)
|
36 | assert.func(opts.callback)
|
37 | assert.number(opts.pageSize)
|
38 |
|
39 | EventEmitter.call(this, {})
|
40 |
|
41 | this.callback = opts.callback
|
42 | this.controls = opts.controls
|
43 | this.pageSize = opts.pageSize
|
44 | this.pagePause = opts.pagePause
|
45 |
|
46 | this.controls.forEach(function (control) {
|
47 | if (control.type === PagedControl.OID) {
|
48 |
|
49 |
|
50 | throw new Error('redundant pagedResultControl')
|
51 | }
|
52 | })
|
53 |
|
54 | this.finished = false
|
55 | this.started = false
|
56 |
|
57 | const emitter = new EventEmitter()
|
58 | emitter.on('searchEntry', this.emit.bind(this, 'searchEntry'))
|
59 | emitter.on('end', this._onEnd.bind(this))
|
60 | emitter.on('error', this._onError.bind(this))
|
61 | this.childEmitter = emitter
|
62 | }
|
63 | util.inherits(SearchPager, EventEmitter)
|
64 | module.exports = SearchPager
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | SearchPager.prototype.begin = function begin () {
|
70 |
|
71 | this._nextPage(null)
|
72 | }
|
73 |
|
74 | SearchPager.prototype._onEnd = function _onEnd (res) {
|
75 | const self = this
|
76 | let cookie = null
|
77 | res.controls.forEach(function (control) {
|
78 | if (control.type === PagedControl.OID) {
|
79 | cookie = control.value.cookie
|
80 | }
|
81 | })
|
82 |
|
83 | const nullCb = function () { }
|
84 |
|
85 | if (cookie === null) {
|
86 |
|
87 | this.finished = true
|
88 | this.emit('page', res, nullCb)
|
89 | const err = new Error('missing paged control')
|
90 | err.name = 'PagedError'
|
91 | if (this.listeners('pageError').length > 0) {
|
92 | this.emit('pageError', err)
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | this.emit('end', res)
|
98 | } else {
|
99 | this.emit('error', err)
|
100 |
|
101 | }
|
102 | return
|
103 | }
|
104 |
|
105 | if (cookie.length === 0) {
|
106 |
|
107 | this.finished = true
|
108 | this.emit('page', nullCb)
|
109 | this.emit('end', res)
|
110 | } else {
|
111 | if (this.pagePause) {
|
112 |
|
113 |
|
114 | this.emit('page', res, function (err) {
|
115 | if (!err) {
|
116 | self._nextPage(cookie)
|
117 | } else {
|
118 |
|
119 | self.emit('end', res)
|
120 | }
|
121 | })
|
122 | } else {
|
123 | this.emit('page', res, nullCb)
|
124 | this._nextPage(cookie)
|
125 | }
|
126 | }
|
127 | }
|
128 |
|
129 | SearchPager.prototype._onError = function _onError (err) {
|
130 | this.finished = true
|
131 | this.emit('error', err)
|
132 | }
|
133 |
|
134 |
|
135 |
|
136 |
|
137 | SearchPager.prototype._nextPage = function _nextPage (cookie) {
|
138 | const controls = this.controls.slice(0)
|
139 | controls.push(new PagedControl({
|
140 | value: {
|
141 | size: this.pageSize,
|
142 | cookie: cookie
|
143 | }
|
144 | }))
|
145 |
|
146 | this.emit('search', controls, this.childEmitter,
|
147 | this._sendCallback.bind(this))
|
148 | }
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | SearchPager.prototype._sendCallback = function _sendCallback (err, res) {
|
154 | if (err) {
|
155 | this.finished = true
|
156 | if (!this.started) {
|
157 |
|
158 | this.callback(err, null)
|
159 | } else {
|
160 | this.emit('error', err)
|
161 | }
|
162 | } else {
|
163 |
|
164 | if (!this.started) {
|
165 | this.started = true
|
166 |
|
167 | this.callback(null, this)
|
168 | }
|
169 | }
|
170 | }
|