Skip to content

Commit

Permalink
Enable custom handlers for api
Browse files Browse the repository at this point in the history
  • Loading branch information
zankich committed Jul 22, 2014
1 parent 6b74c6a commit 459e06d
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 58 deletions.
83 changes: 46 additions & 37 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type api struct {
Password string
Cert string
Key string
Debug bool
handlers []func(http.ResponseWriter, *http.Request)
start func(*api)
}

Expand All @@ -49,6 +49,10 @@ func NewAPI(g *gobot.Gobot) *api {
}
}

func (a *api) AddHandler(f func(http.ResponseWriter, *http.Request)) {
a.handlers = append(a.handlers, f)
}

// start starts the api using the start function
// sets on the API on initialization.
func (a *api) Start() {
Expand All @@ -58,45 +62,40 @@ func (a *api) Start() {
deviceCommandRoute := "/robots/:robot/devices/:device/commands/:command"
robotCommandRoute := "/robots/:robot/commands/:command"

a.server.Get("/", a.setHeaders(a.mcp))
a.server.Get("/commands", a.setHeaders(a.mcpCommands))
a.server.Get(mcpCommandRoute, a.setHeaders(a.executeMcpCommand))
a.server.Post(mcpCommandRoute, a.setHeaders(a.executeMcpCommand))
a.server.Get("/robots", a.setHeaders(a.robots))
a.server.Get("/robots/:robot", a.setHeaders(a.robot))
a.server.Get("/robots/:robot/commands", a.setHeaders(a.robotCommands))
a.server.Get(robotCommandRoute, a.setHeaders(a.executeRobotCommand))
a.server.Post(robotCommandRoute, a.setHeaders(a.executeRobotCommand))
a.server.Get("/robots/:robot/devices", a.setHeaders(a.robotDevices))
a.server.Get("/robots/:robot/devices/:device", a.setHeaders(a.robotDevice))
a.server.Get("/", a.run(a.mcp))
a.server.Get("/commands", a.run(a.mcpCommands))
a.server.Get(mcpCommandRoute, a.run(a.executeMcpCommand))
a.server.Post(mcpCommandRoute, a.run(a.executeMcpCommand))
a.server.Get("/robots", a.run(a.robots))
a.server.Get("/robots/:robot", a.run(a.robot))
a.server.Get("/robots/:robot/commands", a.run(a.robotCommands))
a.server.Get(robotCommandRoute, a.run(a.executeRobotCommand))
a.server.Post(robotCommandRoute, a.run(a.executeRobotCommand))
a.server.Get("/robots/:robot/devices", a.run(a.robotDevices))
a.server.Get("/robots/:robot/devices/:device", a.run(a.robotDevice))
a.server.Get("/robots/:robot/devices/:device/commands",
a.setHeaders(a.robotDeviceCommands),
a.run(a.robotDeviceCommands),
)
a.server.Get(deviceCommandRoute, a.setHeaders(a.executeDeviceCommand))
a.server.Post(deviceCommandRoute, a.setHeaders(a.executeDeviceCommand))
a.server.Get("/robots/:robot/connections", a.setHeaders(a.robotConnections))
a.server.Get(deviceCommandRoute, a.run(a.executeDeviceCommand))
a.server.Post(deviceCommandRoute, a.run(a.executeDeviceCommand))
a.server.Get("/robots/:robot/connections", a.run(a.robotConnections))
a.server.Get("/robots/:robot/connections/:connection",
a.setHeaders(a.robotConnection),
a.run(a.robotConnection),
)
a.server.Get("/:a", a.setHeaders(a.robeaux))
a.server.Get("/:a/", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b/", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b/:c", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b/:c/", a.setHeaders(a.robeaux))
a.server.Get("/:a", a.run(a.robeaux))
a.server.Get("/:a/", a.run(a.robeaux))
a.server.Get("/:a/:b", a.run(a.robeaux))
a.server.Get("/:a/:b/", a.run(a.robeaux))
a.server.Get("/:a/:b/:c", a.run(a.robeaux))
a.server.Get("/:a/:b/:c/", a.run(a.robeaux))

a.start(a)
}

func (a *api) setHeaders(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
func (a *api) run(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
return func(res http.ResponseWriter, req *http.Request) {
if a.Debug {
log.Println(req)
}
if a.Username != "" {
if !a.basicAuth(res, req) {
return
}
for _, handler := range a.handlers {
handler(res, req)
}
f(res, req)
}
Expand Down Expand Up @@ -209,7 +208,7 @@ func (a *api) robotConnection(res http.ResponseWriter, req *http.Request) {

func (a *api) executeMcpCommand(res http.ResponseWriter, req *http.Request) {
var data []byte
var body map[string]interface{}
body := make(map[string]interface{})
command := req.URL.Query().Get(":command")

json.NewDecoder(req.Body).Decode(&body)
Expand All @@ -226,11 +225,11 @@ func (a *api) executeMcpCommand(res http.ResponseWriter, req *http.Request) {
}

func (a *api) executeDeviceCommand(res http.ResponseWriter, req *http.Request) {
var body map[string]interface{}
var data []byte
robot := req.URL.Query().Get(":robot")
device := req.URL.Query().Get(":device")
command := req.URL.Query().Get(":command")
body := make(map[string]interface{})

json.NewDecoder(req.Body).Decode(&body)
d := a.gobot.Robot(robot).Device(device)
Expand All @@ -249,11 +248,11 @@ func (a *api) executeDeviceCommand(res http.ResponseWriter, req *http.Request) {

func (a *api) executeRobotCommand(res http.ResponseWriter, req *http.Request) {
var data []byte
var body map[string]interface{}

robot := req.URL.Query().Get(":robot")
command := req.URL.Query().Get(":command")

body := make(map[string]interface{})
json.NewDecoder(req.Body).Decode(&body)
r := a.gobot.Robot(robot)
body["robot"] = robot
Expand All @@ -269,9 +268,21 @@ func (a *api) executeRobotCommand(res http.ResponseWriter, req *http.Request) {
res.Write(data)
}

func (a *api) SetBasicAuth(user, password string) {
a.Username = user
a.Password = password
a.AddHandler(a.basicAuth)
}

func (a *api) SetDebug() {
a.AddHandler(func(res http.ResponseWriter, req *http.Request) {
log.Println(req)
})
}

// basic auth inspired by
// https://github.com/codegangsta/martini-contrib/blob/master/auth/
func (a *api) basicAuth(res http.ResponseWriter, req *http.Request) bool {
func (a *api) basicAuth(res http.ResponseWriter, req *http.Request) {
auth := req.Header.Get("Authorization")
if !a.secureCompare(auth,
"Basic "+base64.StdEncoding.EncodeToString([]byte(a.Username+":"+a.Password)),
Expand All @@ -280,9 +291,7 @@ func (a *api) basicAuth(res http.ResponseWriter, req *http.Request) bool {
"Basic realm=\"Authorization Required\"",
)
http.Error(res, "Not Authorized", http.StatusUnauthorized)
return false
}
return true
}

func (a *api) secureCompare(given string, actual string) bool {
Expand Down
5 changes: 2 additions & 3 deletions api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ func initTestAPI() *api {
log.SetOutput(gobot.NullReadWriteCloser{})
g := gobot.NewGobot()
a := NewAPI(g)
a.Debug = true
a.start = func(m *api) {}
a.Start()
a.SetDebug()

g.AddRobot(gobot.NewTestRobot("Robot1"))
g.AddRobot(gobot.NewTestRobot("Robot2"))
Expand All @@ -33,8 +33,7 @@ func initTestAPI() *api {
func TestBasicAuth(t *testing.T) {
a := initTestAPI()

a.Username = "admin"
a.Password = "password"
a.SetBasicAuth("admin", "password")

request, _ := http.NewRequest("GET", "/", nil)
request.SetBasicAuth("admin", "password")
Expand Down
16 changes: 13 additions & 3 deletions examples/hello_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,28 @@ package main

import (
"fmt"
"html"
"net/http"

"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/api"
)

func main() {
gbot := gobot.NewGobot()
api.NewAPI(gbot).Start()

gbot.AddCommand("custom_gobot_command", func(params map[string]interface{}) interface{} {
return "This command is attached to the master!"
a := api.NewAPI(gbot)
a.SetDebug()

a.AddHandler(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q \n", html.EscapeString(r.URL.Path))
})
a.Start()

gbot.AddCommand("custom_gobot_command",
func(params map[string]interface{}) interface{} {
return "This command is attached to the mcp!"
})

hello := gbot.AddRobot(gobot.NewRobot("hello"))

Expand Down
21 changes: 16 additions & 5 deletions examples/hello_api_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"fmt"
"html"
"net/http"

"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/api"
Expand All @@ -10,15 +12,24 @@ import (
func main() {
gbot := gobot.NewGobot()

server := api.NewAPI(gbot)
server.Username = "gort"
server.Password = "klatuu"
server.Start()
a := api.NewAPI(gbot)
a.SetBasicAuth("gort", "klatuu")
a.SetDebug()

a.AddHandler(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q \n", html.EscapeString(r.URL.Path))
})
a.Start()

gbot.AddCommand("custom_gobot_command",
func(params map[string]interface{}) interface{} {
return "This command is attached to the mcp!"
})

hello := gbot.AddRobot(gobot.NewRobot("hello"))

hello.AddCommand("hi_there", func(params map[string]interface{}) interface{} {
return []string{fmt.Sprintf("Hey"), fmt.Sprintf("dude!")}
return fmt.Sprintf("This command is attached to the robot %v", hello.Name)
})

gbot.Start()
Expand Down
20 changes: 10 additions & 10 deletions gobot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ func initTestGobot() *Gobot {
g.trap = func(c chan os.Signal) {
c <- os.Interrupt
}
g.AddRobot(NewTestRobot("Robot 1"))
g.AddRobot(NewTestRobot("Robot 2"))
g.AddRobot(NewTestRobot("Robot 3"))
g.AddRobot(NewTestRobot("Robot1"))
g.AddRobot(NewTestRobot("Robot2"))
g.AddRobot(NewTestRobot("Robot3"))
return g
}

Expand All @@ -25,13 +25,13 @@ func TestGobotStart(t *testing.T) {

func TestGobotRobot(t *testing.T) {
g := initTestGobot()
Assert(t, g.Robot("Robot 1").Name, "Robot 1")
Assert(t, g.Robot("Robot 4"), (*Robot)(nil))
Assert(t, g.Robot("Robot 1").Device("Device 4"), (Device)(nil))
Assert(t, g.Robot("Robot 1").Device("Device 1").Name(), "Device 1")
Assert(t, g.Robot("Robot 1").Devices().Len(), 3)
Assert(t, g.Robot("Robot 1").Connection("Connection 4"), (Connection)(nil))
Assert(t, g.Robot("Robot 1").Connections().Len(), 3)
Assert(t, g.Robot("Robot1").Name, "Robot1")
Assert(t, g.Robot("Robot4"), (*Robot)(nil))
Assert(t, g.Robot("Robot1").Device("Device4"), (Device)(nil))
Assert(t, g.Robot("Robot1").Device("Device1").Name(), "Device1")
Assert(t, g.Robot("Robot1").Devices().Len(), 3)
Assert(t, g.Robot("Robot1").Connection("Connection4"), (Connection)(nil))
Assert(t, g.Robot("Robot1").Connections().Len(), 3)
}

func TestGobotToJSON(t *testing.T) {
Expand Down

0 comments on commit 459e06d

Please sign in to comment.