Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
joseustra committed Aug 29, 2016
0 parents commit 7b93df8
Show file tree
Hide file tree
Showing 19 changed files with 1,285 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
*.iml
22 changes: 22 additions & 0 deletions LICENSE
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.

6 changes: 6 additions & 0 deletions README.md
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
126 changes: 126 additions & 0 deletions context.go
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)
}
47 changes: 47 additions & 0 deletions dispatcher.go
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
}
138 changes: 138 additions & 0 deletions helper.go
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
}
28 changes: 28 additions & 0 deletions jwt.go
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
}
Loading

0 comments on commit 7b93df8

Please sign in to comment.