147 lines
3.3 KiB
Go
147 lines
3.3 KiB
Go
package core
|
|
|
|
import (
|
|
"encoding/json"
|
|
ext "github.com/reugn/go-streams/extension"
|
|
"github.com/reugn/go-streams/flow"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/tidwall/pretty"
|
|
"time"
|
|
)
|
|
|
|
type pipelineRecord struct{}
|
|
|
|
func NewRecordPipeline(p Publisher, s Tracker, netChan chan interface{}, serialChan chan interface{}) *pipelineRecord {
|
|
// set pipeline up and wire it together
|
|
collNet := ext.NewChanSource(netChan)
|
|
collSer := ext.NewChanSource(serialChan)
|
|
transNet := flow.NewFlatMap(transformNetFunc, 1)
|
|
transSer := flow.NewFlatMap(transformSerFunc, 1)
|
|
flowStore := flow.NewMap(storeFunc(s), 1)
|
|
|
|
dataSanitizer := flow.NewMap(replaySanitizeFunc(), 1)
|
|
|
|
flowJson := flow.NewMap(jsonFunc, 1)
|
|
sinkPub := newPublishSink(p)
|
|
|
|
// wire up and execute
|
|
demux := flow.Merge(collNet.Via(transNet), collSer.Via(transSer))
|
|
go demux.Via(flowStore).Via(dataSanitizer).Via(flowJson).To(sinkPub)
|
|
|
|
return &pipelineRecord{}
|
|
}
|
|
|
|
func storeFunc(s Tracker) flow.MapFunc {
|
|
return func(i interface{}) interface{} {
|
|
var sd *SensorData
|
|
if v, ok := i.(*SensorData); ok {
|
|
sd = v
|
|
} else {
|
|
panic("unexpected data struct")
|
|
}
|
|
if (*sd == SensorData{} || sd == nil) {
|
|
logrus.Info("empty data")
|
|
} else {
|
|
sd.Servertime = time.Now().UTC()
|
|
s.Put(*sd)
|
|
}
|
|
|
|
logrus.Debugf("%-14v %-40s %-40s %v %v", sd.Source(), sd.Timestamp.Format(time.RFC3339Nano), sd.Servertime.Format(time.RFC3339Nano), sd.Position, sd.Orientation)
|
|
//runtime.Gosched()
|
|
return sd
|
|
}
|
|
}
|
|
|
|
func jsonFunc(i interface{}) interface{} {
|
|
var sd *SensorData
|
|
switch v := i.(type) {
|
|
case SensorData:
|
|
sd = &v
|
|
case *SensorData:
|
|
sd = v
|
|
default:
|
|
panic("jsonFunc: wrong Type")
|
|
}
|
|
|
|
data := map[string]interface{}{}
|
|
if sd.Source() == SOURCE_TCP {
|
|
data[string(SOURCE_TCP)] = *sd
|
|
}
|
|
if sd.Source() == SOURCE_SERIAL {
|
|
data[string(SOURCE_SERIAL)] = *sd
|
|
}
|
|
|
|
jdata, err := json.Marshal(data)
|
|
logrus.Traceln(string(pretty.Pretty(jdata)))
|
|
if err != nil {
|
|
logrus.Fatalln(err)
|
|
}
|
|
return string(jdata)
|
|
|
|
}
|
|
|
|
func transformNetFunc(i interface{}) []interface{} {
|
|
logrus.Traceln("transform TCP data...")
|
|
|
|
var returnSlice []interface{}
|
|
if b, ok := i.([]byte); ok {
|
|
sd, err := ConvertByteSensorData(b)
|
|
if err != nil {
|
|
logrus.Errorln("error converting byte message:", err)
|
|
}
|
|
if sd != nil {
|
|
return append(returnSlice, sd)
|
|
}
|
|
}
|
|
logrus.Errorln("wrong data type. expected []byte data")
|
|
return nil
|
|
}
|
|
|
|
func transformSerFunc(i interface{}) []interface{} {
|
|
logrus.Traceln("transform SERIAL data...")
|
|
|
|
var returnSlice []interface{}
|
|
sd, err := ConvertUbxSensorData(i)
|
|
if err != nil {
|
|
logrus.Errorln("error converting ubx message:", err)
|
|
return nil
|
|
}
|
|
if sd == nil {
|
|
return nil
|
|
}
|
|
return append(returnSlice, sd)
|
|
}
|
|
|
|
// Publish sink will pass data to dispatcher after flowing through the stream processing
|
|
// matches api to use it with github.com/reugn/go-streams/flow
|
|
|
|
type publishSink struct {
|
|
in chan interface{}
|
|
p Publisher
|
|
}
|
|
|
|
func newPublishSink(p Publisher) *publishSink {
|
|
sink := &publishSink{make(chan interface{}), p}
|
|
sink.init()
|
|
return sink
|
|
}
|
|
|
|
func (ps *publishSink) In() chan<- interface{} {
|
|
return ps.in
|
|
}
|
|
|
|
func (ps *publishSink) init() {
|
|
go func() {
|
|
logrus.Trace("publish sink running")
|
|
for elem := range ps.in {
|
|
if v, ok := elem.(string); ok {
|
|
ps.p.Publish(v)
|
|
} else {
|
|
logrus.Debugln("not publishing. wrong format", elem)
|
|
//reflect.TypeOf(elem)
|
|
}
|
|
}
|
|
logrus.Trace("publish sink stopped")
|
|
}()
|
|
}
|