Skip to content

Commit

Permalink
Adds godoc to api package
Browse files Browse the repository at this point in the history
  • Loading branch information
Javier Cervantes committed Oct 22, 2014
1 parent 6d2e25b commit ad96293
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 16 deletions.
10 changes: 10 additions & 0 deletions adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Adaptor struct {
adaptorType string
}

// AdaptorInterface defines behaviour expected for a Gobot Adaptor
type AdaptorInterface interface {
Finalize() bool
Connect() bool
Expand All @@ -22,6 +23,7 @@ type AdaptorInterface interface {
ToJSON() *JSONConnection
}

// NewAdaptor returns a new Gobot Adaptor
func NewAdaptor(name string, adaptorType string, v ...interface{}) *Adaptor {
if name == "" {
name = fmt.Sprintf("%X", Rand(int(^uint(0)>>1)))
Expand All @@ -43,34 +45,42 @@ func NewAdaptor(name string, adaptorType string, v ...interface{}) *Adaptor {
return a
}

// Port returns adaptor port
func (a *Adaptor) Port() string {
return a.port
}

// SetPort sets adaptor port
func (a *Adaptor) SetPort(s string) {
a.port = s
}

// Name returns adaptor name
func (a *Adaptor) Name() string {
return a.name
}

// SetName sets adaptor name
func (a *Adaptor) SetName(s string) {
a.name = s
}

// Type returns adaptor type
func (a *Adaptor) Type() string {
return a.adaptorType
}

// Connected returns true if adaptor is connected
func (a *Adaptor) Connected() bool {
return a.connected
}

// SetConnected sets adaptor as connected/disconnected
func (a *Adaptor) SetConnected(b bool) {
a.connected = b
}

// ToJSON returns a json representation of adaptor
func (a *Adaptor) ToJSON() *JSONConnection {
return &JSONConnection{
Name: a.Name(),
Expand Down
48 changes: 42 additions & 6 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
"github.com/hybridgroup/gobot/api/robeaux"
)

// Optional restful API through Gobot has access
// all the robots.
type api struct {
gobot *gobot.Gobot
router *pat.PatternServeMux
Expand All @@ -25,6 +23,8 @@ type api struct {
start func(*api)
}

// newAPI returns a gobot api instance
// and starts a http server using configuration options
func NewAPI(g *gobot.Gobot) *api {
return &api{
gobot: g,
Expand All @@ -47,45 +47,51 @@ func NewAPI(g *gobot.Gobot) *api {
}
}

// ServeHTTP calls api handlers and then serves request using api router
func (a *api) ServeHTTP(res http.ResponseWriter, req *http.Request) {
for _, handler := range a.handlers {
handler(res, req)
}
a.router.ServeHTTP(res, req)
}

// Post wraps api router Post call
func (a *api) Post(path string, f func(http.ResponseWriter, *http.Request)) {
a.router.Post(path, http.HandlerFunc(f))
}

// Put wraps api router Put call
func (a *api) Put(path string, f func(http.ResponseWriter, *http.Request)) {
a.router.Put(path, http.HandlerFunc(f))
}

// Delete wraps api router Delete call
func (a *api) Delete(path string, f func(http.ResponseWriter, *http.Request)) {
a.router.Del(path, http.HandlerFunc(f))
}

// Options wraps api router Options call
func (a *api) Options(path string, f func(http.ResponseWriter, *http.Request)) {
a.router.Options(path, http.HandlerFunc(f))
}

// Get wraps api router Get call
func (a *api) Get(path string, f func(http.ResponseWriter, *http.Request)) {
a.router.Get(path, http.HandlerFunc(f))
}

// Head wraps api router Head call
func (a *api) Head(path string, f func(http.ResponseWriter, *http.Request)) {
a.router.Head(path, http.HandlerFunc(f))
}

// AddHandler appends handler to api handlers
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.
// Start initializes the api by setting up c3pio routes and robeaux
func (a *api) Start() {
// api
mcpCommandRoute := "/api/commands/:command"
deviceCommandRoute := "/api/robots/:robot/devices/:device/commands/:command"
robotCommandRoute := "/api/robots/:robot/commands/:command"
Expand All @@ -108,7 +114,6 @@ func (a *api) Start() {
a.Get("/api/robots/:robot/connections/:connection", a.robotConnection)
a.Get("/api/", a.mcp)

// robeaux
a.Get("/", func(res http.ResponseWriter, req *http.Request) {
http.Redirect(res, req, "/index.html", http.StatusMovedPermanently)
})
Expand All @@ -125,6 +130,8 @@ func (a *api) Start() {
a.start(a)
}

// robeaux returns handler for robeaux routes.
// Writes asset in response and sets correct header
func (a *api) robeaux(res http.ResponseWriter, req *http.Request) {
path := req.URL.Path
buf, err := robeaux.Asset(path[1:])
Expand All @@ -141,14 +148,20 @@ func (a *api) robeaux(res http.ResponseWriter, req *http.Request) {
res.Write(buf)
}

// mcp returns MCP route handler.
// Writes JSON with gobot representation
func (a *api) mcp(res http.ResponseWriter, req *http.Request) {
a.writeJSON(map[string]interface{}{"MCP": a.gobot.ToJSON()}, res)
}

// mcpCommands returns commands route handler.
// Writes JSON with global commands representation
func (a *api) mcpCommands(res http.ResponseWriter, req *http.Request) {
a.writeJSON(map[string]interface{}{"commands": a.gobot.ToJSON().Commands}, res)
}

// robots returns route handler.
// Writes JSON with robots representation
func (a *api) robots(res http.ResponseWriter, req *http.Request) {
jsonRobots := []*gobot.JSONRobot{}
a.gobot.Robots().Each(func(r *gobot.Robot) {
Expand All @@ -157,14 +170,20 @@ func (a *api) robots(res http.ResponseWriter, req *http.Request) {
a.writeJSON(map[string]interface{}{"robots": jsonRobots}, res)
}

// robot returns route handler.
// Writes JSON with robot representation
func (a *api) robot(res http.ResponseWriter, req *http.Request) {
a.writeJSON(map[string]interface{}{"robot": a.gobot.Robot(req.URL.Query().Get(":robot")).ToJSON()}, res)
}

// robotCommands returns commands route handler
// Writes JSON with robot commands representation
func (a *api) robotCommands(res http.ResponseWriter, req *http.Request) {
a.writeJSON(map[string]interface{}{"commands": a.gobot.Robot(req.URL.Query().Get(":robot")).ToJSON().Commands}, res)
}

// robotDevices returns devices route handler.
// Writes JSON with robot devices representation
func (a *api) robotDevices(res http.ResponseWriter, req *http.Request) {
jsonDevices := []*gobot.JSONDevice{}
a.gobot.Robot(req.URL.Query().Get(":robot")).Devices().Each(func(d gobot.Device) {
Expand All @@ -173,13 +192,18 @@ func (a *api) robotDevices(res http.ResponseWriter, req *http.Request) {
a.writeJSON(map[string]interface{}{"devices": jsonDevices}, res)
}

// robotDevice returns device route handler.
// Writes JSON with robot device representation
func (a *api) robotDevice(res http.ResponseWriter, req *http.Request) {
a.writeJSON(
map[string]interface{}{"device": a.gobot.Robot(req.URL.Query().Get(":robot")).
Device(req.URL.Query().Get(":device")).ToJSON()}, res,
)
}

// robotDeviceEvent returns device event route handler.
// Creates an event stream connection
// and queries event data to be written when received
func (a *api) robotDeviceEvent(res http.ResponseWriter, req *http.Request) {
f, _ := res.(http.Flusher)
c, _ := res.(http.CloseNotifier)
Expand Down Expand Up @@ -210,13 +234,17 @@ func (a *api) robotDeviceEvent(res http.ResponseWriter, req *http.Request) {
}
}

// robotDeviceCommands returns device commands route handler
// writes JSON with robot device commands representation
func (a *api) robotDeviceCommands(res http.ResponseWriter, req *http.Request) {
a.writeJSON(
map[string]interface{}{"commands": a.gobot.Robot(req.URL.Query().Get(":robot")).
Device(req.URL.Query().Get(":device")).ToJSON().Commands}, res,
)
}

// robotConnections returns connections route handler
// writes JSON with robot connections representation
func (a *api) robotConnections(res http.ResponseWriter, req *http.Request) {
jsonConnections := []*gobot.JSONConnection{}
a.gobot.Robot(req.URL.Query().Get(":robot")).Connections().Each(func(c gobot.Connection) {
Expand All @@ -225,6 +253,8 @@ func (a *api) robotConnections(res http.ResponseWriter, req *http.Request) {
a.writeJSON(map[string]interface{}{"connections": jsonConnections}, res)
}

// robotConnection returns connection route handler
// writes JSON with robot connection representation
func (a *api) robotConnection(res http.ResponseWriter, req *http.Request) {
a.writeJSON(
map[string]interface{}{"connection": a.gobot.Robot(req.URL.Query().Get(":robot")).
Expand All @@ -233,13 +263,15 @@ func (a *api) robotConnection(res http.ResponseWriter, req *http.Request) {
)
}

// executeMcpCommand calls a global command asociated to requested route
func (a *api) executeMcpCommand(res http.ResponseWriter, req *http.Request) {
a.executeCommand(a.gobot.Command(req.URL.Query().Get(":command")),
res,
req,
)
}

// executeDeviceCommand calls a device command asociated to requested route
func (a *api) executeDeviceCommand(res http.ResponseWriter, req *http.Request) {
a.executeCommand(
a.gobot.Robot(req.URL.Query().Get(":robot")).
Expand All @@ -250,6 +282,7 @@ func (a *api) executeDeviceCommand(res http.ResponseWriter, req *http.Request) {
)
}

// executeRobotCommand calls a robot command asociated to requested route
func (a *api) executeRobotCommand(res http.ResponseWriter, req *http.Request) {
a.executeCommand(
a.gobot.Robot(req.URL.Query().Get(":robot")).
Expand All @@ -259,6 +292,7 @@ func (a *api) executeRobotCommand(res http.ResponseWriter, req *http.Request) {
)
}

// executeCommand writes JSON response with `f` returned value.
func (a *api) executeCommand(f func(map[string]interface{}) interface{},
res http.ResponseWriter,
req *http.Request,
Expand All @@ -274,12 +308,14 @@ func (a *api) executeCommand(f func(map[string]interface{}) interface{},
}
}

// writeJSON writes `j` as JSON in response
func (a *api) writeJSON(j interface{}, res http.ResponseWriter) {
data, _ := json.Marshal(j)
res.Header().Set("Content-Type", "application/json; charset=utf-8")
res.Write(data)
}

// Debug add handler to api that prints each request
func (a *api) Debug() {
a.AddHandler(func(res http.ResponseWriter, req *http.Request) {
log.Println(req)
Expand Down
4 changes: 2 additions & 2 deletions api/basic_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"net/http"
)

// BasicAuth returns basic auth handler.
// Inspired by https://github.com/codegangsta/martini-contrib/blob/master/auth/
func BasicAuth(username, password string) http.HandlerFunc {
// basic auth inspired by
// https://github.com/codegangsta/martini-contrib/blob/master/auth/
return func(res http.ResponseWriter, req *http.Request) {
if !secureCompare(req.Header.Get("Authorization"),
"Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password)),
Expand Down
5 changes: 5 additions & 0 deletions api/cors.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type CORS struct {
allowOriginPatterns []string
}

// AllowRequestFrom returns handler to verify that requests come from allowedOrigins
func AllowRequestsFrom(allowedOrigins ...string) http.HandlerFunc {
c := &CORS{
AllowOrigins: allowedOrigins,
Expand All @@ -35,6 +36,7 @@ func AllowRequestsFrom(allowedOrigins ...string) http.HandlerFunc {
}
}

// isOriginAllowed returns true if origin matches an allowed origin pattern.
func (c *CORS) isOriginAllowed(origin string) (allowed bool) {
for _, allowedOriginPattern := range c.allowOriginPatterns {
allowed, _ = regexp.MatchString(allowedOriginPattern, origin)
Expand All @@ -45,6 +47,7 @@ func (c *CORS) isOriginAllowed(origin string) (allowed bool) {
return
}

// generatePatterns generates regex expresions for AllowOrigins
func (c *CORS) generatePatterns() {
if c.AllowOrigins != nil {
for _, origin := range c.AllowOrigins {
Expand All @@ -56,10 +59,12 @@ func (c *CORS) generatePatterns() {
}
}

// AllowedHeaders returns allowed headers in a string
func (c *CORS) AllowedHeaders() string {
return strings.Join(c.AllowHeaders, ",")
}

// AllowedMethods returns allowed http methods in a string
func (c *CORS) AllowedMethods() string {
return strings.Join(c.AllowMethods, ",")
}
40 changes: 40 additions & 0 deletions api/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Package api provides functionally to expose your gobot programs
to other by using starting a web server and adding commands.
Example:
package main
import (
"fmt"
"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/api"
)
func main() {
gbot := gobot.NewGobot()
// Starts the API server on default port 3000
api.NewAPI(gbot).Start()
// Accessible via http://localhost:3000/api/commands/say_hello
gbot.AddCommand("say_hello", func(params map[string]interface{}) interface{} {
return "Master says hello!"
})
hello := gbot.AddRobot(gobot.NewRobot("Eve"))
// Accessible via http://localhost:3000/robots/Eve/commands/say_hello
hello.AddCommand("say_hello", func(params map[string]interface{}) interface{} {
return fmt.Sprintf("%v says hello!", hello.Name)
})
gbot.Start()
}
It follows Common Protocol for Programming Physical Input and Output (CPPP-IO) spec:
https://github.com/hybridgroup/cppp-io
*/
package api
Loading

0 comments on commit ad96293

Please sign in to comment.