mirror of
https://github.com/kataras/iris.git
synced 2025-03-14 08:16:28 +01:00
minor
Former-commit-id: 4c71a275f3e10dd0ce77bf5723c370be765663ab
This commit is contained in:
parent
beb3f730a0
commit
8c3e43df7f
|
@ -40,6 +40,7 @@
|
||||||
* [Dynamic Path](routing/dynamic-path/main.go)
|
* [Dynamic Path](routing/dynamic-path/main.go)
|
||||||
* [Root Wildcard](routing/dynamic-path/root-wildcard/main.go)
|
* [Root Wildcard](routing/dynamic-path/root-wildcard/main.go)
|
||||||
* [Implement a Parameter Type](routing/macros/main.go)
|
* [Implement a Parameter Type](routing/macros/main.go)
|
||||||
|
* [Same Path Pattern but Func](routing/dynamic-path/same-pattern-different-func/main.go)
|
||||||
* Middleware
|
* Middleware
|
||||||
* [Per Route](routing/writing-a-middleware/per-route/main.go)
|
* [Per Route](routing/writing-a-middleware/per-route/main.go)
|
||||||
* [Globally](routing/writing-a-middleware/globally/main.go)
|
* [Globally](routing/writing-a-middleware/globally/main.go)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -1350,7 +1351,7 @@ func (ctx *context) EndRequest() {
|
||||||
func (ctx *context) IsCanceled() bool {
|
func (ctx *context) IsCanceled() bool {
|
||||||
if reqCtx := ctx.request.Context(); reqCtx != nil {
|
if reqCtx := ctx.request.Context(); reqCtx != nil {
|
||||||
err := reqCtx.Err()
|
err := reqCtx.Err()
|
||||||
if errors.Is(err, stdContext.Canceled) {
|
if err != nil && errors.Is(err, stdContext.Canceled) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1415,18 +1416,74 @@ func (ctx *context) OnClose(cb Handler) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.OnConnectionClose(cb)
|
// Note(@kataras):
|
||||||
|
// - on normal request-response lifecycle
|
||||||
|
// the `SetBeforeFlush` will be called first
|
||||||
|
// and then `OnConnectionClose`,
|
||||||
|
// - when request was canceled before handler finish its job
|
||||||
|
// then the `OnConnectionClose` will be called first instead,
|
||||||
|
// and when the handler function completed then `SetBeforeFlush` is fired.
|
||||||
|
// These are synchronized, they cannot be executed the same exact time,
|
||||||
|
// below we just make sure the "cb" is executed once
|
||||||
|
// by simple boolean check or an atomic one.
|
||||||
|
var executed uint32
|
||||||
|
|
||||||
fn := func() {
|
callback := func(ctx Context) {
|
||||||
if !ctx.IsCanceled() {
|
if atomic.CompareAndSwapUint32(&executed, 0, 1) {
|
||||||
// If the callback not fired by OnConnectionClose already.
|
|
||||||
cb(ctx)
|
cb(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.writer.SetBeforeFlush(fn)
|
ctx.OnConnectionClose(callback)
|
||||||
|
|
||||||
|
onFlush := func() {
|
||||||
|
callback(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.writer.SetBeforeFlush(onFlush)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note(@kataras): just leave end-developer decide.
|
||||||
|
const goroutinesContextKey = "iris.goroutines"
|
||||||
|
|
||||||
|
type goroutines struct {
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
length int
|
||||||
|
mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var acquireGoroutines = func() interface{} {
|
||||||
|
return &goroutines{wg: new(sync.WaitGroup)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) Go(fn func(cancelCtx stdContext.Context)) (running int) {
|
||||||
|
g := ctx.Values().GetOrSet(goroutinesContextKey, acquireGoroutines).(*goroutines)
|
||||||
|
if fn != nil {
|
||||||
|
g.wg.Add(1)
|
||||||
|
|
||||||
|
g.mu.Lock()
|
||||||
|
g.length++
|
||||||
|
g.mu.Unlock()
|
||||||
|
|
||||||
|
ctx.waitFunc = g.wg.Wait
|
||||||
|
|
||||||
|
go func(reqCtx stdContext.Context) {
|
||||||
|
fn(reqCtx)
|
||||||
|
g.wg.Done()
|
||||||
|
|
||||||
|
g.mu.Lock()
|
||||||
|
g.length--
|
||||||
|
g.mu.Unlock()
|
||||||
|
}(ctx.request.Context())
|
||||||
|
}
|
||||||
|
|
||||||
|
g.mu.RLock()
|
||||||
|
running = g.length
|
||||||
|
g.mu.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
|
// ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
|
||||||
func (ctx *context) ResponseWriter() ResponseWriter {
|
func (ctx *context) ResponseWriter() ResponseWriter {
|
||||||
return ctx.writer
|
return ctx.writer
|
||||||
|
|
|
@ -815,6 +815,19 @@ func (r *Store) Get(key string) interface{} {
|
||||||
return r.GetDefault(key, nil)
|
return r.GetDefault(key, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrSet is like `GetDefault` but it accepts a function which is
|
||||||
|
// fired and its result is used to `Set` if
|
||||||
|
// the "key" was not found or its value is nil.
|
||||||
|
func (r *Store) GetOrSet(key string, setFunc func() interface{}) interface{} {
|
||||||
|
if v, ok := r.GetEntry(key); ok && v.ValueRaw != nil {
|
||||||
|
return v.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
value := setFunc()
|
||||||
|
r.Set(key, value)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
// Visit accepts a visitor which will be filled
|
// Visit accepts a visitor which will be filled
|
||||||
// by the key-value objects.
|
// by the key-value objects.
|
||||||
func (r *Store) Visit(visitor func(key string, value interface{})) {
|
func (r *Store) Visit(visitor func(key string, value interface{})) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user