@@ -218,6 +218,42 @@ func (s *SearchResult) PrettyPrint(indent int) {
218
218
}
219
219
}
220
220
221
+ // SearchAsyncResponseType describes the SearchAsyncResponse content type
222
+ type SearchAsyncResponseType uint8
223
+
224
+ const (
225
+ SearchAsyncResponseTypeNone SearchAsyncResponseType = iota
226
+ SearchAsyncResponseTypeEntry
227
+ SearchAsyncResponseTypeReferral
228
+ SearchAsyncResponseTypeControl
229
+ )
230
+
231
+ // SearchAsyncResponse holds the server's response message to an async search request
232
+ type SearchAsyncResponse struct {
233
+ // Type indicates the SearchAsyncResponse type
234
+ Type SearchAsyncResponseType
235
+ // Entry is the received entry, only set if Type is SearchAsyncResponseTypeEntry
236
+ Entry * Entry
237
+ // Referral is the received referral, only set if Type is SearchAsyncResponseTypeReferral
238
+ Referral string
239
+ // Control is the received control, only set if Type is SearchAsyncResponseTypeControl
240
+ Control Control
241
+ // closed indicates that the request is finished
242
+ closed bool
243
+ // err holds the encountered error while processing server's response, if any
244
+ err error
245
+ }
246
+
247
+ // Closed returns true if the request is finished
248
+ func (r * SearchAsyncResponse ) Closed () bool {
249
+ return r .closed
250
+ }
251
+
252
+ // Err returns the encountered error while processing server's response, if any
253
+ func (r * SearchAsyncResponse ) Err () error {
254
+ return r .err
255
+ }
256
+
221
257
// SearchRequest represents a search request to send to the server
222
258
type SearchRequest struct {
223
259
BaseDN string
@@ -402,6 +438,59 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
402
438
}
403
439
}
404
440
441
+ // SearchAsync performs the given search request asynchronously, it returns a SearchAsyncResponse channel which will be
442
+ // closed when the request finished and an error, not nil if the request to the server failed
443
+ func (l * Conn ) SearchAsync (searchRequest * SearchRequest ) (<- chan * SearchAsyncResponse , error ) {
444
+ msgCtx , err := l .doRequest (searchRequest )
445
+ if err != nil {
446
+ return nil , err
447
+ }
448
+ responses := make (chan * SearchAsyncResponse )
449
+ go func () {
450
+ defer l .finishMessage (msgCtx )
451
+ defer close (responses )
452
+ for {
453
+ packet , err := l .readPacket (msgCtx )
454
+ if err != nil {
455
+ responses <- & SearchAsyncResponse {closed : true , err : err }
456
+ return
457
+ }
458
+
459
+ switch packet .Children [1 ].Tag {
460
+ case 4 :
461
+ entry := & Entry {
462
+ DN : packet .Children [1 ].Children [0 ].Value .(string ),
463
+ Attributes : unpackAttributes (packet .Children [1 ].Children [1 ].Children ),
464
+ }
465
+ responses <- & SearchAsyncResponse {Type : SearchAsyncResponseTypeEntry , Entry : entry }
466
+ case 5 :
467
+ err := GetLDAPError (packet )
468
+ if err != nil {
469
+ responses <- & SearchAsyncResponse {closed : true , err : err }
470
+ return
471
+ }
472
+ var response SearchAsyncResponse
473
+ if len (packet .Children ) == 3 {
474
+ for _ , child := range packet .Children [2 ].Children {
475
+ decodedChild , err := DecodeControl (child )
476
+ if err != nil {
477
+ responses <- & SearchAsyncResponse {closed : true , err : fmt .Errorf ("failed to decode child control: %s" , err )}
478
+ return
479
+ }
480
+ response = SearchAsyncResponse {Type : SearchAsyncResponseTypeControl , Control : decodedChild }
481
+ }
482
+ }
483
+ response .closed = true
484
+ responses <- & response
485
+ return
486
+ case 19 :
487
+ responses <- & SearchAsyncResponse {Type : SearchAsyncResponseTypeReferral , Referral : packet .Children [1 ].Children [0 ].Value .(string )}
488
+ }
489
+ }
490
+ }()
491
+ return responses , nil
492
+ }
493
+
405
494
// unpackAttributes will extract all given LDAP attributes and it's values
406
495
// from the ber.Packet
407
496
func unpackAttributes (children []* ber.Packet ) []* EntryAttribute {
0 commit comments