From 26a9e5598375ca095310e5417494da150dc98331 Mon Sep 17 00:00:00 2001 From: Adrian Zankich Date: Thu, 15 May 2014 11:50:45 -0700 Subject: [PATCH] WIP api refactor --- api/api.go | 118 +++++++++++++++--------------------------- api/api_convention.go | 21 -------- api/api_suite_test.go | 20 +++++++ api/api_test.go | 22 ++++---- connection.go | 18 ++++++- device.go | 22 +++++++- robot.go | 24 ++++++++- test_helper.go | 3 ++ 8 files changed, 132 insertions(+), 116 deletions(-) delete mode 100644 api/api_convention.go create mode 100644 api/api_suite_test.go diff --git a/api/api.go b/api/api.go index d44d02c7d..dfc20b901 100644 --- a/api/api.go +++ b/api/api.go @@ -27,10 +27,10 @@ type api struct { start func(*api) } -func NewApi(g gobot.Gobot) *api { +func NewApi(g *gobot.Gobot) *api { return &api{ - Gobot: g, - startFunc: func(a *api) { + gobot: g, + start: func(a *api) { if a == nil { return } @@ -68,170 +68,136 @@ func NewApi(g gobot.Gobot) *api { func (a *api) Start() { a.server = martini.Classic() - m.Use(martini.Static("robeaux")) - m.Use(cors.Allow(&cors.Options{ + a.server.Use(martini.Static("robeaux")) + a.server.Use(cors.Allow(&cors.Options{ AllowAllOrigins: true, })) - m.Get("/robots", func(res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots", func(res http.ResponseWriter, req *http.Request) { a.robots(res, req) }) - m.Get("/robots/:robotname", func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots/:robotname", func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.robot(params["robotname"], res, req) }) - m.Get("/robots/:robotname/commands", func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots/:robotname/commands", func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.robot_commands(params["robotname"], res, req) }) robot_command_route := "/robots/:robotname/commands/:command" - m.Get(robot_command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get(robot_command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.executeRobotCommand(params["robotname"], params["command"], res, req) }) - m.Post(robot_command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Post(robot_command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.executeRobotCommand(params["robotname"], params["command"], res, req) }) - m.Get("/robots/:robotname/devices", func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots/:robotname/devices", func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.robot_devices(params["robotname"], res, req) }) - m.Get("/robots/:robotname/devices/:devicename", func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots/:robotname/devices/:devicename", func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.robot_device(params["robotname"], params["devicename"], res, req) }) - m.Get("/robots/:robotname/devices/:devicename/commands", func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots/:robotname/devices/:devicename/commands", func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.robot_device_commands(params["robotname"], params["devicename"], res, req) }) command_route := "/robots/:robotname/devices/:devicename/commands/:command" - m.Get(command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get(command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.executeCommand(params["robotname"], params["devicename"], params["command"], res, req) }) - m.Post(command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Post(command_route, func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.executeCommand(params["robotname"], params["devicename"], params["command"], res, req) }) - m.Get("/robots/:robotname/connections", func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots/:robotname/connections", func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.robot_connections(params["robotname"], res, req) }) - m.Get("/robots/:robotname/connections/:connectionname", func(params martini.Params, res http.ResponseWriter, req *http.Request) { + a.server.Get("/robots/:robotname/connections/:connectionname", func(params martini.Params, res http.ResponseWriter, req *http.Request) { a.robot_connection(params["robotname"], params["connectionname"], res, req) }) a.start(a) } -func (me *api) robots(res http.ResponseWriter, req *http.Request) { - jsonRobots := make([]*jsonRobot, 0) - for _, robot := range me.master.Robots { - jsonRobots = append(jsonRobots, me.formatJsonRobot(robot)) +func (a *api) robots(res http.ResponseWriter, req *http.Request) { + jsonRobots := make([]*gobot.JsonRobot, 0) + for _, robot := range a.gobot.Robots { + jsonRobots = append(jsonRobots, robot.ToJson()) } data, _ := json.Marshal(jsonRobots) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (me *api) robot(name string, res http.ResponseWriter, req *http.Request) { - data, _ := json.Marshal(me.formatJsonRobot(me.master.FindRobot(name))) +func (a *api) robot(name string, res http.ResponseWriter, req *http.Request) { + data, _ := json.Marshal(a.gobot.Robot(name).ToJson()) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (me *api) robot_commands(name string, res http.ResponseWriter, req *http.Request) { - data, _ := json.Marshal(me.master.FindRobot(name).RobotCommands) +func (a *api) robot_commands(name string, res http.ResponseWriter, req *http.Request) { + data, _ := json.Marshal(a.gobot.Robot(name).RobotCommands) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (me *api) robot_devices(name string, res http.ResponseWriter, req *http.Request) { - devices := me.master.FindRobot(name).GetDevices() - jsonDevices := make([]*jsonDevice, 0) +func (a *api) robot_devices(name string, res http.ResponseWriter, req *http.Request) { + devices := a.gobot.Robot(name).Devices() + jsonDevices := make([]*gobot.JsonDevice, 0) for _, device := range devices { - jsonDevices = append(jsonDevices, me.formatJsonDevice(device)) + jsonDevices = append(jsonDevices, device.ToJson()) } data, _ := json.Marshal(jsonDevices) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (me *api) robot_device(robot string, device string, res http.ResponseWriter, req *http.Request) { - data, _ := json.Marshal(me.formatJsonDevice(me.master.FindRobot(robot).GetDevice(device))) +func (a *api) robot_device(robot string, device string, res http.ResponseWriter, req *http.Request) { + data, _ := json.Marshal(a.gobot.Robot(robot).Device(device).ToJson()) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (me *api) robot_device_commands(robot string, device string, res http.ResponseWriter, req *http.Request) { - data, _ := json.Marshal(me.master.FindRobot(robot).GetDevice(device).Commands()) +func (a *api) robot_device_commands(robot string, device string, res http.ResponseWriter, req *http.Request) { + data, _ := json.Marshal(a.gobot.Robot(robot).Device(device).Commands()) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (me *api) robot_connections(name string, res http.ResponseWriter, req *http.Request) { - connections := me.master.FindRobot(name).GetConnections() - jsonConnections := make([]*jsonConnection, 0) +func (a *api) robot_connections(name string, res http.ResponseWriter, req *http.Request) { + connections := a.gobot.Robot(name).Connections() + jsonConnections := make([]*gobot.JsonConnection, 0) for _, connection := range connections { - jsonConnections = append(jsonConnections, me.formatJsonConnection(connection)) + jsonConnections = append(jsonConnections, connection.ToJson()) } data, _ := json.Marshal(jsonConnections) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (me *api) robot_connection(robot string, connection string, res http.ResponseWriter, req *http.Request) { - data, _ := json.Marshal(me.formatJsonConnection(me.master.FindRobot(robot).GetConnection(connection))) +func (a *api) robot_connection(robot string, connection string, res http.ResponseWriter, req *http.Request) { + data, _ := json.Marshal(a.gobot.Robot(robot).Connection(connection).ToJson()) res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Write(data) } -func (a *api) formatJsonRobot(robot *Robot) *jsonRobot { - jsonRobot := new(jsonRobot) - jsonRobot.Name = robot.Name - jsonRobot.Commands = robot.RobotCommands - jsonRobot.Connections = make([]*jsonConnection, 0) - for _, device := range robot.devices { - jsonDevice := a.formatJsonDevice(device) - jsonRobot.Connections = append(jsonRobot.Connections, jsonDevice.Connection) - jsonRobot.Devices = append(jsonRobot.Devices, jsonDevice) - } - return jsonRobot -} - -func (a *api) formatJsonConnection(connection *connection) *jsonConnection { - jsonConnection := new(jsonConnection) - jsonConnection.Name = connection.Name - jsonConnection.Port = connection.Port - jsonConnection.Adaptor = connection.Type - return jsonConnection -} - -func (a *api) formatJsonDevice(device *device) *jsonDevice { - jsonDevice := new(jsonDevice) - jsonDevice.Name = device.Name - jsonDevice.Driver = device.Type - jsonDevice.Connection = a.formatJsonConnection( - a.master.FindRobot(device.Robot.Name). - GetConnection(FieldByNamePtr(FieldByNamePtr(device.Driver, "Adaptor"). - Interface().(AdaptorInterface), "Name"). - Interface().(string))) - jsonDevice.Commands = FieldByNamePtr(device.Driver, "Commands").Interface().([]string) - return jsonDevice -} - func (a *api) executeCommand(robotname string, devicename string, commandname string, res http.ResponseWriter, req *http.Request) { data, _ := ioutil.ReadAll(req.Body) var body map[string]interface{} json.Unmarshal(data, &body) - robot := a.master.FindRobot(robotname).GetDevice(devicename) + robot := a.gobot.Robot(robotname).Device(devicename) commands := robot.Commands().([]string) for command := range commands { if commands[command] == commandname { ret := make([]interface{}, 0) - for _, v := range Call(robot.Driver, commandname, body) { + for _, v := range gobot.Call(robot.Driver, commandname, body) { ret = append(ret, v.Interface()) } data, _ = json.Marshal(ret) @@ -249,7 +215,7 @@ func (a *api) executeRobotCommand(robotname string, commandname string, res http data, _ := ioutil.ReadAll(req.Body) body := make(map[string]interface{}) json.Unmarshal(data, &body) - robot := a.master.FindRobot(robotname) + robot := a.gobot.Robot(robotname) in := make([]reflect.Value, 1) body["robotname"] = robotname in[0] = reflect.ValueOf(body) diff --git a/api/api_convention.go b/api/api_convention.go deleted file mode 100644 index 053ff5a1b..000000000 --- a/api/api_convention.go +++ /dev/null @@ -1,21 +0,0 @@ -package api - -type jsonRobot struct { - Name string `json:"name"` - Commands []string `json:"commands"` - Connections []*jsonConnection `json:"connections"` - Devices []*jsonDevice `json:"devices"` -} - -type jsonDevice struct { - Name string `json:"name"` - Driver string `json:"driver"` - Connection *jsonConnection `json:"connection"` - Commands []string `json:"commands"` -} - -type jsonConnection struct { - Name string `json:"name"` - Port string `json:"port"` - Adaptor string `json:"adaptor"` -} diff --git a/api/api_suite_test.go b/api/api_suite_test.go new file mode 100644 index 000000000..22011f173 --- /dev/null +++ b/api/api_suite_test.go @@ -0,0 +1,20 @@ +package api + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "log" + "testing" +) + +type null struct{} + +func (null) Write(p []byte) (int, error) { + return len(p), nil +} + +func TestApi(t *testing.T) { + log.SetOutput(new(null)) + RegisterFailHandler(Fail) + RunSpecs(t, "Api Suite") +} diff --git a/api/api_test.go b/api/api_test.go index 4b69ba747..bb7e490a6 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -3,34 +3,30 @@ package api import ( "bytes" "encoding/json" + "github.com/hybridgroup/gobot" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "io/ioutil" "net/http" "net/http/httptest" - "os" ) var _ = Describe("Master", func() { var ( - m *Master + m *gobot.Gobot a *api ) BeforeEach(func() { - m = NewMaster() - a = Api(m) - a.startFunc = func(m *api) {} + m = gobot.NewGobot() + a = NewApi(m) + a.start = func(m *api) {} - m.Robots = []*Robot{ - newTestRobot("Robot 1"), - newTestRobot("Robot 2"), - newTestRobot("Robot 3"), + m.Robots = []*gobot.Robot{ + gobot.NewTestRobot("Robot 1"), + gobot.NewTestRobot("Robot 2"), + gobot.NewTestRobot("Robot 3"), } - m.trap = func(c chan os.Signal) { - c <- os.Interrupt - } - m.Start() }) Context("when valid", func() { diff --git a/connection.go b/connection.go index 61e3a8aa8..96c833e68 100644 --- a/connection.go +++ b/connection.go @@ -11,9 +11,15 @@ type Connection interface { Finalize() bool } +type JsonConnection struct { + Name string `json:"name"` + Port string `json:"port"` + Adaptor string `json:"adaptor"` +} + type connection struct { - Name string `json:"name"` - Type string `json:"adaptor"` + Name string `json:"-"` + Type string `json:"-"` Adaptor AdaptorInterface `json:"-"` Port string `json:"-"` Robot *Robot `json:"-"` @@ -68,3 +74,11 @@ func (c *connection) Finalize() bool { log.Println("Finalizing " + c.Name + "...") return c.Adaptor.Finalize() } + +func (c *connection) ToJson() *JsonConnection { + jsonConnection := new(JsonConnection) + jsonConnection.Name = c.Name + jsonConnection.Port = c.Port + jsonConnection.Adaptor = c.Type + return jsonConnection +} diff --git a/device.go b/device.go index c00d4a79f..53125341d 100644 --- a/device.go +++ b/device.go @@ -12,9 +12,16 @@ type Device interface { Halt() bool } +type JsonDevice struct { + Name string `json:"name"` + Driver string `json:"driver"` + Connection *JsonConnection `json:"connection"` + Commands []string `json:"commands"` +} + type device struct { - Name string `json:"name"` - Type string `json:"driver"` + Name string `json:"-"` + Type string `json:"-"` Interval time.Duration `json:"-"` Robot *Robot `json:"-"` Driver DriverInterface `json:"-"` @@ -69,3 +76,14 @@ func (d *device) Halt() bool { func (d *device) Commands() interface{} { return FieldByNamePtr(d.Driver, "Commands").Interface() } + +func (d *device) ToJson() *JsonDevice { + jsonDevice := new(JsonDevice) + jsonDevice.Name = d.Name + jsonDevice.Driver = d.Type + jsonDevice.Connection = d.Robot.Connection(FieldByNamePtr(FieldByNamePtr(d.Driver, "Adaptor"). + Interface().(AdaptorInterface), "Name"). + Interface().(string)).ToJson() + jsonDevice.Commands = FieldByNamePtr(d.Driver, "Commands").Interface().([]string) + return jsonDevice +} diff --git a/robot.go b/robot.go index 48bf960ca..72a88c980 100644 --- a/robot.go +++ b/robot.go @@ -7,10 +7,17 @@ import ( "time" ) +type JsonRobot struct { + Name string `json:"name"` + Commands []string `json:"commands"` + Connections []*JsonConnection `json:"connections"` + Devices []*JsonDevice `json:"devices"` +} + type Robot struct { - Name string `json:"name"` + Name string `json:"-"` Commands map[string]interface{} `json:"-"` - RobotCommands []string `json:"commands"` + RobotCommands []string `json:"-"` Work func() `json:"-"` connections connections `json:"-"` devices devices `json:"-"` @@ -121,3 +128,16 @@ func (r *Robot) Connection(name string) *connection { } return nil } + +func (r *Robot) ToJson() *JsonRobot { + jsonRobot := new(JsonRobot) + jsonRobot.Name = r.Name + jsonRobot.Commands = r.RobotCommands + jsonRobot.Connections = make([]*JsonConnection, 0) + for _, device := range r.Devices() { + jsonDevice := device.ToJson() + jsonRobot.Connections = append(jsonRobot.Connections, jsonDevice.Connection) + jsonRobot.Devices = append(jsonRobot.Devices, jsonDevice) + } + return jsonRobot +} diff --git a/test_helper.go b/test_helper.go index 38d443755..53706e5c7 100644 --- a/test_helper.go +++ b/test_helper.go @@ -66,6 +66,9 @@ func robotTestFunction(params map[string]interface{}) string { return fmt.Sprintf("hey %v, %v", robotname, message) } +func NewTestRobot(name string) *Robot { + return newTestRobot(name) +} func newTestRobot(name string) *Robot { adaptor1 := newTestAdaptor("Connection 1") adaptor2 := newTestAdaptor("Connection 2")