package core import ( "fmt" "git.timovolkmann.de/gyrogpsc/ublox" "github.com/sirupsen/logrus" "go.bug.st/serial" "net" "os" "sync" "time" ) type Collector interface { Collect() Close() } type CollectorType uint8 const ( SERIAL CollectorType = iota TCP ) var tcpSingleton *tcpCollector func NewCollector(typ CollectorType, proc Pusher, config *Configuration) Collector { var coll Collector switch typ { case SERIAL: coll = newSerial(proc, config) case TCP: if tcpSingleton == nil { tcpSingleton = newTcp(proc, config) } else { tcpSingleton.SetProcessor(proc) } coll = tcpSingleton default: panic("selected collector type not implemented") } return coll } type serialCollector struct { active bool proc Pusher config *Configuration mu sync.RWMutex } func (s *serialCollector) isSerialCollActive() bool { s.mu.RLock() defer s.mu.RUnlock() return s.active } func (s *serialCollector) Collect() { s.mu.Lock() s.active = true s.mu.Unlock() 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) } //} } defer port.Close() decoder := ublox.NewDecoder(port) for s.isSerialCollActive() { meas, err := decoder.Decode() if err != nil { if err.Error() == "NMEA not implemented" { continue } logrus.Println("serial read err:", err) break } sd, err := ConvertUbxToSensorData(meas) if err != nil { logrus.Println("convert err:", err, meas, sd) continue } // skip irrelevant messages if sd == nil { continue } err = s.proc.Push(sd) if err != nil { logrus.Println("process err:", err, *sd) continue } } logrus.Println("serial collector stopped") }() } func (s *serialCollector) Close() { s.mu.Lock() s.active = false s.mu.Unlock() } func newSerial(proc Pusher, config *Configuration) *serialCollector { return &serialCollector{ active: false, proc: proc, config: config, } } type tcpCollector struct { active bool processor Pusher //config *Configuration } func (t *tcpCollector) Collect() { t.active = true } func (t *tcpCollector) Close() { t.active = false } func (t *tcpCollector) SetProcessor(p Pusher) { t.processor = p } func newTcp(proc Pusher, config *Configuration) *tcpCollector { logrus.Println("start tcp collector") listener, err := net.Listen("tcp", config.Collectors.TcpCollectorPort) if err != nil { fmt.Println("Error listening:", err) //os.Exit(1) } coll := &tcpCollector{ active: false, processor: proc, } go func() { for { // Listen for an incoming connection. conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting: ", err.Error()) os.Exit(1) } logrus.Println("...new incoming tcp connection...") // Handle connections in a new goroutine. go coll.jsonHandler(conn) } }() return coll } // handles incoming tcp connections with json payload. func (c *tcpCollector) jsonHandler(conn net.Conn) { defer conn.Close() // TRY reader := bufio.NewReader(conn) OR NewScanner(conn) buf := make([]byte, 2048) for { // Read the incoming connection into the buffer. n, err := conn.Read(buf) if err != nil { fmt.Println("TCP error - reading from connection:", n, err.Error()) break } //json := pretty.Pretty(buf[:n]) //fmt.Println(string(json)) //fmt.Println(string(buf[:n])) sd, err := ConvertSensorDataPhone(buf[:n]) if err != nil { logrus.Println(err) continue } if !c.active { //time.Sleep(50 * time.Millisecond) continue } err = c.processor.Push(sd) if err != nil { logrus.Fatalln(err) } } }