Skip to content

Commit 7500441

Browse files
committed
feat: SSE add request failure event callback function #1041 (#1076)
1 parent 3b41b01 commit 7500441

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

sse.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ type (
5151
// when an error occurs with [EventSource] processing
5252
EventErrorFunc func(error)
5353

54+
// EventRequestFailureFunc is a callback function type used to receive event
55+
// details from the Server-Sent Events(SSE) request failure
56+
EventRequestFailureFunc func(err error, res *http.Response)
57+
5458
// Event struct represents the event details from the Server-Sent Events(SSE) stream
5559
Event struct {
5660
ID string
@@ -76,6 +80,7 @@ type (
7680
maxBufSize int
7781
onOpen EventOpenFunc
7882
onError EventErrorFunc
83+
onRequestFailure EventRequestFailureFunc
7984
onEvent map[string]*callback
8085
log Logger
8186
closed bool
@@ -343,12 +348,33 @@ func (es *EventSource) OnError(ef EventErrorFunc) *EventSource {
343348
defer es.lock.Unlock()
344349
if es.onError != nil {
345350
es.log.Warnf("Overwriting an existing OnError callback from=%s to=%s",
346-
functionName(es.OnError), functionName(ef))
351+
functionName(es.onError), functionName(ef))
347352
}
348353
es.onError = ef
349354
return es
350355
}
351356

357+
// OnRequestFailure registered callback gets triggered when the HTTP request
358+
// failure while establishing a SSE connection.
359+
//
360+
// es.OnRequestFailure(func(err error, res *http.Response) {
361+
// fmt.Println("Error and response:", err, res)
362+
// })
363+
//
364+
// Note:
365+
// - Do not forget to close the HTTP response body.
366+
// - HTTP response may be nil.
367+
func (es *EventSource) OnRequestFailure(ef EventRequestFailureFunc) *EventSource {
368+
es.lock.Lock()
369+
defer es.lock.Unlock()
370+
if es.onRequestFailure != nil {
371+
es.log.Warnf("Overwriting an existing OnRequestFailure callback from=%s to=%s",
372+
functionName(es.onRequestFailure), functionName(ef))
373+
}
374+
es.onRequestFailure = ef
375+
return es
376+
}
377+
352378
// OnMessage method registers a callback to emit every SSE event message
353379
// from the server. The second result argument is optional; it can be used
354380
// to register the data type for JSON data.
@@ -495,6 +521,14 @@ func (es *EventSource) triggerOnError(err error) {
495521
}
496522
}
497523

524+
func (es *EventSource) triggerOnRequestFailure(err error, res *http.Response) {
525+
es.lock.RLock()
526+
defer es.lock.RUnlock()
527+
if es.onRequestFailure != nil {
528+
es.onRequestFailure(err, res)
529+
}
530+
}
531+
498532
func (es *EventSource) createRequest() (*http.Request, error) {
499533
req, err := http.NewRequest(es.method, es.url, es.body)
500534
if err != nil {
@@ -557,6 +591,9 @@ func (es *EventSource) connect() (*http.Response, error) {
557591
} else {
558592
err = doErr
559593
}
594+
if err != nil {
595+
es.triggerOnRequestFailure(err, resp)
596+
}
560597
break
561598
}
562599

sse_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,31 @@ func TestGH1044TrimHeader(t *testing.T) {
342342
})
343343
}
344344

345+
func TestGH1041RequestFailureWithResponseBody(t *testing.T) {
346+
es := createEventSource(t, "", func(any) {}, nil)
347+
ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
348+
w.Header().Set(hdrContentTypeKey, jsonContentType)
349+
w.WriteHeader(http.StatusBadRequest)
350+
_, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Unable to establish connection" }`))
351+
})
352+
defer ts.Close()
353+
354+
rfFunc := func(err error, res *http.Response) {
355+
defer res.Body.Close()
356+
resBytes, _ := io.ReadAll(res.Body)
357+
358+
assertNotNil(t, err)
359+
assertEqual(t, "resty:sse: 400 Bad Request", err.Error())
360+
assertEqual(t, `{ "id": "bad_request", "message": "Unable to establish connection" }`, string(resBytes))
361+
}
362+
363+
es.SetURL(ts.URL).OnRequestFailure(rfFunc)
364+
es.OnRequestFailure(rfFunc)
365+
err := es.Get()
366+
assertNotNil(t, err)
367+
assertEqual(t, "resty:sse: 400 Bad Request", err.Error())
368+
}
369+
345370
func TestEventSourceHTTPError(t *testing.T) {
346371
es := createEventSource(t, "", func(any) {}, nil)
347372
ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)