1
0
mirror of https://github.com/hybridgroup/gobot.git synced 2025-04-26 13:48:49 +08:00

WIP project restructure

This commit is contained in:
Adrian Zankich 2014-04-29 13:20:32 -07:00
parent 86f0580f58
commit 90ee5d7d70
190 changed files with 310 additions and 307 deletions

View File

@ -1,46 +0,0 @@
package gobot
import (
"log"
"reflect"
)
type connection struct {
Name string `json:"name"`
Type string `json:"adaptor"`
Adaptor AdaptorInterface `json:"-"`
Port string `json:"-"`
Robot *Robot `json:"-"`
Params map[string]interface{} `json:"-"`
}
type Connection interface {
Connect() bool
Finalize() bool
}
func NewConnection(adaptor AdaptorInterface, r *Robot) *connection {
c := new(connection)
s := reflect.ValueOf(adaptor).Type().String()
c.Type = s[1:len(s)]
c.Name = FieldByNamePtr(adaptor, "Name").String()
c.Port = FieldByNamePtr(adaptor, "Port").String()
c.Params = make(map[string]interface{})
keys := FieldByNamePtr(adaptor, "Params").MapKeys()
for k := range keys {
c.Params[keys[k].String()] = FieldByNamePtr(adaptor, "Params").MapIndex(keys[k])
}
c.Robot = r
c.Adaptor = adaptor
return c
}
func (c *connection) Connect() bool {
log.Println("Connecting to " + c.Name + " on port " + c.Port + "...")
return c.Adaptor.Connect()
}
func (c *connection) Finalize() bool {
log.Println("Finalizing " + c.Name + "...")
return c.Adaptor.Finalize()
}

View File

@ -1,4 +1,4 @@
package gobot
package adaptor
type Adaptor struct {
Name string `json:"name"`

View File

@ -1,4 +1,4 @@
package gobot
package api
import (
"encoding/json"
@ -8,77 +8,65 @@ import (
"reflect"
"github.com/go-martini/martini"
"github.com/hybridgroup/gobot"
"github.com/martini-contrib/auth"
"github.com/martini-contrib/cors"
)
type startFuncAlias func(*api)
// Optional restful API through the master to access
// Optional restful API through Gobot has access
// all the robots.
type api struct {
master *Master
server *martini.ClassicMartini
Host string
Port string
Username string
Password string
Cert string
Key string
startFunc startFuncAlias
gobot *gobot.Gobot
server *martini.ClassicMartini
Host string
Port string
Username string
Password string
Cert string
Key string
start func(*api)
}
func NewApi() *api {
return &api{startFunc: defaultStartFunc}
}
func NewApi(g gobot.Gobot) *api {
return &api{
Gobot: g,
startFunc: func(a *api) {
if a == nil {
return
}
var defaultStartFunc = func(a *api) {
if a == nil {
return
username := a.Username
if username != "" {
password := a.Password
a.server.Use(auth.Basic(username, password))
}
port := a.Port
if port == "" {
port = "3000"
}
host := a.Host
cert := a.Cert
key := a.Key
log.Println("Initializing API on " + host + ":" + port + "...")
go func() {
if cert != "" && key != "" {
http.ListenAndServeTLS(host+":"+port, cert, key, a.server)
} else {
log.Println("WARNING: API using insecure connection. We recommend using an SSL certificate with Gobot.")
http.ListenAndServe(host+":"+port, a.server)
}
}()
},
}
username := a.Username
if username != "" {
password := a.Password
a.server.Use(auth.Basic(username, password))
}
port := a.Port
if port == "" {
port = "3000"
}
host := a.Host
cert := a.Cert
key := a.Key
log.Println("Initializing API on " + host + ":" + port + "...")
go func() {
if cert != "" && key != "" {
http.ListenAndServeTLS(host+":"+port, cert, key, a.server)
} else {
log.Println("WARNING: API using insecure connection. We recommend using an SSL certificate with Gobot.")
http.ListenAndServe(host+":"+port, a.server)
}
}()
}
// start starts the api using the start function
// sets on the API on initialization.
func (a *api) start() {
if a == nil {
return
}
a.startFunc(a)
}
func Api(bot *Master) *api {
a := new(api)
a.master = bot
bot.Api = a
m := martini.Classic()
a.server = m
func (a *api) Start() {
a.server = martini.Classic()
m.Use(martini.Static("robeaux"))
m.Use(cors.Allow(&cors.Options{
@ -135,7 +123,7 @@ func Api(bot *Master) *api {
a.robot_connection(params["robotname"], params["connectionname"], res, req)
})
return a
a.start(a)
}
func (me *api) robots(res http.ResponseWriter, req *http.Request) {

View File

@ -1,4 +1,4 @@
package gobot
package api
type jsonRobot struct {
Name string `json:"name"`

View File

@ -1,4 +1,4 @@
package gobot
package api
import (
"bytes"

View File

@ -1,4 +1,4 @@
package gobot
package driver
type Driver struct {
Interval string `json:"interval"`

72
core/robot/connection.go Normal file
View File

@ -0,0 +1,72 @@
package robot
import (
"errors"
"github.com/hybridgroup/gobot/core/adaptor"
"github.com/hybridgroup/gobot/core/utils"
"log"
"reflect"
)
type connection struct {
Name string `json:"name"`
Type string `json:"adaptor"`
Adaptor adaptor.AdaptorInterface `json:"-"`
Port string `json:"-"`
Robot *Robot `json:"-"`
Params map[string]interface{} `json:"-"`
}
type Connection interface {
Connect() bool
Finalize() bool
}
type connections []*connection
// Start() starts all the connections.
func (c connections) Start() error {
var err error
log.Println("Starting connections...")
for _, connection := range c {
log.Println("Starting connection " + connection.Name + "...")
if connection.Connect() == false {
err = errors.New("Could not start connection")
break
}
}
return err
}
// Filanize() finalizes all the connections.
func (c connections) Finalize() {
for _, connection := range c {
connection.Finalize()
}
}
func NewConnection(adaptor adaptor.AdaptorInterface, r *Robot) *connection {
c := new(connection)
s := reflect.ValueOf(adaptor).Type().String()
c.Type = s[1:len(s)]
c.Name = utils.FieldByNamePtr(adaptor, "Name").String()
c.Port = utils.FieldByNamePtr(adaptor, "Port").String()
c.Params = make(map[string]interface{})
keys := utils.FieldByNamePtr(adaptor, "Params").MapKeys()
for k := range keys {
c.Params[keys[k].String()] = utils.FieldByNamePtr(adaptor, "Params").MapIndex(keys[k])
}
c.Robot = r
c.Adaptor = adaptor
return c
}
func (c *connection) Connect() bool {
log.Println("Connecting to " + c.Name + " on port " + c.Port + "...")
return c.Adaptor.Connect()
}
func (c *connection) Finalize() bool {
log.Println("Finalizing " + c.Name + "...")
return c.Adaptor.Finalize()
}

78
core/robot/device.go Normal file
View File

@ -0,0 +1,78 @@
package robot
import (
"errors"
"github.com/hybridgroup/gobot/core/driver"
"github.com/hybridgroup/gobot/core/utils"
"log"
"reflect"
)
type Device interface {
Init() bool
Start() bool
Halt() bool
}
type device struct {
Name string `json:"name"`
Type string `json:"driver"`
Interval string `json:"-"`
Robot *Robot `json:"-"`
Driver driver.DriverInterface `json:"-"`
}
type devices []*device
// Start() starts all the devices.
func (d devices) Start() error {
var err error
log.Println("Starting devices...")
for _, device := range d {
log.Println("Starting device " + device.Name + "...")
if device.Start() == false {
err = errors.New("Could not start connection")
break
}
}
return err
}
// Halt() stop all the devices.
func (d devices) Halt() {
for _, device := range d {
device.Halt()
}
}
func NewDevice(driver driver.DriverInterface, r *Robot) *device {
d := new(device)
s := reflect.ValueOf(driver).Type().String()
d.Type = s[1:len(s)]
d.Name = utils.FieldByNamePtr(driver, "Name").String()
d.Robot = r
if utils.FieldByNamePtr(driver, "Interval").String() == "" {
utils.FieldByNamePtr(driver, "Interval").SetString("0.1s")
}
d.Driver = driver
return d
}
func (d *device) Init() bool {
log.Println("Device " + d.Name + " initialized")
return d.Driver.Init()
}
func (d *device) Start() bool {
log.Println("Device " + d.Name + " started")
return d.Driver.Start()
}
func (d *device) Halt() bool {
log.Println("Device " + d.Name + " halted")
return d.Driver.Halt()
}
func (d *device) Commands() interface{} {
return utils.FieldByNamePtr(d.Driver, "Commands").Interface()
}

View File

@ -1,7 +1,8 @@
package gobot
package robot
import (
"fmt"
"github.com/hybridgroup/gobot/core/utils"
"log"
"math/rand"
"time"
@ -14,31 +15,44 @@ type Robot struct {
Commands map[string]interface{} `json:"-"`
RobotCommands []string `json:"commands"`
Work func() `json:"-"`
connections []*connection `json:"-"`
devices []*device `json:"-"`
master *Master `json:"-"`
connections connections `json:"-"`
devices devices `json:"-"`
}
func (r *Robot) Start() {
if r.master == nil {
r.master = NewMaster()
type Robots []*Robot
func (r Robots) Start() {
for _, robot := range r {
robot.Start()
}
r.master.Robots = []*Robot{r}
r.master.Start()
}
func (r *Robot) startRobot() {
func (r Robots) Each(f func(*Robot)) {
for _, robot := range r {
f(robot)
}
}
func NewRobot(name string, c []Connection, d []Device, work func()) *Robot {
r := &Robot{
Name: name,
Connections: c,
Devices: d,
Work: work,
}
r.initName()
r.initCommands()
r.initConnections()
if r.startConnections() != true {
r.initDevices()
return r
}
func (r *Robot) Start() {
// if !r.startConnections() {
if err := r.GetConnections().Start(); err != nil {
panic("Could not start connections")
}
if r.initDevices() != true {
panic("Could not initialize devices")
}
if r.startDevices() != true {
if err := r.GetDevices().Start(); err != nil {
panic("Could not start devices")
}
if r.Work != nil {
@ -62,10 +76,10 @@ func (r *Robot) initCommands() {
}
func (r *Robot) initConnections() {
r.connections = make([]*connection, len(r.Connections))
r.connections = make(connections, len(r.Connections))
log.Println("Initializing connections...")
for i, connection := range r.Connections {
log.Println("Initializing connection ", FieldByNamePtr(connection, "Name"), "...")
log.Println("Initializing connection ", utils.FieldByNamePtr(connection, "Name"), "...")
r.connections[i] = NewConnection(connection, r)
}
}
@ -87,43 +101,11 @@ func (r *Robot) initDevices() bool {
return success
}
func (r *Robot) startConnections() bool {
log.Println("Starting connections...")
success := true
for _, connection := range r.connections {
log.Println("Starting connection " + connection.Name + "...")
if connection.Connect() == false {
success = false
break
}
}
return success
}
func (r *Robot) startDevices() bool {
log.Println("Starting devices...")
success := true
for _, device := range r.devices {
log.Println("Starting device " + device.Name + "...")
if device.Start() == false {
success = false
break
}
}
return success
}
func (r *Robot) finalizeConnections() {
for _, connection := range r.connections {
connection.Finalize()
}
}
func (r *Robot) GetDevices() devices {
return devices(r.devices)
}
func (r *Robot) GetDevice(name string) *device {
func (r *Robot) Device(name string) *device {
if r == nil {
return nil
}
@ -135,11 +117,11 @@ func (r *Robot) GetDevice(name string) *device {
return nil
}
func (r *Robot) GetConnections() []*connection {
return r.connections
func (r *Robot) GetConnections() connections {
return connections(r.connections)
}
func (r *Robot) GetConnection(name string) *connection {
func (r *Robot) Connection(name string) *connection {
if r == nil {
return nil
}

View File

@ -1,4 +1,4 @@
package gobot
package robot
import (
. "github.com/onsi/ginkgo"

View File

@ -1,4 +1,4 @@
package gobot
package utils
import (
"math"

View File

@ -1,9 +1,9 @@
package gobot
package utils
import (
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"time"
)
var _ = Describe("Utils", func() {

View File

@ -1,61 +0,0 @@
package gobot
import (
"log"
"reflect"
)
type Device interface {
Init() bool
Start() bool
Halt() bool
}
type device struct {
Name string `json:"name"`
Type string `json:"driver"`
Interval string `json:"-"`
Robot *Robot `json:"-"`
Driver DriverInterface `json:"-"`
}
type devices []*device
// Halt() stop all the devices.
func (d devices) Halt() {
for _, device := range d {
device.Halt()
}
}
func NewDevice(driver DriverInterface, r *Robot) *device {
d := new(device)
s := reflect.ValueOf(driver).Type().String()
d.Type = s[1:len(s)]
d.Name = FieldByNamePtr(driver, "Name").String()
d.Robot = r
if FieldByNamePtr(driver, "Interval").String() == "" {
FieldByNamePtr(driver, "Interval").SetString("0.1s")
}
d.Driver = driver
return d
}
func (d *device) Init() bool {
log.Println("Device " + d.Name + " initialized")
return d.Driver.Init()
}
func (d *device) Start() bool {
log.Println("Device " + d.Name + " started")
return d.Driver.Start()
}
func (d *device) Halt() bool {
log.Println("Device " + d.Name + " halted")
return d.Driver.Halt()
}
func (d *device) Commands() interface{} {
return FieldByNamePtr(d.Driver, "Commands").Interface()
}

View File

@ -2,38 +2,38 @@ package main
import (
"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/firmata"
"github.com/hybridgroup/gobot/gpio"
"github.com/hybridgroup/gobot/core/api"
"github.com/hybridgroup/gobot/core/robot"
"github.com/hybridgroup/gobot/core/utils"
"github.com/hybridgroup/gobot/platforms/firmata"
"github.com/hybridgroup/gobot/platforms/gpio"
"time"
)
func main() {
firmataAdaptor := firmata.NewFirmataAdaptor()
firmataAdaptor.Name = "firmata"
firmataAdaptor.Port = "/dev/ttyACM0"
gbot := gobot.NewGobot()
gbot.Api = api.NewApi()
button := gpio.NewButtonDriver(firmataAdaptor)
button.Name = "button"
button.Pin = "2"
firmataAdaptor := firmata.NewFirmataAdaptor("myFirmata", "/dev/ttyACM0")
led := gpio.NewLedDriver(firmataAdaptor)
led.Name = "led"
led.Pin = "13"
button := gpio.NewButtonDriver(firmataAdaptor, "myButton", "2")
led := gpio.NewLedDriver(firmataAdaptor, "myLed", "13")
work := func() {
gobot.On(button.Events["push"], func(data interface{}) {
utils.Every((1 * time.Second), func() {
led.Toggle()
})
utils.On(button.Events["push"], func(data interface{}) {
led.On()
})
gobot.On(button.Events["release"], func(data interface{}) {
utils.On(button.Events["release"], func(data interface{}) {
led.Off()
})
}
robot := gobot.Robot{
Connections: []gobot.Connection{firmataAdaptor},
Devices: []gobot.Device{button, led},
Work: work,
}
gbot.Robots = append(gbot.Robots,
robot.NewRobot("name", []robot.Connection{firmataAdaptor}, []robot.Device{button, led}, work),
)
robot.Start()
gbot.Start()
}

43
gobot.go Normal file
View File

@ -0,0 +1,43 @@
package gobot
import (
"github.com/hybridgroup/gobot/core/robot"
"os"
"os/signal"
)
type Gobot struct {
Robots robot.Robots
trap func(chan os.Signal)
}
func NewGobot() *Gobot {
return &Gobot{
trap: func(c chan os.Signal) {
signal.Notify(c, os.Interrupt)
},
}
}
func (g *Gobot) Start() {
g.Robots.Start()
c := make(chan os.Signal, 1)
g.trap(c)
// waiting for interrupt coming on the channel
_ = <-c
g.Robots.Each(func(r *robot.Robot) {
r.GetDevices().Halt()
r.GetConnections().Finalize()
})
}
func (g *Gobot) Robot(name string) *robot.Robot {
for _, r := range g.Robots {
if r.Name == name {
return r
}
}
return nil
}

View File

@ -1,58 +0,0 @@
package gobot
import (
"os"
"os/signal"
"runtime"
)
type Master struct {
Robots []*Robot
NumCPU int
Api *api
trap func(chan os.Signal)
}
// used to be GobotMaster()
func NewMaster() *Master {
return &Master{
NumCPU: runtime.NumCPU(),
trap: func(c chan os.Signal) {
signal.Notify(c, os.Interrupt)
},
}
}
func (m *Master) Start() {
// this changes the amount of cores used by the program
// to match the amount of CPUs set on master.
runtime.GOMAXPROCS(m.NumCPU)
if m.Api != nil {
m.Api.start()
}
for _, r := range m.Robots {
r.startRobot()
}
var c = make(chan os.Signal, 1)
m.trap(c)
// waiting on something coming on the channel
_ = <-c
for _, r := range m.Robots {
r.GetDevices().Halt()
r.finalizeConnections()
}
}
func (m *Master) FindRobot(name string) *Robot {
for _, robot := range m.Robots {
if robot.Name == name {
return robot
}
}
return nil
}

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 162 KiB

View File

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Some files were not shown because too many files have changed in this diff Show More