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 } // }}}