Merge branch 'master' into master
This commit is contained in:
commit
9b1a10fff0
|
@ -276,15 +276,15 @@ containing the following fields:
|
|||
|timeLimit |the maximum amount of time the server should take in responding, in seconds. Defaults to 10. Lots of servers will ignore this.|
|
||||
|paged |enable and/or configure automatic result paging|
|
||||
|
||||
Responses from the `search` method are an `EventEmitter` where you will get a
|
||||
notification for each `searchEntry` that comes back from the server. You will
|
||||
additionally be able to listen for a `searchReference`, `error` and `end` event.
|
||||
Note that the `error` event will only be for client/TCP errors, not LDAP error
|
||||
codes like the other APIs. You'll want to check the LDAP status code
|
||||
(likely for `0`) on the `end` event to assert success. LDAP search results
|
||||
can give you a lot of status codes, such as time or size exceeded, busy,
|
||||
inappropriate matching, etc., which is why this method doesn't try to wrap up
|
||||
the code matching.
|
||||
Responses inside callback of the `search` method are an `EventEmitter` where you will get a notification for
|
||||
each `searchEntry` that comes back from the server. You will additionally be able to listen for a `searchRequest`
|
||||
, `searchReference`, `error` and `end` event.
|
||||
`searchRequest` is emitted immediately after every `SearchRequest` is sent with a `SearchRequest` parameter. You can do operations
|
||||
like `client.abandon` with `searchRequest.messageID` to abandon this search request. Note that the `error` event will
|
||||
only be for client/TCP errors, not LDAP error codes like the other APIs. You'll want to check the LDAP status code
|
||||
(likely for `0`) on the `end` event to assert success. LDAP search results can give you a lot of status codes, such as
|
||||
time or size exceeded, busy, inappropriate matching, etc., which is why this method doesn't try to wrap up the code
|
||||
matching.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -298,6 +298,9 @@ const opts = {
|
|||
client.search('o=example', opts, (err, res) => {
|
||||
assert.ifError(err);
|
||||
|
||||
res.on('searchRequest', (searchRequest) => {
|
||||
console.log('searchRequest: ', searchRequest.messageID);
|
||||
});
|
||||
res.on('searchEntry', (entry) => {
|
||||
console.log('entry: ' + JSON.stringify(entry.object));
|
||||
});
|
||||
|
|
|
@ -630,9 +630,9 @@ Client.prototype.search = function search (base,
|
|||
callback: callback,
|
||||
controls: controls,
|
||||
pageSize: size,
|
||||
pagePause: pageOpts.pagePause
|
||||
pagePause: pageOpts.pagePause,
|
||||
sendRequest: sendRequest
|
||||
})
|
||||
pager.on('search', sendRequest)
|
||||
pager.begin()
|
||||
} else {
|
||||
sendRequest(controls, new CorkedEmitter(), callback)
|
||||
|
@ -1251,7 +1251,9 @@ Client.prototype._sendSocket = function _sendSocket (message,
|
|||
conn.end()
|
||||
} else if (emitter) {
|
||||
sentEmitter = true
|
||||
return callback(null, emitter)
|
||||
callback(null, emitter)
|
||||
emitter.emit('searchRequest', message)
|
||||
return
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ const assert = require('assert-plus')
|
|||
// var Protocol = require('../protocol')
|
||||
const PagedControl = require('../controls/paged_results_control.js')
|
||||
|
||||
const CorkedEmitter = require('../corked_emitter.js')
|
||||
|
||||
/// --- API
|
||||
|
||||
/**
|
||||
|
@ -29,19 +31,20 @@ const PagedControl = require('../controls/paged_results_control.js')
|
|||
* will be emitted (and 'end' will not be). By listening to
|
||||
* 'pageError', a successful search that lacks paging will be
|
||||
* able to emit 'end'.
|
||||
* 3. search - Emitted as an internal event to trigger another client search.
|
||||
*/
|
||||
function SearchPager (opts) {
|
||||
assert.object(opts)
|
||||
assert.func(opts.callback)
|
||||
assert.number(opts.pageSize)
|
||||
assert.func(opts.sendRequest)
|
||||
|
||||
EventEmitter.call(this, {})
|
||||
CorkedEmitter.call(this, {})
|
||||
|
||||
this.callback = opts.callback
|
||||
this.controls = opts.controls
|
||||
this.pageSize = opts.pageSize
|
||||
this.pagePause = opts.pagePause
|
||||
this.sendRequest = opts.sendRequest
|
||||
|
||||
this.controls.forEach(function (control) {
|
||||
if (control.type === PagedControl.OID) {
|
||||
|
@ -55,12 +58,13 @@ function SearchPager (opts) {
|
|||
this.started = false
|
||||
|
||||
const emitter = new EventEmitter()
|
||||
emitter.on('searchRequest', this.emit.bind(this, 'searchRequest'))
|
||||
emitter.on('searchEntry', this.emit.bind(this, 'searchEntry'))
|
||||
emitter.on('end', this._onEnd.bind(this))
|
||||
emitter.on('error', this._onError.bind(this))
|
||||
this.childEmitter = emitter
|
||||
}
|
||||
util.inherits(SearchPager, EventEmitter)
|
||||
util.inherits(SearchPager, CorkedEmitter)
|
||||
module.exports = SearchPager
|
||||
|
||||
/**
|
||||
|
@ -143,8 +147,7 @@ SearchPager.prototype._nextPage = function _nextPage (cookie) {
|
|||
}
|
||||
}))
|
||||
|
||||
this.emit('search', controls, this.childEmitter,
|
||||
this._sendCallback.bind(this))
|
||||
this.sendRequest(controls, this.childEmitter, this._sendCallback.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -777,14 +777,23 @@ tap.test('search paged', { timeout: 10000 }, function (t) {
|
|||
t.test('paged - no pauses', function (t2) {
|
||||
let countEntries = 0
|
||||
let countPages = 0
|
||||
let currentSearchRequest = null
|
||||
t.context.client.search('cn=paged', { paged: { pageSize: 100 } }, function (err, res) {
|
||||
t2.error(err)
|
||||
res.on('searchEntry', entryListener)
|
||||
res.on('searchRequest', (searchRequest) => {
|
||||
t2.ok(searchRequest instanceof ldap.SearchRequest)
|
||||
if (currentSearchRequest === null) {
|
||||
t2.equal(countPages, 0)
|
||||
}
|
||||
currentSearchRequest = searchRequest
|
||||
})
|
||||
res.on('page', pageListener)
|
||||
res.on('error', (err) => t2.error(err))
|
||||
res.on('end', function () {
|
||||
res.on('end', function (result) {
|
||||
t2.equal(countEntries, 1000)
|
||||
t2.equal(countPages, 10)
|
||||
t2.equal(result.messageID, currentSearchRequest.messageID)
|
||||
t2.end()
|
||||
})
|
||||
|
||||
|
@ -797,8 +806,11 @@ tap.test('search paged', { timeout: 10000 }, function (t) {
|
|||
countEntries += 1
|
||||
}
|
||||
|
||||
function pageListener () {
|
||||
function pageListener (result) {
|
||||
countPages += 1
|
||||
if (countPages < 10) {
|
||||
t2.equal(result.messageID, currentSearchRequest.messageID)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -899,6 +911,25 @@ tap.test('search paged', { timeout: 10000 }, function (t) {
|
|||
})
|
||||
})
|
||||
|
||||
tap.test('paged - search with delayed event listener binding', function (t) {
|
||||
t.context.client.search('cn=paged', { filter: '(objectclass=*)', paged: true }, function (err, res) {
|
||||
t.error(err)
|
||||
setTimeout(() => {
|
||||
let gotEntry = 0
|
||||
res.on('searchEntry', function () {
|
||||
gotEntry++
|
||||
})
|
||||
res.on('error', function (err) {
|
||||
t.fail(err)
|
||||
})
|
||||
res.on('end', function () {
|
||||
t.equal(gotEntry, 1000)
|
||||
t.end()
|
||||
})
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue