125 lines
2.8 KiB
Go
125 lines
2.8 KiB
Go
package framework
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Context type is the customized context of Araneae framework
|
|
//
|
|
// It packages the internal context.Context with basic "wr" couple.
|
|
type Context struct {
|
|
ctx context.Context
|
|
request *http.Request
|
|
responseWriter http.ResponseWriter
|
|
|
|
handlers []ControllerHandler
|
|
// current handler index
|
|
index int
|
|
|
|
params map[string]string
|
|
|
|
hasTimeout bool
|
|
writerMux *sync.Mutex
|
|
}
|
|
|
|
// NewContext create a new context
|
|
func NewContext(w http.ResponseWriter, r *http.Request) *Context {
|
|
return &Context{
|
|
ctx: r.Context(),
|
|
request: r,
|
|
responseWriter: w,
|
|
writerMux: &sync.Mutex{},
|
|
index: -1, // will be set to 0 when at the beginning
|
|
}
|
|
}
|
|
|
|
// {{{ Basic functions
|
|
|
|
// WriterMux returns the writer mutex.
|
|
//
|
|
// This is useful when goroutines concurrently write into responseWriter,
|
|
// while at the same time we are writing into the responseWriter for a
|
|
// panic or timeout.
|
|
// We can protect it at the context level.
|
|
func (ctx *Context) WriterMux() *sync.Mutex {
|
|
return ctx.writerMux
|
|
}
|
|
|
|
// GetRequest returns the original request
|
|
func (ctx *Context) GetRequest() *http.Request {
|
|
return ctx.request
|
|
}
|
|
|
|
// GetResponseWriter returns the original response writer
|
|
func (ctx *Context) GetResponseWriter() http.ResponseWriter {
|
|
return ctx.responseWriter
|
|
}
|
|
|
|
// SetHasTimeout indicates that the context has timeout.
|
|
//
|
|
// So that other goroutines won't write into the responseWriter anymore
|
|
func (ctx *Context) SetHasTimeout() {
|
|
ctx.hasTimeout = true
|
|
}
|
|
|
|
// HasTimeout returns whether the context has timeout.
|
|
func (ctx *Context) HasTimeout() bool {
|
|
return ctx.hasTimeout
|
|
}
|
|
|
|
// }}}
|
|
// {{{ Implements context interface
|
|
|
|
// BaseContext return a request default Context
|
|
func (ctx *Context) BaseContext() context.Context {
|
|
return ctx.request.Context()
|
|
}
|
|
|
|
// Done calls the base function
|
|
func (ctx *Context) Done() <-chan struct{} {
|
|
return ctx.BaseContext().Done()
|
|
}
|
|
|
|
// Deadline calls the base function
|
|
func (ctx *Context) Deadline() (deadline time.Time, ok bool) {
|
|
return ctx.BaseContext().Deadline()
|
|
}
|
|
|
|
// Err calls the base function
|
|
func (ctx *Context) Err() error {
|
|
return ctx.BaseContext().Err()
|
|
}
|
|
|
|
// Value calls the base function
|
|
func (ctx *Context) Value(key any) any {
|
|
return ctx.BaseContext().Value(key)
|
|
}
|
|
|
|
// Next runs the next function in the function chain
|
|
func (ctx *Context) Next() error {
|
|
ctx.index++
|
|
if ctx.index >= len(ctx.handlers) {
|
|
// This is the end of the chain
|
|
return nil
|
|
}
|
|
// Run this handler
|
|
if err := ctx.handlers[ctx.index](ctx); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetHandlers sets handlers for context
|
|
func (ctx *Context) SetHandlers(handlers []ControllerHandler) {
|
|
ctx.handlers = handlers
|
|
}
|
|
|
|
func (ctx *Context) SetParams(params map[string]string) {
|
|
ctx.params = params
|
|
}
|
|
|
|
// }}}
|