-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7b93df8
Showing
19 changed files
with
1,285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.idea | ||
*.iml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2014 RocWong | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Minion | ||
|
||
## A micro RESTfull "framework" for Go apps. | ||
|
||
## License | ||
Minion is licensed under the MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package minion | ||
|
||
import ( | ||
"errors" | ||
"log" | ||
"math" | ||
"net/http" | ||
|
||
"github.com/julienschmidt/httprouter" | ||
"github.com/unrolled/render" | ||
) | ||
|
||
// Context the context of each request | ||
type Context struct { | ||
Writer ResponseWriter | ||
Req *http.Request | ||
Session Session | ||
Keys map[string]interface{} | ||
Params routerParams | ||
Engine *Engine | ||
render *render.Render | ||
writer writer | ||
handlers []HandlerFunc | ||
index int8 | ||
HTMLEngine | ||
} | ||
|
||
const ( | ||
abortIndex = math.MaxInt8 / 2 | ||
) | ||
|
||
// Next should be used only in the middlewares. | ||
// It executes the pending handlers in the chain inside the calling handler. | ||
func (c *Context) Next() { | ||
c.index++ | ||
s := int8(len(c.handlers)) | ||
for ; c.index < s; c.index++ { | ||
c.handlers[c.index](c) | ||
} | ||
} | ||
|
||
// Set Sets a new pair key/value just for the specified context. | ||
func (c *Context) Set(key string, item interface{}) { | ||
if c.Keys == nil { | ||
c.Keys = make(map[string]interface{}) | ||
} | ||
c.Keys[key] = item | ||
} | ||
|
||
// Get returns the value for the given key or an error if the key does not exist. | ||
func (c *Context) Get(key string) (interface{}, error) { | ||
if c.Keys != nil { | ||
value, ok := c.Keys[key] | ||
if ok { | ||
return value, nil | ||
} | ||
} | ||
return nil, errors.New("Key does not exist.") | ||
} | ||
|
||
// MustGet returns the value for the given key or panics if the value doesn't exist. | ||
func (c *Context) MustGet(key string) interface{} { | ||
value, err := c.Get(key) | ||
if err != nil || value == nil { | ||
log.Panicf("Key %s doesn't exist", value) | ||
} | ||
return value | ||
} | ||
|
||
// SetHeader sets a response header. | ||
func (c *Context) SetHeader(key, value string) { | ||
c.Writer.Header().Set(key, value) | ||
} | ||
|
||
// Abort Forces the system to do not continue calling the pending handlers in the chain. | ||
func (c *Context) Abort() { | ||
c.index = abortIndex | ||
} | ||
|
||
// Redirect returns a HTTP redirect to the specific location. default for 302 | ||
func (c *Context) Redirect(location string, status ...int) { | ||
c.SetHeader("Location", location) | ||
if status != nil { | ||
http.Redirect(c.Writer, c.Req, location, status[0]) | ||
} else { | ||
http.Redirect(c.Writer, c.Req, location, 302) | ||
} | ||
} | ||
|
||
// JSON Serializes the given struct as JSON into the response body in a fast and efficient way. | ||
// It also sets the Content-Type as "application/json". | ||
func (c *Context) JSON(status int, data interface{}) { | ||
c.render.JSON(c.Writer, status, data) | ||
} | ||
|
||
// JSONP Serializes the given struct as JSONP into the response body in a fast and efficient way. | ||
// It also sets the Content-Type as "application/javascript". | ||
func (c *Context) JSONP(status int, data interface{}, callback string) { | ||
c.render.JSONP(c.Writer, status, callback, data) | ||
} | ||
|
||
// Text Writes the given string into the response body and sets the Content-Type to "text/plain". | ||
func (c *Context) Text(status int, data string) { | ||
c.render.Text(c.Writer, status, data) | ||
} | ||
|
||
// HTML renders the html template and sets the Content-Type to "text/html". | ||
func (c *Context) HTML(status int, tmpl string, data interface{}) { | ||
c.render.HTML(c.Writer, status, tmpl, data) | ||
} | ||
|
||
func (c *Engine) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context { | ||
ctx := c.pool.Get().(*Context) | ||
ctx.Writer = &ctx.writer | ||
ctx.Req = req | ||
ctx.Keys = nil | ||
ctx.Params = routerParams{req: req, params: params} | ||
ctx.handlers = handlers | ||
ctx.writer.reset(w) | ||
ctx.index = -1 | ||
return ctx | ||
} | ||
|
||
func (c *Engine) reuseContext(ctx *Context) { | ||
c.pool.Put(ctx) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package minion | ||
|
||
import "fmt" | ||
|
||
// Dispatcher TODO | ||
type Dispatcher struct { | ||
Size int | ||
} | ||
|
||
// NewDispatcher TODO | ||
func NewDispatcher(size int) *Dispatcher { | ||
return &Dispatcher{Size: size} | ||
} | ||
|
||
// WorkerQueue TODO | ||
var WorkerQueue chan chan Job | ||
|
||
// WorkQueue A buffered channel that we can send work requests on. | ||
var WorkQueue = make(chan Job, 100) | ||
|
||
// StartDispatcher TODO | ||
func (d *Dispatcher) StartDispatcher() { | ||
WorkerQueue = make(chan chan Job, d.Size) | ||
|
||
for i := 0; i < d.Size; i++ { | ||
fmt.Println("Starting worker", i+1) | ||
worker := NewWorker(i+1, WorkerQueue) | ||
worker.Start() | ||
} | ||
|
||
go func() { | ||
for { | ||
select { | ||
case work := <-WorkQueue: | ||
go func() { | ||
worker := <-WorkerQueue | ||
worker <- work | ||
}() | ||
} | ||
} | ||
}() | ||
} | ||
|
||
// Add adds a new job to the worker | ||
func (d *Dispatcher) Add(job Job) { | ||
WorkQueue <- job | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package minion | ||
|
||
import ( | ||
"crypto/hmac" | ||
"crypto/sha1" | ||
"encoding/base64" | ||
"fmt" | ||
"net/http" | ||
"strconv" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// ClientIP returns more real IP address. | ||
func (c *Context) ClientIP() string { | ||
clientIP := c.Req.Header.Get("X-Real-IP") | ||
if len(clientIP) == 0 { | ||
clientIP = c.Req.Header.Get("X-Forwarded-For") | ||
} | ||
if len(clientIP) == 0 { | ||
clientIP = c.Req.RemoteAddr | ||
} | ||
return clientIP | ||
} | ||
|
||
// SetCookie sets given cookie value to response header. | ||
// c.SetCookie(name, value [, MaxAge, Path, Domain, Secure, HttpOnly]) | ||
func (c *Context) SetCookie(name, value string, others ...interface{}) { | ||
cookie := &http.Cookie{} | ||
cookie.Name = name | ||
cookie.Value = value | ||
|
||
if len(others) > 0 { | ||
switch v := others[0].(type) { | ||
case int: | ||
cookie.MaxAge = v | ||
case int64: | ||
cookie.MaxAge = int(v) | ||
case int32: | ||
cookie.MaxAge = int(v) | ||
} | ||
} | ||
|
||
// default "/" | ||
if len(others) > 1 { | ||
if v, ok := others[1].(string); ok && len(v) > 0 { | ||
cookie.Path = v | ||
} | ||
} else { | ||
cookie.Path = "/" | ||
} | ||
|
||
// default empty | ||
if len(others) > 2 { | ||
if v, ok := others[2].(string); ok && len(v) > 0 { | ||
cookie.Domain = v | ||
} | ||
} | ||
|
||
// default empty | ||
if len(others) > 3 { | ||
switch v := others[3].(type) { | ||
case bool: | ||
cookie.Secure = v | ||
} | ||
} | ||
|
||
// default false. | ||
if len(others) > 4 { | ||
if v, ok := others[4].(bool); ok && v { | ||
cookie.HttpOnly = true | ||
} | ||
} | ||
|
||
http.SetCookie(c.Writer, cookie) | ||
} | ||
|
||
// GetCookie returns given cookie value from request header. | ||
func (c *Context) GetCookie(name string) string { | ||
cookie, err := c.Req.Cookie(name) | ||
if err != nil { | ||
return "" | ||
} | ||
return cookie.Value | ||
} | ||
|
||
var cookieSecret string | ||
|
||
// SetCookieSecret sets global default secure cookie secret. | ||
func (m *Engine) SetCookieSecret(secret string) { | ||
cookieSecret = secret | ||
} | ||
|
||
// SetSecureCookie sets given cookie value to response header with default secret string. | ||
func (c *Context) SetSecureCookie(name, value string, others ...interface{}) { | ||
c.SetBasicSecureCookie(cookieSecret, name, value, others...) | ||
} | ||
|
||
// GetSecureCookie returns given cookie value from request header with default secret string. | ||
func (c *Context) GetSecureCookie(name string) (string, bool) { | ||
return c.GetBasicSecureCookie(cookieSecret, name) | ||
} | ||
|
||
// SetBasicSecureCookie sets given cookie value to response header with secret string. | ||
func (c *Context) SetBasicSecureCookie(Secret, name, value string, others ...interface{}) { | ||
|
||
vs := base64.URLEncoding.EncodeToString([]byte(value)) | ||
timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) | ||
hm := hmac.New(sha1.New, []byte(Secret)) | ||
fmt.Fprintf(hm, "%s%s", vs, timestamp) | ||
sig := fmt.Sprintf("%02x", hm.Sum(nil)) | ||
cookie := strings.Join([]string{vs, timestamp, sig}, "|") | ||
c.SetCookie(name, cookie, others...) | ||
} | ||
|
||
// GetBasicSecureCookie returns given cookie value from request header with secret string. | ||
func (c *Context) GetBasicSecureCookie(Secret, name string) (string, bool) { | ||
val := c.GetCookie(name) | ||
if val == "" { | ||
return "", false | ||
} | ||
|
||
parts := strings.SplitN(val, "|", 3) | ||
if len(parts) != 3 { | ||
return "", false | ||
} | ||
vs := parts[0] | ||
timestamp := parts[1] | ||
sig := parts[2] | ||
|
||
hm := hmac.New(sha1.New, []byte(Secret)) | ||
fmt.Fprintf(hm, "%s%s", vs, timestamp) | ||
if fmt.Sprintf("%02x", hm.Sum(nil)) != sig { | ||
return "", false | ||
} | ||
res, _ := base64.URLEncoding.DecodeString(vs) | ||
return string(res), true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package minion | ||
|
||
import ( | ||
"github.com/dgrijalva/jwt-go" | ||
"github.com/gorilla/context" | ||
) | ||
|
||
// CreateJWTToken creates a jwt token with the given secret | ||
func CreateJWTToken(secret string, claims interface{}) (string, error) { | ||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims.(jwt.Claims)) | ||
tokenString, err := token.SignedString([]byte(secret)) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return tokenString, nil | ||
} | ||
|
||
// GetClaims returns the claims | ||
func (c *Context) GetClaims() map[string]interface{} { | ||
|
||
claims := context.Get(c.Req, "claims") | ||
if claims != nil { | ||
return claims.(jwt.MapClaims) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.