gyrogpsc/core/collectors.go

189 lines
3.8 KiB
Go

package core
import (
"bufio"
"fmt"
"git.timovolkmann.de/gyrogpsc/ublox"
"github.com/sirupsen/logrus"
"go.bug.st/serial"
"net"
"os"
"sync"
"time"
)
type Collector interface {
Collect() <-chan interface{}
Close()
//OutChannel() <-chan interface{}
}
type CollectorType string
const (
SERIAL CollectorType = "SERIAL_COLLECTOR"
TCP CollectorType = "TCP_COLLECTOR"
)
var tcpSingleton *tcpCollector
func NewCollector(config *Configuration, typ CollectorType) Collector {
var coll Collector
switch typ {
case SERIAL:
coll = newSerial(config)
case TCP:
if tcpSingleton == nil {
tcpSingleton = newTcp(config)
}
coll = tcpSingleton
default:
panic("selected collector type not implemented")
}
return coll
}
type serialCollector struct {
//active bool
out chan interface{}
config *Configuration
mu sync.RWMutex
}
func (s *serialCollector) Collect() <-chan interface{} {
c := make(chan interface{})
s.out = c
go func() {
logrus.Println("start serial collector")
mode := &serial.Mode{
BaudRate: 115200,
}
port, err := serial.Open(s.config.Collectors.SerialCollectorPort, mode)
if err != nil {
logrus.Warn("can't open serial port:", err)
//if e, ok := err.(serial.PortError); ok && e.Code() == serial.PortBusy {
for i := 3; i < 20; i = i + 2 {
logrus.Warnf("try again in -> %vms", i*i)
time.Sleep(time.Millisecond * time.Duration(i*i))
port, err = serial.Open(s.config.Collectors.SerialCollectorPort, mode)
if err == nil {
break
}
}
if err != nil {
logrus.Fatal(err)
}
//}
}
decoder := ublox.NewDecoder(port)
defer func() {
if r := recover(); r != nil {
logrus.Infoln("stopped collecting channel: serial")
}
logrus.Infoln("close serial port")
port.Close()
}()
for {
meas, err2 := decoder.Decode()
if err2 != nil {
if err2.Error() == "NMEA not implemented" {
continue
}
logrus.Println("serial read err2:", err2)
break
}
s.out <- meas
}
logrus.Println("serial collector stopped")
}()
return c
}
func (s *serialCollector) Close() {
close(s.out)
}
func newSerial(config *Configuration) *serialCollector {
return &serialCollector{
//active: false,
out: make(chan interface{}),
config: config,
}
}
type tcpCollector struct {
//active bool
out chan interface{}
//config *Configuration
}
func (t *tcpCollector) Collect() <-chan interface{} {
logrus.Info("starting tcp collector")
t.out = make(chan interface{})
return t.out
}
func (t *tcpCollector) Close() {
close(t.out)
}
func newTcp(config *Configuration) *tcpCollector {
//func newTcp(proc Processor, config *Configuration) *tcpCollector {
logrus.Println("listen for tcp connections on port", config.Collectors.TcpCollectorPort)
listener, err := net.Listen("tcp", config.Collectors.TcpCollectorPort)
if err != nil {
fmt.Println("Error listening:", err)
//os.Exit(1)
}
c := &tcpCollector{
out: make(chan interface{}),
}
go func() {
for {
// Listen for an incoming connection.
conn, err := listener.Accept()
if err != nil {
logrus.Errorln("Error accepting: ", err.Error())
os.Exit(1)
}
logrus.Infoln("new incoming tcp connection...")
// Handle connections in a new goroutine.
go c.connectionHandler(conn)
}
}()
return c
}
// handles incoming tcp connections.
func (t *tcpCollector) connectionHandler(conn net.Conn) {
defer func() {
if r := recover(); r != nil {
logrus.Infoln("stopped collecting tcp: panic")
}
logrus.Infoln("close connection")
conn.Close()
}()
sc := bufio.NewScanner(conn)
for sc.Scan() {
// Read the incoming connection into the buffer.
res := append([]byte{}, sc.Bytes()...)
if err2 := sc.Err(); err2 != nil {
logrus.Warn("lost tcp link:", err2)
break
}
select {
case t.out <- res:
default:
logrus.Traceln("stopped collecting tcp messages: messages")
break
}
}
}