Skip to content

Commit

Permalink
Merge branch 'context-test'
Browse files Browse the repository at this point in the history
  • Loading branch information
joeybloggs authored and joeybloggs committed Apr 13, 2016
2 parents 906db78 + 6eabe5f commit e192b9d
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 157 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
##LARS
<img align="right" src="https://raw.githubusercontent.com/go-playground/lars/master/examples/README/test.gif">
![Project status](https://img.shields.io/badge/version-2.6-green.svg)
![Project status](https://img.shields.io/badge/version-2.7-green.svg)
[![Build Status](https://semaphoreci.com/api/v1/projects/4351aa2d-2f94-40be-a6ef-85c248490378/679708/badge.svg)](https://semaphoreci.com/joeybloggs/lars)
[![Coverage Status](https://coveralls.io/repos/github/go-playground/lars/badge.svg?branch=master)](https://coveralls.io/github/go-playground/lars?branch=master)
[![Go Report Card](https://goreportcard.com/badge/go-playground/lars)](https://goreportcard.com/report/go-playground/lars)
Expand Down
117 changes: 81 additions & 36 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"net"
"net/http"
"strings"
"sync"
"time"

"golang.org/x/net/context"
"golang.org/x/net/websocket"
Expand All @@ -24,8 +24,6 @@ type Param struct {
// It is therefore safe to read values by the index.
type Params []Param

type store map[string]interface{}

// Context is the context interface type
type Context interface {
context.Context
Expand All @@ -35,8 +33,8 @@ type Context interface {
Param(name string) string
ParseForm() error
ParseMultipartForm(maxMemory int64) error
Set(key string, value interface{})
Get(key string) (value interface{}, exists bool)
Set(key interface{}, value interface{})
Get(key interface{}) (value interface{}, exists bool)
Next()
RequestStart(w http.ResponseWriter, r *http.Request)
RequestEnd()
Expand All @@ -58,19 +56,17 @@ type Context interface {

// Ctx encapsulates the http request, response context
type Ctx struct {
context.Context
netContext context.Context
request *http.Request
response *Response
websocket *websocket.Conn
params Params
handlers HandlersChain
parent Context
handlerName string
store store
index int
formParsed bool
multipartFormParsed bool
parent Context
m *sync.RWMutex
}

var _ context.Context = &Ctx{}
Expand Down Expand Up @@ -119,7 +115,7 @@ func (c *Ctx) RequestStart(w http.ResponseWriter, r *http.Request) {
c.request = r
c.response.reset(w)
c.params = c.params[0:0]
c.store = nil
c.netContext = context.Background() // in go 1.7 will call r.Context(), netContext will go away and be replaced with the Request objects Context
c.index = -1
c.handlers = nil
c.formParsed = false
Expand Down Expand Up @@ -186,34 +182,19 @@ func (c *Ctx) ParseMultipartForm(maxMemory int64) error {
return nil
}

// Set is used to store a new key/value pair exclusivelly for thisContext.
// It also lazy initializes c.Keys if it was not used previously.
func (c *Ctx) Set(key string, value interface{}) {

if c.store == nil {

if c.m == nil {
c.m = new(sync.RWMutex)
}

c.m.Lock()
c.store = make(store)
} else {
c.m.Lock()
}

c.store[key] = value
c.m.Unlock()
// Set is used to store a new key/value pair using the
// golang.org/x/net/context contained on this Context.
// It is a shortcut for context.WithValue(..., ...)
func (c *Ctx) Set(key interface{}, value interface{}) {
c.netContext = context.WithValue(c.netContext, key, value)
}

// Get returns the value for the given key, ie: (value, true).
// If the value does not exists it returns (nil, false)
func (c *Ctx) Get(key string) (value interface{}, exists bool) {
if c.store != nil {
c.m.RLock()
value, exists = c.store[key]
c.m.RUnlock()
}
// Get returns the value for the given key and is a shortcut
// for the golang.org/x/net/context context.Value(...) ... but it
// also returns if the value was found or not.
func (c *Ctx) Get(key interface{}) (value interface{}, exists bool) {
value = c.netContext.Value(key)
exists = value != nil
return
}

Expand Down Expand Up @@ -424,3 +405,67 @@ func (c *Ctx) Inline(r io.Reader, filename string) (err error) {

return
}

// golang.org/x/net/context functions to comply with context.Context interface and keep context update on lars.Context object

// Context returns the request's context. To change the context, use
// WithContext.
//
// The returned context is always non-nil.
func (c *Ctx) Context() context.Context {
return c.netContext // TODO: in go 1.7 return c.request.Context()
}

// WithContext updates the underlying request's context with to ctx
// The provided ctx must be non-nil.
func (c *Ctx) WithContext(ctx context.Context) {
c.netContext = ctx // TODO: in go 1.7 must update Request object after calling c.request.WithContext(...)
}

// Deadline calls the underlying golang.org/x/net/context Deadline()
func (c *Ctx) Deadline() (deadline time.Time, ok bool) {
return c.netContext.Deadline()
}

// Done calls the underlying golang.org/x/net/context Done()
func (c *Ctx) Done() <-chan struct{} {
return c.netContext.Done()
}

// Err calls the underlying golang.org/x/net/context Err()
func (c *Ctx) Err() error {
return c.netContext.Err()
}

// Value calls the underlying golang.org/x/net/context Value()
func (c *Ctx) Value(key interface{}) interface{} {
return c.netContext.Value(key)
}

// WithCancel calls golang.org/x/net/context WithCancel and automatically
// updates context on the containing las.Context object.
func (c *Ctx) WithCancel() (cf context.CancelFunc) {
c.netContext, cf = context.WithCancel(c.netContext)
return
}

// WithDeadline calls golang.org/x/net/context WithDeadline and automatically
// updates context on the containing las.Context object.
func (c *Ctx) WithDeadline(deadline time.Time) (cf context.CancelFunc) {
c.netContext, cf = context.WithDeadline(c.netContext, deadline)
return
}

// WithTimeout calls golang.org/x/net/context WithTimeout and automatically
// updates context on the containing las.Context object.
func (c *Ctx) WithTimeout(timeout time.Duration) (cf context.CancelFunc) {
c.netContext, cf = context.WithTimeout(c.netContext, timeout)
return
}

// WithValue calls golang.org/x/net/context WithValue and automatically
// updates context on the containing las.Context object.
// Can also use Set() function on Context object (Recommended)
func (c *Ctx) WithValue(key interface{}, val interface{}) {
c.netContext = context.WithValue(c.netContext, key, val)
}
Loading

0 comments on commit e192b9d

Please sign in to comment.