Skip to content
This repository has been archived by the owner on Apr 22, 2022. It is now read-only.

Commit

Permalink
Replaces gorilla mux to goji and decied to remove vendor dependencies…
Browse files Browse the repository at this point in the history
… from git (#28)

* Replaces gorilla mux to goji

Removed the applicationContext stuff. Now every handler is a struct, and each one hold its dependencies.

* handler not handle

* Ignoring vendor dir

* Hide handlers complexity instantiation.

* Websocket handler does not need common handlers

* Use maps instead of for loops to search in memdb for apps (#29)

* Use maps instead of for loops to search in memdb for apps; use mutexes more efficiently by immediately unlocking when lock is no longer needed, not just at the end of the function via defer

* Fixed assignment to entry in nil map

* Minor impovements in source code

* Replaces gorilla mux to goji

Removed the applicationContext stuff. Now every handler is a struct, and each one hold its dependencies.

* handler not handle

* Ignoring vendor dir

* Hide handlers complexity instantiation.

* Websocket handler does not need common handlers

* renamed IdMutex to IDMutex to follow go convention
  • Loading branch information
dimiro1 authored Aug 12, 2016
1 parent 7a4568e commit 6225d80
Show file tree
Hide file tree
Showing 76 changed files with 154 additions and 11,925 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,5 @@ config.json
build
.vscode/*
debug

vendor/*
6 changes: 3 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ task :test do
sh 'GO15VENDOREXPERIMENT=1 go test . `glide nv`'
end

desc 'Download the development dependencies'
task :'dev-deps' do
sh 'go get github.com/pusher/pusher-http-go'
desc 'Download the dependencies'
task :'deps' do
sh 'glide install -v -s'
end

desc 'Generate distributions'
Expand Down
18 changes: 12 additions & 6 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion glide.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package: github.com/dimiro1/ipe
import:
- package: github.com/golang/glog
- package: github.com/gorilla/mux
- package: github.com/gorilla/websocket
- package: github.com/pusher/pusher-http-go
- package: goji.io
subpackages:
- pat
- package: golang.org/x/net
subpackages:
- context
29 changes: 0 additions & 29 deletions ipe/context.go

This file was deleted.

10 changes: 5 additions & 5 deletions ipe/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type db interface {

// memdb is an in memory implementation of db interface
type memdb struct {
IdMutex sync.Mutex
IDMutex sync.Mutex
KeyMutex sync.Mutex
AppsByAppID map[string]*app
AppsByKey map[string]*app
Expand All @@ -34,9 +34,9 @@ func newMemdb() *memdb {
}

func (db *memdb) AddApp(a *app) error {
db.IdMutex.Lock()
db.IDMutex.Lock()
db.AppsByAppID[a.AppID] = a
db.IdMutex.Unlock()
db.IDMutex.Unlock()

db.KeyMutex.Lock()
db.AppsByKey[a.Key] = a
Expand All @@ -46,9 +46,9 @@ func (db *memdb) AddApp(a *app) error {

// GetAppByAppID returns an App with by appID
func (db *memdb) GetAppByAppID(appID string) (*app, error) {
db.IdMutex.Lock()
db.IDMutex.Lock()
a, ok := db.AppsByAppID[appID]
db.IdMutex.Unlock()
db.IDMutex.Unlock()
if ok {
return a, nil
}
Expand Down
100 changes: 71 additions & 29 deletions ipe/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import (
"sort"
"strings"

goji "goji.io"

"goji.io/pat"

log "github.com/golang/glog"
"golang.org/x/net/context"

"github.com/dimiro1/ipe/utils"
)
Expand Down Expand Up @@ -46,11 +51,11 @@ func prepareQueryString(params url.Values) string {
// * The request path (e.g. /some/resource)
// * The query parameters sorted by key, with keys converted to lowercase, then joined as in the query string.
// Note that the string must not be url escaped (e.g. given the keys auth_key: foo, Name: Something else, you get auth_key=foo&name=Something else)
func restAuthenticationHandler(ctx *applicationContext, h contextHandler) contextHandler {
return contextHandlerFunc(func(ctx *applicationContext, p params, w http.ResponseWriter, r *http.Request) {
appID := p.Get("app_id")
func restAuthenticationHandler(DB db, next goji.Handler) goji.HandlerFunc {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
appID := pat.Param(ctx, "app_id")

app, err := ctx.DB.GetAppByAppID(appID)
app, err := DB.GetAppByAppID(appID)

if err != nil {
log.Error(err)
Expand All @@ -68,20 +73,20 @@ func restAuthenticationHandler(ctx *applicationContext, h contextHandler) contex
toSign := strings.ToUpper(r.Method) + "\n" + r.URL.Path + "\n" + queryString

if utils.HashMAC([]byte(toSign), []byte(app.Secret)) == signature {
h.ServeWithContext(ctx, p, w, r)
next.ServeHTTPC(ctx, w, r)
} else {
log.Error("Not authorized")
http.Error(w, "Not authorized", http.StatusUnauthorized)
}
})
}
}

// Check if the application is disabled
func restCheckAppDisabledHandler(ctx *applicationContext, h contextHandler) contextHandler {
return contextHandlerFunc(func(ctx *applicationContext, p params, w http.ResponseWriter, r *http.Request) {
appID := p.Get("app_id")
func restCheckAppDisabledHandler(DB db, next goji.Handler) goji.HandlerFunc {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
appID := pat.Param(ctx, "app_id")

currentApp, err := ctx.DB.GetAppByAppID(appID)
currentApp, err := DB.GetAppByAppID(appID)

if err != nil {
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusForbidden)
Expand All @@ -93,16 +98,35 @@ func restCheckAppDisabledHandler(ctx *applicationContext, h contextHandler) cont
return
}

h.ServeWithContext(ctx, p, w, r)
})
next.ServeHTTPC(ctx, w, r)
}
}

func recoverHandler(next goji.Handler) goji.HandlerFunc {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
defer func() {
if r := recover(); r != nil {
log.Errorf("Please verify the url parameters error was: %s", r)
http.Error(w, "Not authorized", http.StatusUnauthorized)
return
}
}()
next.ServeHTTPC(ctx, w, r)
}
}

// commonHandlers combine restCheckAppDisabledHandler and restAuthenticationHandler handlers
func commonHandlers(ctx *applicationContext, h contextHandlerFunc) contextHandler {
return restCheckAppDisabledHandler(ctx, restAuthenticationHandler(ctx, h))
func commonHandlers(DB db, next goji.Handler) goji.HandlerFunc {
return recoverHandler(restCheckAppDisabledHandler(DB, restAuthenticationHandler(DB, next)))
}

func newPostEventsHandler(DB db) goji.HandlerFunc {
return commonHandlers(DB, &postEventsHandler{DB})
}

// An event consists of a name and data (typically JSON) which may be sent to all subscribers to a particular channel or channels.
type postEventsHandler struct{ DB db }

// ServeHTTPC An event consists of a name and data (typically JSON) which may be sent to all subscribers to a particular channel or channels.
// This is conventionally known as triggering an event.
//
// The body should contain a Hash of parameters encoded as JSON where data parameter itself is JSON encoded.
Expand All @@ -117,10 +141,10 @@ func commonHandlers(ctx *applicationContext, h contextHandlerFunc) contextHandle
// Response is an empty JSON hash.
//
// POST /apps/{app_id}/events
func postEvents(ctx *applicationContext, p params, w http.ResponseWriter, r *http.Request) {
appID := p.Get("app_id")
func (h *postEventsHandler) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
appID := pat.Param(ctx, "app_id")

app, err := ctx.DB.GetAppByAppID(appID)
app, err := h.DB.GetAppByAppID(appID)

if err != nil {
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
Expand Down Expand Up @@ -163,6 +187,12 @@ func postEvents(ctx *applicationContext, p params, w http.ResponseWriter, r *htt
w.Write([]byte("{}"))
}

func newGetChannelsHandler(DB db) goji.HandlerFunc {
return commonHandlers(DB, &getChannelsHandler{DB})
}

type getChannelsHandler struct{ DB db }

// Allows fetching a hash of occupied channels (optionally filtered by prefix),
// and optionally one or more attributes for each channel.
//
Expand All @@ -182,10 +212,10 @@ func postEvents(ctx *applicationContext, p params, w http.ResponseWriter, r *htt
// }
//
// GET /apps/{app_id}/channels
func getChannels(ctx *applicationContext, p params, w http.ResponseWriter, r *http.Request) {
func (h *getChannelsHandler) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()

appID := p.Get("app_id")
appID := pat.Param(ctx, "app_id")
filter := query.Get("filter_by_prefix")
info := query.Get("info")

Expand All @@ -206,7 +236,7 @@ func getChannels(ctx *applicationContext, p params, w http.ResponseWriter, r *ht
return
}

app, err := ctx.DB.GetAppByAppID(appID)
app, err := h.DB.GetAppByAppID(appID)

if err != nil {
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
Expand Down Expand Up @@ -252,6 +282,12 @@ func getChannels(ctx *applicationContext, p params, w http.ResponseWriter, r *ht
}
}

func newGetChannelHandler(DB db) goji.HandlerFunc {
return commonHandlers(DB, &getChannelHandler{DB})
}

type getChannelHandler struct{ DB db }

// Fetch info for one channel
//
// Example:
Expand All @@ -262,19 +298,19 @@ func getChannels(ctx *applicationContext, p params, w http.ResponseWriter, r *ht
// }
//
// GET /apps/{app_id}/channels/{channel_name}
func getChannel(ctx *applicationContext, p params, w http.ResponseWriter, r *http.Request) {
func (h *getChannelHandler) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")

query := r.URL.Query()

appID := p.Get("app_id")
app, err := ctx.DB.GetAppByAppID(appID)
appID := pat.Param(ctx, "app_id")
app, err := h.DB.GetAppByAppID(appID)

if err != nil {
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
}

channelName := p.Get("channel_name")
channelName := pat.Param(ctx, "channel_name")

// Channel name could not be empty
if strings.TrimSpace(channelName) == "" {
Expand Down Expand Up @@ -340,6 +376,12 @@ func getChannel(ctx *applicationContext, p params, w http.ResponseWriter, r *htt
}
}

func newGetChannelUsersHandler(DB db) goji.HandlerFunc {
return commonHandlers(DB, &getChannelUsersHandler{DB})
}

type getChannelUsersHandler struct{ DB db }

// Allowed only for presence-channels
//
// Example:
Expand All @@ -351,9 +393,9 @@ func getChannel(ctx *applicationContext, p params, w http.ResponseWriter, r *htt
// }
//
// GET /apps/{app_id}/channels/{channel_name}/users
func getChannelUsers(ctx *applicationContext, p params, w http.ResponseWriter, r *http.Request) {
appID := p.Get("app_id")
channelName := p.Get("channel_name")
func (h *getChannelUsersHandler) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
appID := pat.Param(ctx, "app_id")
channelName := pat.Param(ctx, "channel_name")

isPresence := utils.IsPresenceChannel(channelName)

Expand All @@ -362,7 +404,7 @@ func getChannelUsers(ctx *applicationContext, p params, w http.ResponseWriter, r
return
}

app, err := ctx.DB.GetAppByAppID(appID)
app, err := h.DB.GetAppByAppID(appID)

if err != nil {
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
Expand Down
Loading

0 comments on commit 6225d80

Please sign in to comment.