mirror of
https://github.com/kataras/iris.git
synced 2026-05-10 16:13:46 +00:00
Add 'context.OnConnectionClose(callbackFn) bool' and 'context.OnClose(callbackFn)' and give a use case example. More on this path later on, stay tuned.
Former-commit-id: dc6580f072d076b8cb204a681e45905210981153
This commit is contained in:
@@ -340,6 +340,32 @@ type Context interface {
|
||||
// IsStopped checks and returns true if the current position of the Context is 255,
|
||||
// means that the StopExecution() was called.
|
||||
IsStopped() bool
|
||||
// OnConnectionClose registers the "cb" function which will fire (on its own goroutine, no need to be registered goroutine by the end-dev)
|
||||
// when the underlying connection has gone away.
|
||||
//
|
||||
// This mechanism can be used to cancel long operations on the server
|
||||
// if the client has disconnected before the response is ready.
|
||||
//
|
||||
// It depends on the `http#CloseNotify`.
|
||||
// CloseNotify may wait to notify until Request.Body has been
|
||||
// fully read.
|
||||
//
|
||||
// After the main Handler has returned, there is no guarantee
|
||||
// that the channel receives a value.
|
||||
//
|
||||
// Finally, it reports whether the protocol supports pipelines (HTTP/1.1 with pipelines disabled is not supported).
|
||||
// The "cb" will not fire for sure if the output value is false.
|
||||
//
|
||||
// Note that you can register only one callback for the entire request handler chain/per route.
|
||||
//
|
||||
// Look the `ResponseWriter#CloseNotifier` for more.
|
||||
OnConnectionClose(fnGoroutine func()) bool
|
||||
// OnClose registers the callback function "cb" to the underline connection closing event using the `Context#OnConnectionClose`
|
||||
// and also in the end of the request handler using the `ResponseWriter#SetBeforeFlush`.
|
||||
// Note that you can register only one callback for the entire request handler chain/per route.
|
||||
//
|
||||
// Look the `Context#OnConnectionClose` and `ResponseWriter#SetBeforeFlush` for more.
|
||||
OnClose(cb func())
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
// | Current "user/request" storage |
|
||||
@@ -1355,6 +1381,76 @@ func (ctx *context) IsStopped() bool {
|
||||
return ctx.currentHandlerIndex == stopExecutionIndex
|
||||
}
|
||||
|
||||
// OnConnectionClose registers the "cb" function which will fire (on its own goroutine, no need to be registered goroutine by the end-dev)
|
||||
// when the underlying connection has gone away.
|
||||
//
|
||||
// This mechanism can be used to cancel long operations on the server
|
||||
// if the client has disconnected before the response is ready.
|
||||
//
|
||||
// It depends on the `http#CloseNotify`.
|
||||
// CloseNotify may wait to notify until Request.Body has been
|
||||
// fully read.
|
||||
//
|
||||
// After the main Handler has returned, there is no guarantee
|
||||
// that the channel receives a value.
|
||||
//
|
||||
// Finally, it reports whether the protocol supports pipelines (HTTP/1.1 with pipelines disabled is not supported).
|
||||
// The "cb" will not fire for sure if the output value is false.
|
||||
//
|
||||
// Note that you can register only one callback for the entire request handler chain/per route.
|
||||
//
|
||||
// Look the `ResponseWriter#CloseNotifier` for more.
|
||||
func (ctx *context) OnConnectionClose(cb func()) bool {
|
||||
// Note that `ctx.ResponseWriter().CloseNotify()` can already do the same
|
||||
// but it returns a channel which will never fire if it the protocol version is not compatible,
|
||||
// here we don't want to allocate an empty channel, just skip it.
|
||||
notifier, ok := ctx.writer.CloseNotifier()
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
notify := notifier.CloseNotify()
|
||||
go func() {
|
||||
<-notify
|
||||
if cb != nil {
|
||||
cb()
|
||||
}
|
||||
}()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// OnClose registers the callback function "cb" to the underline connection closing event using the `Context#OnConnectionClose`
|
||||
// and also in the end of the request handler using the `ResponseWriter#SetBeforeFlush`.
|
||||
// Note that you can register only one callback for the entire request handler chain/per route.
|
||||
//
|
||||
// Look the `Context#OnConnectionClose` and `ResponseWriter#SetBeforeFlush` for more.
|
||||
func (ctx *context) OnClose(cb func()) {
|
||||
if cb == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Register the on underline connection close handler first.
|
||||
ctx.OnConnectionClose(cb)
|
||||
|
||||
// Author's notes:
|
||||
// This is fired on `ctx.ResponseWriter().FlushResponse()` which is fired by the framework automatically, internally, on the end of request handler(s),
|
||||
// it is not fired on the underline streaming function of the writer: `ctx.ResponseWriter().Flush()` (which can be fired more than one if streaming is supported by the client).
|
||||
// The `FlushResponse` is called only once, so add the "cb" here, no need to add done request handlers each time `OnClose` is called by the end-dev.
|
||||
//
|
||||
// Don't allow more than one because we don't allow that on `OnConnectionClose` too:
|
||||
// old := ctx.writer.GetBeforeFlush()
|
||||
// if old != nil {
|
||||
// ctx.writer.SetBeforeFlush(func() {
|
||||
// old()
|
||||
// cb()
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
ctx.writer.SetBeforeFlush(cb)
|
||||
}
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
// | Current "user/request" storage |
|
||||
// | and share information between the handlers - Values(). |
|
||||
|
||||
@@ -83,6 +83,21 @@ type ResponseWriter interface {
|
||||
|
||||
// WiteTo writes a response writer (temp: status code, headers and body) to another response writer
|
||||
WriteTo(ResponseWriter)
|
||||
|
||||
// Flusher indicates if `Flush` is supported by the client.
|
||||
//
|
||||
// The default HTTP/1.x and HTTP/2 ResponseWriter implementations
|
||||
// support Flusher, but ResponseWriter wrappers may not. Handlers
|
||||
// should always test for this ability at runtime.
|
||||
//
|
||||
// Note that even for ResponseWriters that support Flush,
|
||||
// if the client is connected through an HTTP proxy,
|
||||
// the buffered data may not reach the client until the response
|
||||
// completes.
|
||||
Flusher() (http.Flusher, bool)
|
||||
|
||||
// CloseNotifier indicates if the protocol supports the underline connection closure notification.
|
||||
CloseNotifier() (http.CloseNotifier, bool)
|
||||
}
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
@@ -296,21 +311,25 @@ func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return nil, nil, errors.New("hijack is not supported by this ResponseWriter")
|
||||
}
|
||||
|
||||
// Flusher indicates if `Flush` is supported by the client.
|
||||
//
|
||||
// The default HTTP/1.x and HTTP/2 ResponseWriter implementations
|
||||
// support Flusher, but ResponseWriter wrappers may not. Handlers
|
||||
// should always test for this ability at runtime.
|
||||
//
|
||||
// Note that even for ResponseWriters that support Flush,
|
||||
// if the client is connected through an HTTP proxy,
|
||||
// the buffered data may not reach the client until the response
|
||||
// completes.
|
||||
func (w *responseWriter) Flusher() (http.Flusher, bool) {
|
||||
flusher, canFlush := w.ResponseWriter.(http.Flusher)
|
||||
return flusher, canFlush
|
||||
}
|
||||
|
||||
// Flush sends any buffered data to the client.
|
||||
func (w *responseWriter) Flush() {
|
||||
// The Flusher interface is implemented by ResponseWriters that allow
|
||||
// an HTTP handler to flush buffered data to the client.
|
||||
//
|
||||
// The default HTTP/1.x and HTTP/2 ResponseWriter implementations
|
||||
// support Flusher, but ResponseWriter wrappers may not. Handlers
|
||||
// should always test for this ability at runtime.
|
||||
//
|
||||
// Note that even for ResponseWriters that support Flush,
|
||||
// if the client is connected through an HTTP proxy,
|
||||
// the buffered data may not reach the client until the response
|
||||
// completes.
|
||||
if fl, isFlusher := w.ResponseWriter.(http.Flusher); isFlusher {
|
||||
fl.Flush()
|
||||
if flusher, ok := w.Flusher(); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +368,12 @@ func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
|
||||
return ErrPushNotSupported
|
||||
}
|
||||
|
||||
// CloseNotifier indicates if the protocol supports the underline connection closure notification.
|
||||
func (w *responseWriter) CloseNotifier() (http.CloseNotifier, bool) {
|
||||
notifier, supportsCloseNotify := w.ResponseWriter.(http.CloseNotifier)
|
||||
return notifier, supportsCloseNotify
|
||||
}
|
||||
|
||||
// CloseNotify returns a channel that receives at most a
|
||||
// single value (true) when the client connection has gone
|
||||
// away.
|
||||
@@ -368,9 +393,10 @@ func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
|
||||
// is a problem, use HTTP/2 or only use CloseNotify on methods
|
||||
// such as POST.
|
||||
func (w *responseWriter) CloseNotify() <-chan bool {
|
||||
if notifier, supportsCloseNotify := w.ResponseWriter.(http.CloseNotifier); supportsCloseNotify {
|
||||
if notifier, ok := w.CloseNotifier(); ok {
|
||||
return notifier.CloseNotify()
|
||||
}
|
||||
|
||||
ch := make(chan bool, 1)
|
||||
return ch
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user