251 lines
5.8 KiB
Go
251 lines
5.8 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"github.com/google/uuid"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/sync/semaphore"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type OpMode uint8
|
|
|
|
const (
|
|
STOPPED OpMode = iota
|
|
LIVE
|
|
RECORDING
|
|
REPLAY
|
|
)
|
|
|
|
type Service interface {
|
|
AllTrackings() ([]TrackingMetadata, error)
|
|
StartPipeline(cols ...CollectorType) (string, error)
|
|
StartRecord() (string, error)
|
|
StopRecord() (*TrackingMetadata, error)
|
|
StopAll() (*TrackingMetadata, error)
|
|
|
|
LoadTracking(trackingId uuid.UUID) (*Tracking, error)
|
|
DeleteTracking(trackingId uuid.UUID)
|
|
|
|
StartReplay()
|
|
PauseReplay()
|
|
StopReplay()
|
|
}
|
|
|
|
type Tracker interface {
|
|
Put(data SensorData)
|
|
Recorder
|
|
}
|
|
|
|
type Recorder interface {
|
|
SetRecording(s bool) (ok bool)
|
|
IsRecording() bool
|
|
}
|
|
|
|
type trackingService struct {
|
|
opMode OpMode
|
|
tracking *Tracking
|
|
pipeline *pipelineRecord
|
|
collectors []Collector
|
|
store Storer
|
|
publisher Publisher
|
|
config *Configuration
|
|
recSem *semaphore.Weighted
|
|
mu *sync.RWMutex
|
|
}
|
|
|
|
func TrackingService(c *Configuration, s Storer, p Publisher) *trackingService {
|
|
t := &Tracking{}
|
|
ts := &trackingService{
|
|
tracking: t,
|
|
opMode: STOPPED,
|
|
collectors: nil,
|
|
recSem: semaphore.NewWeighted(1),
|
|
mu: &sync.RWMutex{},
|
|
config: c,
|
|
store: s,
|
|
publisher: p,
|
|
}
|
|
|
|
// first initialize of tcp collector to to open tcp port
|
|
NewCollector(c, TCP)
|
|
|
|
return ts
|
|
}
|
|
|
|
func (t *trackingService) Put(data SensorData) {
|
|
if !t.IsRecording() {
|
|
return
|
|
}
|
|
t.mu.Lock()
|
|
t.tracking.Data = append(t.tracking.Data, data)
|
|
t.tracking.Size++
|
|
logrus.Traceln("raw data points: len->", len(t.tracking.Data))
|
|
t.mu.Unlock()
|
|
}
|
|
|
|
func (t *trackingService) SetRecording(s bool) (ok bool) {
|
|
if okay := t.recSem.TryAcquire(1); okay && s {
|
|
// if i want to turn on and can get semaphore then return success
|
|
return true
|
|
} else if !s && !okay {
|
|
// if i want to turn off and cant get semaphore, i can safely turn off by releasing semaphore and return success
|
|
t.recSem.Release(1)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (t *trackingService) IsRecording() bool {
|
|
if t.recSem.TryAcquire(1) {
|
|
t.recSem.Release(1)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (t *trackingService) StartPipeline(cols ...CollectorType) (string, error) {
|
|
logrus.Info("SERVICE: NEW PIPELINE")
|
|
if t.opMode == RECORDING {
|
|
txt := "trackingservice: please stop recording before resetting pipeline"
|
|
logrus.Warn(txt)
|
|
return "RECORDING", errors.New(txt)
|
|
}
|
|
if t.opMode == LIVE {
|
|
txt := "trackingservice: stop tracking running stream before creating new one"
|
|
logrus.Warnln(txt)
|
|
//t.StopAll()
|
|
//time.Sleep(1000 * time.Millisecond)
|
|
return "record already running since: " + t.tracking.TimeCreated.String(), errors.New(txt)
|
|
}
|
|
logrus.Debugln("new tracking:", cols)
|
|
t.opMode = LIVE
|
|
|
|
t.collectors = nil
|
|
var tcp, ser chan interface{}
|
|
for _, col := range cols {
|
|
c := NewCollector(t.config, col)
|
|
t.collectors = append(t.collectors, c)
|
|
if col == TCP {
|
|
tcp = c.OutChannel()
|
|
}
|
|
if col == SERIAL {
|
|
ser = c.OutChannel()
|
|
}
|
|
c.Collect()
|
|
}
|
|
t.safelyReplaceTracking(newTracking())
|
|
t.tracking.Collectors = cols
|
|
|
|
NewRecordPipeline(t.publisher, t, tcp, ser)
|
|
t.publisher.SetStreaming(true)
|
|
|
|
//time.Sleep(3 * time.Second)
|
|
return "LIVE", nil
|
|
}
|
|
|
|
func (t *trackingService) AllTrackings() ([]TrackingMetadata, error) {
|
|
logrus.Info("SERVICE: GET ALL TRACKINGS")
|
|
data, err := t.store.LoadAll()
|
|
return data, err
|
|
}
|
|
|
|
func (t *trackingService) StartRecord() (string, error) {
|
|
logrus.Info("SERVICE: START RECORD")
|
|
if t.opMode != LIVE {
|
|
if t.opMode == RECORDING {
|
|
txt := "trackingservice: already recording"
|
|
logrus.Warn(txt)
|
|
return "record already running since: " + t.tracking.TimeCreated.String(), errors.New(txt)
|
|
} else {
|
|
txt := "trackingservice: start collector pipeline to record data"
|
|
logrus.Warn(txt)
|
|
return "record already running since: " + t.tracking.TimeCreated.String(), errors.New(txt)
|
|
}
|
|
}
|
|
t.opMode = RECORDING
|
|
t.tracking.TimeCreated = time.Now()
|
|
t.SetRecording(true)
|
|
return "record started at: " + t.tracking.TimeCreated.String(), nil
|
|
}
|
|
|
|
func (t *trackingService) StopRecord() (*TrackingMetadata, error) {
|
|
logrus.Info("SERVICE: STOP RECORD")
|
|
if t.opMode != RECORDING {
|
|
txt := "trackingservice: couldn't stop. not recording"
|
|
logrus.Info(txt)
|
|
return nil, errors.New(txt)
|
|
}
|
|
t.SetRecording(false)
|
|
|
|
err := t.store.Save(*t.tracking)
|
|
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
t.opMode = LIVE
|
|
//time.Sleep(20 * time.Millisecond)
|
|
tm := t.tracking.TrackingMetadata
|
|
t.safelyReplaceTracking(newTracking())
|
|
t.tracking.Collectors = tm.Collectors
|
|
return &tm, err
|
|
}
|
|
|
|
func (t *trackingService) StopAll() (*TrackingMetadata, error) {
|
|
logrus.Info("SERVICE: STOP ALL")
|
|
var tm *TrackingMetadata = nil
|
|
var err error
|
|
for _, e := range t.collectors {
|
|
e.Stop()
|
|
}
|
|
// let buffer run empty after collectors stopped
|
|
time.Sleep(time.Millisecond * 5)
|
|
t.publisher.SetStreaming(false)
|
|
if t.opMode == RECORDING {
|
|
logrus.Info("trackingservice: gracefully stop recording ")
|
|
tm, err = t.StopRecord()
|
|
}
|
|
t.opMode = STOPPED
|
|
return tm, err
|
|
}
|
|
|
|
func (t *trackingService) LoadTracking(trackingId uuid.UUID) (*Tracking, error) {
|
|
if !(t.opMode == REPLAY || t.opMode == STOPPED) {
|
|
t.StopAll()
|
|
}
|
|
logrus.Info("LOAD TRACKING from database")
|
|
tracking, err := t.store.Load(trackingId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.safelyReplaceTracking(*tracking)
|
|
NewReplayPipeline(t.publisher, t.tracking)
|
|
t.publisher.SetStreaming(true)
|
|
t.opMode = REPLAY
|
|
return t.tracking, nil
|
|
}
|
|
|
|
func (t *trackingService) DeleteTracking(trackingId uuid.UUID) {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (t *trackingService) StartReplay() {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (t *trackingService) PauseReplay() {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (t *trackingService) StopReplay() {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (t *trackingService) safelyReplaceTracking(tr Tracking) {
|
|
t.recSem.Acquire(context.Background(), 1)
|
|
*t.tracking = tr
|
|
t.recSem.Release(1)
|
|
}
|