Internal refactoring. Removing the global config.
This commit is contained in:
+16
-2
@@ -33,11 +33,25 @@ type app struct {
|
||||
Stats *expvar.Map `json:"-"`
|
||||
}
|
||||
|
||||
// Alloc memory for Connections and Channels
|
||||
func (a *app) Init() {
|
||||
func newApp(name, appID, key, secret string, onlySSL, disabled, userEvents, webHooks bool, webHookURL string) *app {
|
||||
|
||||
a := &app{
|
||||
Name: name,
|
||||
AppID: appID,
|
||||
Key: key,
|
||||
Secret: secret,
|
||||
OnlySSL: onlySSL,
|
||||
ApplicationDisabled: disabled,
|
||||
UserEvents: userEvents,
|
||||
WebHooks: webHooks,
|
||||
URLWebHook: webHookURL,
|
||||
}
|
||||
|
||||
a.Connections = make(map[string]*connection)
|
||||
a.Channels = make(map[string]*channel)
|
||||
a.Stats = expvar.NewMap(fmt.Sprintf("%s (%s)", a.Name, a.AppID))
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// Only Presence channels
|
||||
|
||||
+15
-16
@@ -11,17 +11,16 @@ import (
|
||||
|
||||
var id = 0
|
||||
|
||||
func newApp() *app {
|
||||
|
||||
a := app{Name: "Test", AppID: strconv.Itoa(id), Key: "123", Secret: "123", OnlySSL: false, ApplicationDisabled: false, UserEvents: true}
|
||||
a.Init()
|
||||
func newTestApp() *app {
|
||||
|
||||
a := newApp("Test", strconv.Itoa(id), "123", "123", false, false, true, false, "")
|
||||
id++
|
||||
return &a
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func TestConnect(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
app.Connect(newConnection("socketID", nil))
|
||||
|
||||
@@ -32,7 +31,7 @@ func TestConnect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDisconnect(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
app.Connect(newConnection("socketID", nil))
|
||||
app.Disconnect("socketID")
|
||||
@@ -44,7 +43,7 @@ func TestDisconnect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindConnection(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
app.Connect(newConnection("socketID", nil))
|
||||
|
||||
@@ -59,7 +58,7 @@ func TestFindConnection(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindChannelByChannelID(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
channel := newChannel("ID")
|
||||
app.AddChannel(channel)
|
||||
@@ -70,7 +69,7 @@ func TestFindChannelByChannelID(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindOrCreateChannelByChannelID(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
if len(app.Channels) != 0 {
|
||||
t.Error("Length of channels must be 0 before test")
|
||||
@@ -85,7 +84,7 @@ func TestFindOrCreateChannelByChannelID(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRemoveChannel(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
if len(app.Channels) != 0 {
|
||||
t.Error("Length of channels must be 0 before test")
|
||||
@@ -108,7 +107,7 @@ func TestRemoveChannel(t *testing.T) {
|
||||
|
||||
func Test_add_channels(t *testing.T) {
|
||||
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
// Public
|
||||
|
||||
@@ -149,7 +148,7 @@ func Test_add_channels(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_AllChannels(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
app.AddChannel(newChannel("private-test"))
|
||||
app.AddChannel(newChannel("presence-test"))
|
||||
app.AddChannel(newChannel("test"))
|
||||
@@ -160,7 +159,7 @@ func Test_AllChannels(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_New_Subscriber(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
if len(app.Connections) != 0 {
|
||||
t.Error("Length of subscribers before test must be 0")
|
||||
@@ -175,7 +174,7 @@ func Test_New_Subscriber(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_find_subscriber(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
conn := newConnection("1", nil)
|
||||
app.Connect(conn)
|
||||
|
||||
@@ -203,7 +202,7 @@ func Test_find_subscriber(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_find_or_create_channels(t *testing.T) {
|
||||
app := newApp()
|
||||
app := newTestApp()
|
||||
|
||||
// Public
|
||||
if len(app.PublicChannels()) != 0 {
|
||||
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
// Copyright 2014 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipe
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
log "github.com/golang/glog"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/dimiro1/ipe/utils"
|
||||
)
|
||||
|
||||
// Prepare Querystring
|
||||
func prepareQueryString(params url.Values) string {
|
||||
var keys []string
|
||||
|
||||
for key := range params {
|
||||
keys = append(keys, strings.ToLower(key))
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
var pieces []string
|
||||
|
||||
for _, key := range keys {
|
||||
pieces = append(pieces, key+"="+params.Get(key))
|
||||
}
|
||||
|
||||
return strings.Join(pieces, "&")
|
||||
}
|
||||
|
||||
// Authenticate pusher
|
||||
// see: https://gist.github.com/mloughran/376898
|
||||
//
|
||||
// The signature is a HMAC SHA256 hex digest.
|
||||
// This is generated by signing a string made up of the following components concatenated with newline characters \n.
|
||||
//
|
||||
// * The uppercase request method (e.g. POST)
|
||||
// * 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(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
appID := vars["app_id"]
|
||||
|
||||
app, err := conf.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
http.Error(w, "Not authorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
params := r.URL.Query()
|
||||
|
||||
signature := params.Get("auth_signature")
|
||||
params.Del("auth_signature")
|
||||
|
||||
queryString := prepareQueryString(params)
|
||||
|
||||
toSign := strings.ToUpper(r.Method) + "\n" + r.URL.Path + "\n" + queryString
|
||||
|
||||
if utils.HashMAC([]byte(toSign), []byte(app.Secret)) == signature {
|
||||
h.ServeHTTP(w, r)
|
||||
} else {
|
||||
log.Error("Not authorized")
|
||||
http.Error(w, "Not authorized", http.StatusUnauthorized)
|
||||
}
|
||||
})
|
||||
}
|
||||
+24
-35
@@ -1,54 +1,43 @@
|
||||
// Copyright 2014 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Copyright 2014, 2016 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipe
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The config file
|
||||
type configFile struct {
|
||||
Host string // The host, eg: :8080 will start on 0.0.0.0:8080
|
||||
User string
|
||||
Password string
|
||||
SSL bool
|
||||
SSLHost string
|
||||
SSLKeyFile string
|
||||
SSLCertFile string
|
||||
|
||||
Apps []*app
|
||||
Apps []configApp
|
||||
}
|
||||
|
||||
// Initialize Apps
|
||||
func (c *configFile) Init() {
|
||||
for _, app := range c.Apps {
|
||||
app.Init()
|
||||
}
|
||||
type configApp struct {
|
||||
Name string
|
||||
AppID string
|
||||
Key string
|
||||
Secret string
|
||||
OnlySSL bool
|
||||
ApplicationDisabled bool
|
||||
UserEvents bool
|
||||
WebHooks bool
|
||||
URLWebHook string
|
||||
}
|
||||
|
||||
func (c *configFile) WasProvidedUserAndPassword() bool {
|
||||
return len(strings.TrimSpace(c.User)) > 0 && len(strings.TrimSpace(c.Password)) > 0
|
||||
}
|
||||
|
||||
// Returns an App with by appID
|
||||
func (c *configFile) GetAppByAppID(appID string) (*app, error) {
|
||||
for _, a := range c.Apps {
|
||||
if a.AppID == appID {
|
||||
return a, nil
|
||||
}
|
||||
}
|
||||
return &app{}, errors.New("App not found")
|
||||
}
|
||||
|
||||
// Returns an App with by key
|
||||
func (c *configFile) GetAppByKey(key string) (*app, error) {
|
||||
for _, a := range c.Apps {
|
||||
if a.Key == key {
|
||||
return a, nil
|
||||
}
|
||||
}
|
||||
return &app{}, errors.New("App not found")
|
||||
func newAppFromConfig(a configApp) *app {
|
||||
return newApp(
|
||||
a.Name,
|
||||
a.AppID,
|
||||
a.Key,
|
||||
a.Secret,
|
||||
a.OnlySSL,
|
||||
a.ApplicationDisabled,
|
||||
a.UserEvents,
|
||||
a.WebHooks,
|
||||
a.URLWebHook,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2016 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipe
|
||||
|
||||
import "net/http"
|
||||
|
||||
type applicationContext struct {
|
||||
DB db
|
||||
}
|
||||
|
||||
// A handlerHTTPC responds to an HTTP request with custom application context.
|
||||
type handlerHTTPC interface {
|
||||
ServeHTTPC(ctx *applicationContext, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
type handlerHTTPCFunc func(ctx *applicationContext, w http.ResponseWriter, r *http.Request)
|
||||
|
||||
func (c handlerHTTPCFunc) ServeHTTPC(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
c(ctx, w, r)
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2016 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipe
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// db represents a app database
|
||||
// For now it there is only one memory database implementation
|
||||
// but in the future I can write a sql implementation
|
||||
type db interface {
|
||||
GetAppByAppID(appID string) (*app, error)
|
||||
GetAppByKey(key string) (*app, error)
|
||||
AddApp(*app) error
|
||||
}
|
||||
|
||||
// memdb is a in memory implementation of db interface
|
||||
type memdb struct {
|
||||
sync.Mutex
|
||||
Apps []*app
|
||||
}
|
||||
|
||||
func newMemdb() *memdb {
|
||||
return &memdb{}
|
||||
}
|
||||
|
||||
func (db *memdb) AddApp(a *app) error {
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
|
||||
db.Apps = append(db.Apps, a)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAppByAppID returns an App with by appID
|
||||
func (db *memdb) GetAppByAppID(appID string) (*app, error) {
|
||||
for _, a := range db.Apps {
|
||||
if a.AppID == appID {
|
||||
return a, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("App not found")
|
||||
}
|
||||
|
||||
// GetAppByKey returns an App with by key
|
||||
func (db *memdb) GetAppByKey(key string) (*app, error) {
|
||||
for _, a := range db.Apps {
|
||||
if a.Key == key {
|
||||
return a, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("App not found")
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2016 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipe
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_db_GetAppByAppID(t *testing.T) {
|
||||
app := &app{AppID: "123456", Name: "Example"}
|
||||
|
||||
db := newMemdb()
|
||||
db.AddApp(app)
|
||||
|
||||
a, err := db.GetAppByAppID("123456")
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("GetAppByAppID(%q) == %q, want %q", "123456", a, app)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_db_GetAppByAppID__error(t *testing.T) {
|
||||
app := &app{AppID: "123456", Name: "Example"}
|
||||
|
||||
db := newMemdb()
|
||||
db.AddApp(app)
|
||||
|
||||
a, err := db.GetAppByAppID("not-found")
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("GetAppByAppID(%q) == %q, want %q", "123456", a, app)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_db_GetAppByKey(t *testing.T) {
|
||||
app := &app{AppID: "123456", Name: "Example", Key: "654321"}
|
||||
|
||||
db := newMemdb()
|
||||
db.AddApp(app)
|
||||
|
||||
a, err := db.GetAppByKey("654321")
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("GetAppByKey(%q) == %q, want %q", "654321", a, app)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_db_GetAppByKey__error(t *testing.T) {
|
||||
app := &app{AppID: "123456", Name: "Example", Key: "654321"}
|
||||
|
||||
db := newMemdb()
|
||||
db.AddApp(app)
|
||||
|
||||
a, err := db.GetAppByKey("not-found")
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("GetAppByKey(%q) == %q, want %v", "not-found", a, nil)
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2014 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Check if the application is disabled
|
||||
func restCheckAppDisabledHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
appID := vars["app_id"]
|
||||
|
||||
currentApp, err := conf.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if currentApp.ApplicationDisabled {
|
||||
http.Error(w, "Application disabled", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
@@ -8,13 +8,103 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/dimiro1/ipe/utils"
|
||||
log "github.com/golang/glog"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/dimiro1/ipe/utils"
|
||||
)
|
||||
|
||||
// Prepare Querystring
|
||||
func prepareQueryString(params url.Values) string {
|
||||
var keys []string
|
||||
|
||||
for key := range params {
|
||||
keys = append(keys, strings.ToLower(key))
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
var pieces []string
|
||||
|
||||
for _, key := range keys {
|
||||
pieces = append(pieces, key+"="+params.Get(key))
|
||||
}
|
||||
|
||||
return strings.Join(pieces, "&")
|
||||
}
|
||||
|
||||
// Authenticate pusher
|
||||
// see: https://gist.github.com/mloughran/376898
|
||||
//
|
||||
// The signature is a HMAC SHA256 hex digest.
|
||||
// This is generated by signing a string made up of the following components concatenated with newline characters \n.
|
||||
//
|
||||
// * The uppercase request method (e.g. POST)
|
||||
// * 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 handlerHTTPC) handlerHTTPC {
|
||||
return handlerHTTPCFunc(func(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
appID := vars["app_id"]
|
||||
|
||||
app, err := ctx.DB.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
http.Error(w, "Not authorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
params := r.URL.Query()
|
||||
|
||||
signature := params.Get("auth_signature")
|
||||
params.Del("auth_signature")
|
||||
|
||||
queryString := prepareQueryString(params)
|
||||
|
||||
toSign := strings.ToUpper(r.Method) + "\n" + r.URL.Path + "\n" + queryString
|
||||
|
||||
if utils.HashMAC([]byte(toSign), []byte(app.Secret)) == signature {
|
||||
h.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 handlerHTTPC) handlerHTTPC {
|
||||
return handlerHTTPCFunc(func(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
appID := vars["app_id"]
|
||||
|
||||
currentApp, err := ctx.DB.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if currentApp.ApplicationDisabled {
|
||||
http.Error(w, "Application disabled", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
h.ServeHTTPC(ctx, w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// commonHandlers combine restCheckAppDisabledHandler and restAuthenticationHandler handlers
|
||||
func commonHandlers(ctx *applicationContext, h handlerHTTPCFunc) handlerHTTPC {
|
||||
return restCheckAppDisabledHandler(ctx, restAuthenticationHandler(ctx, h))
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
@@ -30,11 +120,11 @@ import (
|
||||
// Response is an empty JSON hash.
|
||||
//
|
||||
// POST /apps/{app_id}/events
|
||||
func postEvents(w http.ResponseWriter, r *http.Request) {
|
||||
func postEvents(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
appID := vars["app_id"]
|
||||
|
||||
app, err := conf.GetAppByAppID(appID)
|
||||
app, err := ctx.DB.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
|
||||
@@ -96,7 +186,7 @@ func postEvents(w http.ResponseWriter, r *http.Request) {
|
||||
// }
|
||||
//
|
||||
// GET /apps/{app_id}/channels
|
||||
func getChannels(w http.ResponseWriter, r *http.Request) {
|
||||
func getChannels(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
params := r.URL.Query()
|
||||
vars := mux.Vars(r)
|
||||
|
||||
@@ -121,7 +211,7 @@ func getChannels(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
app, err := conf.GetAppByAppID(appID)
|
||||
app, err := ctx.DB.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
|
||||
@@ -177,14 +267,14 @@ func getChannels(w http.ResponseWriter, r *http.Request) {
|
||||
// }
|
||||
//
|
||||
// GET /apps/{app_id}/channels/{channel_name}
|
||||
func getChannel(w http.ResponseWriter, r *http.Request) {
|
||||
func getChannel(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
||||
|
||||
params := r.URL.Query()
|
||||
vars := mux.Vars(r)
|
||||
|
||||
appID := vars["app_id"]
|
||||
app, err := conf.GetAppByAppID(appID)
|
||||
app, err := ctx.DB.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
|
||||
@@ -267,7 +357,7 @@ func getChannel(w http.ResponseWriter, r *http.Request) {
|
||||
// }
|
||||
//
|
||||
// GET /apps/{app_id}/channels/{channel_name}/users
|
||||
func getChannelUsers(w http.ResponseWriter, r *http.Request) {
|
||||
func getChannelUsers(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
appID := vars["app_id"]
|
||||
@@ -280,7 +370,7 @@ func getChannelUsers(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
app, err := conf.GetAppByAppID(appID)
|
||||
app, err := ctx.DB.GetAppByAppID(appID)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not found an app with app_id: %s", appID), http.StatusBadRequest)
|
||||
+28
-7
@@ -14,25 +14,46 @@ import (
|
||||
log "github.com/golang/glog"
|
||||
)
|
||||
|
||||
// Conf holds the global configuration state
|
||||
var conf configFile
|
||||
|
||||
// Start Parse the configuration file and starts the ipe server
|
||||
// It Panic if could not start the HTTP or HTTPS server
|
||||
func Start(configfile string) {
|
||||
func Start(filename string) {
|
||||
var conf configFile
|
||||
|
||||
rand.Seed(time.Now().Unix())
|
||||
file, err := os.Open(configfile)
|
||||
file, err := os.Open(filename)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Reading config
|
||||
if err := json.NewDecoder(file).Decode(&conf); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
conf.Init()
|
||||
router := newRouter()
|
||||
// Using a in memory database
|
||||
db := newMemdb()
|
||||
|
||||
// Adding applications
|
||||
for _, a := range conf.Apps {
|
||||
db.AddApp(newAppFromConfig(a))
|
||||
}
|
||||
|
||||
// Creating the global application context
|
||||
ctx := &applicationContext{DB: db}
|
||||
|
||||
// The router
|
||||
router := newRouter(ctx)
|
||||
|
||||
router.POST("/apps/{app_id}/events", commonHandlers(ctx, postEvents))
|
||||
|
||||
router.GET("/apps/{app_id}/channels", commonHandlers(ctx, getChannels))
|
||||
|
||||
router.GET("/apps/{app_id}/channels/{channel_name}", commonHandlers(ctx, getChannel))
|
||||
|
||||
router.GET("/apps/{app_id}/channels/{channel_name}/users", commonHandlers(ctx, getChannelUsers))
|
||||
|
||||
router.GET("/app/{key}", handlerHTTPCFunc(wsHandler))
|
||||
|
||||
if conf.SSL {
|
||||
go func() {
|
||||
|
||||
+24
-16
@@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Copyright 2014, 2016 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
@@ -10,23 +10,31 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// newRouter is a function that returns a new configured Router
|
||||
// It add the necessary middlewares
|
||||
func newRouter() *mux.Router {
|
||||
router := mux.NewRouter().StrictSlash(true)
|
||||
type router struct {
|
||||
ctx *applicationContext
|
||||
mux *mux.Router
|
||||
routes map[string]handlerHTTPC
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
var handler http.Handler
|
||||
|
||||
handler = route.HandlerFunc
|
||||
func newRouter(ctx *applicationContext) *router {
|
||||
return &router{
|
||||
ctx: ctx,
|
||||
mux: mux.NewRouter().StrictSlash(true),
|
||||
}
|
||||
}
|
||||
|
||||
if route.RequiresRestAuth {
|
||||
handler = restAuthenticationHandler(handler)
|
||||
handler = restCheckAppDisabledHandler(handler)
|
||||
}
|
||||
func (a *router) GET(path string, handler handlerHTTPC) {
|
||||
a.mux.Methods("GET").Path(path).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
handler.ServeHTTPC(a.ctx, w, r)
|
||||
})
|
||||
}
|
||||
|
||||
router.Methods(route.Method).Path(route.Pattern).Name(route.Name).Handler(handler)
|
||||
}
|
||||
func (a *router) POST(path string, handler handlerHTTPC) {
|
||||
a.mux.Methods("POST").Path(path).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
handler.ServeHTTPC(a.ctx, w, r)
|
||||
})
|
||||
}
|
||||
|
||||
return router
|
||||
func (a router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
a.mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright 2014 Claudemiro Alves Feitosa Neto. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipe
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// A route
|
||||
type route struct {
|
||||
Name string
|
||||
Method string
|
||||
Pattern string
|
||||
HandlerFunc http.HandlerFunc
|
||||
RequiresRestAuth bool
|
||||
}
|
||||
|
||||
var routes = []route{
|
||||
{
|
||||
"PostEvents",
|
||||
"POST",
|
||||
"/apps/{app_id}/events",
|
||||
postEvents,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"GetChannels",
|
||||
"GET",
|
||||
"/apps/{app_id}/channels",
|
||||
getChannels,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"GetChannel",
|
||||
"GET",
|
||||
"/apps/{app_id}/channels/{channel_name}",
|
||||
getChannel,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"GetChannelUsers",
|
||||
"GET",
|
||||
"/apps/{app_id}/channels/{channel_name}/users",
|
||||
getChannelUsers,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Websocket",
|
||||
"GET",
|
||||
"/app/{key}",
|
||||
wsHandler,
|
||||
false,
|
||||
},
|
||||
}
|
||||
@@ -207,7 +207,7 @@ func onMessage(conn *websocket.Conn, w http.ResponseWriter, r *http.Request, ses
|
||||
}
|
||||
|
||||
// Websocket GET /app/{key}
|
||||
func wsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func wsHandler(ctx *applicationContext, w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
defer func() {
|
||||
if conn != nil {
|
||||
@@ -223,7 +223,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
appKey := vars["key"]
|
||||
|
||||
app, err := conf.GetAppByKey(appKey)
|
||||
app, err := ctx.DB.GetAppByKey(appKey)
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
Reference in New Issue
Block a user