[WIP] save point
This commit is contained in:
parent
2a9c3a1153
commit
01d5feed7b
@ -23,9 +23,9 @@ func main() {
|
||||
log.Println("initialize processing pipeline")
|
||||
processor := core.NewPipeline(dispatcher, 50, 494)
|
||||
processor.Run()
|
||||
//collectRoutines(processor)
|
||||
collectRoutines(processor)
|
||||
log.Println("start http server")
|
||||
core.FiberListenAndServe(dispatcher)
|
||||
core.FiberListen(dispatcher)
|
||||
//core.HttpListenAndServe(dispatcher, HTTP_PORT)
|
||||
}
|
||||
|
||||
|
||||
@ -2,41 +2,162 @@ package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.timovolkmann.de/gyrogpsc/ublox"
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
func TcpCollector(proc Processor, tcpPort string) {
|
||||
log.Println("start tcp collectors")
|
||||
type Collector interface {
|
||||
Collect()
|
||||
Stop()
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", tcpPort)
|
||||
if err != nil {
|
||||
fmt.Println("Error listening:", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
// Close the listener when the application closes.
|
||||
defer listener.Close()
|
||||
type CollectorType uint8
|
||||
|
||||
for {
|
||||
// Listen for an incoming connection.
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
fmt.Println("Error accepting: ", err.Error())
|
||||
os.Exit(1)
|
||||
const (
|
||||
SERIAL CollectorType = iota
|
||||
TCP
|
||||
)
|
||||
|
||||
var tcpSingleton *tcpCollector
|
||||
|
||||
func NewCollector(typ CollectorType, proc Processor, 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)
|
||||
}
|
||||
log.Println("...new incoming tcp connection...")
|
||||
coll = tcpSingleton
|
||||
//case DATABASE:
|
||||
// if len(trackingId) != 1 {
|
||||
// panic("only 1 tracking per collector")
|
||||
// }
|
||||
// coll = newDbReplay(proc, config, trackingId[0])
|
||||
default:
|
||||
panic("selected collector type not implemented")
|
||||
}
|
||||
return coll
|
||||
}
|
||||
|
||||
// Handle connections in a new goroutine.
|
||||
go jsonHandler(conn, proc)
|
||||
type serialCollector struct {
|
||||
active bool
|
||||
proc Processor
|
||||
config *Configuration
|
||||
}
|
||||
|
||||
func (s *serialCollector) Collect() {
|
||||
go func() {
|
||||
log.Println("start serial collectors")
|
||||
mode := &serial.Mode{
|
||||
BaudRate: 115200,
|
||||
}
|
||||
port, err := serial.Open(s.config.SerialCollectorPort, mode)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
defer port.Close()
|
||||
|
||||
decoder := ublox.NewDecoder(port)
|
||||
|
||||
for s.active {
|
||||
meas, err := decoder.Decode()
|
||||
if err != nil {
|
||||
if err.Error() == "NMEA not implemented" {
|
||||
continue
|
||||
}
|
||||
log.Println("serial read err:", err)
|
||||
break
|
||||
}
|
||||
sd, err := ConvertUbxToSensorData(meas)
|
||||
if err != nil {
|
||||
log.Println("convert err:", err, meas)
|
||||
continue
|
||||
}
|
||||
if sd == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
err = s.proc.Push(sd)
|
||||
if err != nil {
|
||||
log.Println("process err:", err, *sd)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *serialCollector) Stop() {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func newSerial(proc Processor, config *Configuration) *serialCollector {
|
||||
return &serialCollector{
|
||||
active: false,
|
||||
proc: proc,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
type tcpCollector struct {
|
||||
active bool
|
||||
processor Processor
|
||||
//config *Configuration
|
||||
}
|
||||
|
||||
func (t *tcpCollector) Collect() {
|
||||
t.active = true
|
||||
}
|
||||
|
||||
func (t *tcpCollector) Stop() {
|
||||
t.active = false
|
||||
}
|
||||
|
||||
func (t *tcpCollector) SetProcessor(p Processor) {
|
||||
t.processor = p
|
||||
}
|
||||
|
||||
func newTcp(proc Processor, config *Configuration) *tcpCollector {
|
||||
log.Println("start tcp collector")
|
||||
|
||||
listener, err := net.Listen("tcp", config.TcpCollectorPort)
|
||||
if err != nil {
|
||||
fmt.Println("Error listening:", err.Error())
|
||||
//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)
|
||||
}
|
||||
log.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 jsonHandler(conn net.Conn, proc Processor) {
|
||||
func (c *tcpCollector) jsonHandler(conn net.Conn) {
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
@ -57,54 +178,27 @@ func jsonHandler(conn net.Conn, proc Processor) {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = proc.Process(sd)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
if !c.active {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
err = c.processor.Push(sd)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SerialCollector(proc Processor, serialPort string) {
|
||||
log.Println("start serial collectors")
|
||||
mode := &serial.Mode{
|
||||
BaudRate: 115200,
|
||||
}
|
||||
port, err := serial.Open(serialPort, mode)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
defer port.Close()
|
||||
type replayCollector struct{}
|
||||
|
||||
decoder := ublox.NewDecoder(port)
|
||||
|
||||
for {
|
||||
meas, err := decoder.Decode()
|
||||
if err != nil {
|
||||
if err.Error() == "NMEA not implemented" {
|
||||
continue
|
||||
}
|
||||
log.Println("serial read err:", err)
|
||||
break
|
||||
}
|
||||
sd, err := ConvertUbxToSensorData(meas)
|
||||
if err != nil {
|
||||
log.Println("convert err:", err, meas)
|
||||
continue
|
||||
}
|
||||
if sd == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
err = proc.Process(sd)
|
||||
if err != nil {
|
||||
log.Println("process err:", err, *sd)
|
||||
continue
|
||||
}
|
||||
}
|
||||
func (r *replayCollector) Collect() {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func replayCollector(storage string, proc Processor, trackingId int) {
|
||||
|
||||
func (r *replayCollector) Stop() {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func newDbReplay(proc Processor, config *Configuration, trackingId uuid.UUID) *replayCollector {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package core
|
||||
|
||||
type Configuration struct {
|
||||
TcpCollectorPort string
|
||||
SerialCollectorPort string
|
||||
HttpPort string
|
||||
TcpCollectorPort string
|
||||
SerialCollectorPort string
|
||||
HttpPort string
|
||||
publishIntervalMs int
|
||||
syncUpdateIntervalMs int
|
||||
}
|
||||
|
||||
func LoadConfigYaml() error {
|
||||
|
||||
46
core/http.go
46
core/http.go
@ -72,7 +72,7 @@ func HttpListenAndServe(sub Subscriber, httpPort string) {
|
||||
log.Fatal(http.ListenAndServe(httpPort, nil))
|
||||
}
|
||||
|
||||
func FiberListenAndServe(sub Subscriber) {
|
||||
func FiberListen(sub Subscriber) {
|
||||
app := fiber.New()
|
||||
app.Static("/static", "static")
|
||||
|
||||
@ -80,17 +80,20 @@ func FiberListenAndServe(sub Subscriber) {
|
||||
app.Get("/", fiberHomeHandler)
|
||||
|
||||
// Websocket
|
||||
app.Get("/ws", ws.New(fiberWebsocketHandler))
|
||||
app.Get("/ws", ws.New(createFiberWebsocketHandler(sub)))
|
||||
|
||||
// TODO: Get all SerialPorts
|
||||
app.Get("/serialports")
|
||||
|
||||
// Tracking persistence controls
|
||||
trackings := app.Group("/trackings")
|
||||
trackings.Get("/") // Get all trackings Metadata
|
||||
trackings.Post("/") // Initialize new tracking by websocket and prepare for automatic recording. Toggle ?serial=true and ?tcp=true. Returns trackingId
|
||||
trackings.Post("/") // Initialize new tracking, open websocket and prepare for automatic recording. Toggle ?serial=true and ?tcp=true. Returns trackingId
|
||||
trackings.Patch("/") // Starts recording
|
||||
trackings.Put("/") // Stops current recording. Returns trackingId if record was successful
|
||||
trackings.Delete("/") // Stops websocket connection, pipelines and collectors
|
||||
|
||||
trackings.Get("/:trackingId") // Gets Tracking Metadata by Id.
|
||||
trackings.Get("/:trackingId") // Gets Tracking Metadata and loads sensorRecords from database.
|
||||
trackings.Post("/:trackingId") // Starts Replay.
|
||||
trackings.Patch("/:trackingId") // Pauses Replay.
|
||||
trackings.Put("/:trackingId") // Stops Replay.
|
||||
@ -99,20 +102,31 @@ func FiberListenAndServe(sub Subscriber) {
|
||||
log.Fatal(app.Listen(":3011"))
|
||||
}
|
||||
|
||||
func fiberWebsocketHandler(c *ws.Conn) {
|
||||
for {
|
||||
mt, msg, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
log.Println("read:", err)
|
||||
break
|
||||
}
|
||||
log.Printf("recv: %s", msg)
|
||||
err = c.WriteMessage(mt, msg)
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
break
|
||||
func createFiberWebsocketHandler(s Subscriber) func(conn *ws.Conn) {
|
||||
return func(c *ws.Conn) {
|
||||
// Handle and discard inbound messages
|
||||
go func() {
|
||||
for {
|
||||
if _, _, err := c.NextReader(); err != nil {
|
||||
c.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
dispatcherId, channel := s.Subscribe()
|
||||
defer s.Unsubscribe(dispatcherId)
|
||||
for {
|
||||
cmsg := <-channel
|
||||
err := c.WriteMessage(ws.TextMessage, []byte(cmsg))
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func fiberHomeHandler(c *fiber.Ctx) error {
|
||||
|
||||
@ -10,42 +10,59 @@ import (
|
||||
)
|
||||
|
||||
type Processor interface {
|
||||
Process(data *Sensordata) error
|
||||
Push(data *Sensordata) error
|
||||
}
|
||||
|
||||
type Pipeline interface {
|
||||
Run()
|
||||
Stop()
|
||||
}
|
||||
|
||||
type Storer interface {
|
||||
Persist()
|
||||
Store(data Sensordata)
|
||||
}
|
||||
|
||||
type pipeline struct {
|
||||
syn synchronizer
|
||||
agr aggregator
|
||||
pub Publisher
|
||||
//stor Storer
|
||||
active bool
|
||||
syn synchronizer
|
||||
agr aggregator
|
||||
pub Publisher
|
||||
stor Storer
|
||||
publishTicker *time.Ticker
|
||||
}
|
||||
|
||||
func NewPipeline(d Publisher, publishIntervalMs int, syncUpdateIntervalMs int) *pipeline {
|
||||
// TODO: replace timing params with config struct
|
||||
// pipe implements Runner & Processor
|
||||
func NewPipeline(d Publisher, s Storer, conf *Configuration) *pipeline {
|
||||
return &pipeline{
|
||||
false,
|
||||
synchronizer{
|
||||
//bufferSize: 100,
|
||||
mutex: &sync.Mutex{},
|
||||
updateTicker: time.NewTicker(time.Duration(syncUpdateIntervalMs) * time.Millisecond),
|
||||
updateTicker: time.NewTicker(time.Duration(conf.syncUpdateIntervalMs) * time.Millisecond),
|
||||
},
|
||||
aggregator{
|
||||
tcpMutex: &sync.Mutex{},
|
||||
serialMutex: &sync.Mutex{},
|
||||
},
|
||||
d,
|
||||
time.NewTicker(time.Duration(publishIntervalMs) * time.Millisecond),
|
||||
s,
|
||||
time.NewTicker(time.Duration(conf.publishIntervalMs) * time.Millisecond),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pipeline) Run() {
|
||||
go p.scheduleSynchronizer()
|
||||
go func() {
|
||||
for {
|
||||
for p.active {
|
||||
<-p.syn.updateTicker.C
|
||||
err := p.refreshDelay()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
go func() {
|
||||
for p.active {
|
||||
<-p.publishTicker.C
|
||||
err := p.Publish()
|
||||
if err != nil && err.Error() != "no data available" {
|
||||
@ -53,7 +70,7 @@ func (p *pipeline) Run() {
|
||||
}
|
||||
}
|
||||
}()
|
||||
log.Println("pipeline: processing service started")
|
||||
log.Println("pipe: processing service started")
|
||||
}
|
||||
|
||||
func (p *pipeline) Publish() error {
|
||||
@ -109,14 +126,6 @@ type synchronizer struct {
|
||||
}
|
||||
|
||||
func (p *pipeline) scheduleSynchronizer() {
|
||||
log.Println("synchronizer: started")
|
||||
for {
|
||||
<-p.syn.updateTicker.C
|
||||
err := p.refreshDelay()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pipeline) refreshDelay() error {
|
||||
@ -144,7 +153,7 @@ func (p *pipeline) refreshDelay() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pipeline) Process(data *Sensordata) error {
|
||||
func (p *pipeline) Push(data *Sensordata) error {
|
||||
if data == nil {
|
||||
return errors.New("nil processing not allowed")
|
||||
}
|
||||
@ -156,7 +165,7 @@ func (p *pipeline) Process(data *Sensordata) error {
|
||||
case SOURCE_SERIAL:
|
||||
go p.pushSerialDataToBuffer(*data)
|
||||
default:
|
||||
panic("pipeline: invalid data source")
|
||||
panic("pipe: invalid data source")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -177,3 +186,7 @@ func (p *pipeline) pushSerialDataToBuffer(data Sensordata) {
|
||||
p.agr.serialSensorData = p.agr.serialSensorData.ConsolidateEpochsOnly(data)
|
||||
p.agr.serialMutex.Unlock()
|
||||
}
|
||||
|
||||
func (p *pipeline) Stop() {
|
||||
p.active = false
|
||||
}
|
||||
|
||||
1
core/replay.go
Normal file
1
core/replay.go
Normal file
@ -0,0 +1 @@
|
||||
package core
|
||||
46
core/repository.go
Normal file
46
core/repository.go
Normal file
@ -0,0 +1,46 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type writeRepo interface {
|
||||
SaveTracking(tracking *Tracking) error
|
||||
}
|
||||
|
||||
type readRepo interface {
|
||||
AllTrackings() ([]trackingMetadata, error)
|
||||
LoadTracking(id uuid.UUID) (Tracking, error)
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
repoStubSave
|
||||
loader repoStubLoad
|
||||
}
|
||||
|
||||
type repoStubSave struct {
|
||||
sensordataBuffer
|
||||
}
|
||||
type repoStubLoad struct{}
|
||||
|
||||
func (r *repoStubSave) SaveTracking(tracking *Tracking) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *repoStubLoad) AllTrackings() ([]trackingMetadata, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *repoStubLoad) LoadTracking(id uuid.UUID) (Tracking, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
type sensordataBuffer struct {
|
||||
// TODO: database stub
|
||||
data []Sensordata
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (s *sensordataBuffer) Store(data Sensordata) {
|
||||
}
|
||||
106
core/trackings.go
Normal file
106
core/trackings.go
Normal file
@ -0,0 +1,106 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OpMode uint8
|
||||
|
||||
const (
|
||||
STOPPED OpMode = iota
|
||||
LIVE
|
||||
REPLAY
|
||||
)
|
||||
|
||||
type TrackingService struct {
|
||||
Current *Tracking
|
||||
config *Configuration
|
||||
repo *repository
|
||||
pipe *pipeline
|
||||
opMode OpMode
|
||||
collectors []Collector
|
||||
//publish Publisher
|
||||
}
|
||||
|
||||
type Tracking struct {
|
||||
trackingMetadata
|
||||
data []*sensorRecord
|
||||
}
|
||||
|
||||
type trackingMetadata struct {
|
||||
UUID uuid.UUID
|
||||
TimeCreated time.Time
|
||||
}
|
||||
|
||||
type sensorRecord struct {
|
||||
RecordTime time.Time
|
||||
Sensordata
|
||||
}
|
||||
|
||||
func Service(c *Configuration) *TrackingService {
|
||||
d := NewDispatcher()
|
||||
r := &repository{}
|
||||
return &TrackingService{
|
||||
Current: nil,
|
||||
opMode: STOPPED,
|
||||
config: c,
|
||||
repo: r,
|
||||
pipe: NewPipeline(d, r, c),
|
||||
collectors: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TrackingService) NewTracking(cols ...CollectorType) {
|
||||
t.opMode = LIVE
|
||||
for _, col := range cols {
|
||||
t.collectors = append(t.collectors, NewCollector(col, t.pipe, t.config))
|
||||
}
|
||||
t.Current = emptyTracking()
|
||||
}
|
||||
|
||||
func (t *TrackingService) StartRecord() {
|
||||
if t.opMode != LIVE {
|
||||
log.Println("trackingservice: wrong mode of operation")
|
||||
}
|
||||
t.pipe.Run()
|
||||
for _, e := range t.collectors {
|
||||
e.Collect()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TrackingService) StopRecord() {
|
||||
if t.opMode != LIVE {
|
||||
log.Println("trackingservice: wrong mode of operation")
|
||||
}
|
||||
t.pipe.Stop()
|
||||
for _, e := range t.collectors {
|
||||
e.Stop()
|
||||
}
|
||||
err := t.repo.SaveTracking(t.Current)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
t.Current = emptyTracking()
|
||||
}
|
||||
|
||||
func (t *TrackingService) Reset() {
|
||||
}
|
||||
|
||||
func (t *TrackingService) LoadTrackings() {
|
||||
|
||||
}
|
||||
|
||||
func (t *TrackingService) LoadTracking(trackingId uuid.UUID) {
|
||||
|
||||
}
|
||||
|
||||
func emptyTracking() *Tracking {
|
||||
return &Tracking{
|
||||
trackingMetadata: trackingMetadata{
|
||||
UUID: uuid.New(),
|
||||
},
|
||||
data: []*sensorRecord{},
|
||||
}
|
||||
}
|
||||
2
go.mod
2
go.mod
@ -5,9 +5,11 @@ go 1.15
|
||||
require (
|
||||
github.com/gofiber/fiber/v2 v2.2.4
|
||||
github.com/gofiber/websocket/v2 v2.0.2
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/stretchr/testify v1.6.1 // indirect
|
||||
github.com/tidwall/gjson v1.6.0
|
||||
github.com/tidwall/pretty v1.0.2 // indirect
|
||||
github.com/upper/db/v4 v4.0.1 // indirect
|
||||
go.bug.st/serial v1.1.1
|
||||
)
|
||||
|
||||
50
go.sum
50
go.sum
@ -1,26 +1,44 @@
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
|
||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
|
||||
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/fasthttp/websocket v1.4.3 h1:qjhRJ/rTy4KB8oBxljEC00SDt6HUY9jLRfM601SUdS4=
|
||||
github.com/fasthttp/websocket v1.4.3/go.mod h1:5r4oKssgS7W6Zn6mPWap3NWzNPJNzUUh3baWTOhcYQk=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gofiber/fiber/v2 v2.1.0/go.mod h1:aG+lMkwy3LyVit4CnmYUbUdgjpc3UYOltvlJZ78rgQ0=
|
||||
github.com/gofiber/fiber/v2 v2.2.4 h1:t2V2SxlbQGdt8+SS/Mo+tQB0pDQn7OajKdA72qHcBVw=
|
||||
github.com/gofiber/fiber/v2 v2.2.4/go.mod h1:Aso7/M+EQOinVkWp4LUYjdlTpKTBoCk2Qo4djnMsyHE=
|
||||
github.com/gofiber/websocket/v2 v2.0.2 h1:UA/6NpyG+vmPGlvJvW8MJPJpRFuS7abinZ5HbLuV8u0=
|
||||
github.com/gofiber/websocket/v2 v2.0.2/go.mod h1:7VBnzEVRK0K0eTIVc5GbXPF1JWUFnllY0X4cRtG2v78=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
|
||||
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.1 h1:AHx9Ra40wIzl+GelgX2X6AWxmT5tfxhI1PL0523HcSw=
|
||||
github.com/mattn/go-sqlite3 v1.14.1/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/savsgio/gotils v0.0.0-20200608150037-a5f6f5aef16c h1:2nF5+FZ4/qp7pZVL7fR6DEaSTzuDmNaFTyqp92/hwF8=
|
||||
github.com/savsgio/gotils v0.0.0-20200608150037-a5f6f5aef16c/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
@ -32,6 +50,10 @@ github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/upper/db v1.0.1 h1:AFzy0fFO7EZ5woZGE/LVl9BWLKqyAWlglu+ZyHQTlbU=
|
||||
github.com/upper/db v3.7.1+incompatible h1:ehR+Q0msV25yZWXdFYD+3n4BvY9jefI336lmZy7FlAQ=
|
||||
github.com/upper/db/v4 v4.0.1 h1:mHmGBffne8fdiJjmtYXCuHSghO9027q4TJA9oGP50OM=
|
||||
github.com/upper/db/v4 v4.0.1/go.mod h1:pyAEIpPfnhpvO4zVbyUI+asgZjppZlq705fOFTyUOso=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE=
|
||||
@ -40,16 +62,27 @@ github.com/valyala/fasthttp v1.17.0 h1:P8/koH4aSnJ4xbd0cUUFEGQs3jQqIxoDDyRQrUiAk
|
||||
github.com/valyala/fasthttp v1.17.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
gitlab.com/cznic/ebnf2y v1.0.0/go.mod h1:jx14dqOldV2pRvSi8HASTB/k5fkIv2TwjYAp5py0MTs=
|
||||
gitlab.com/cznic/golex v1.0.0/go.mod h1:vkWdDgqbbThjRHoOLU7yNPgMxaubAkwnvF/4zeG8cvU=
|
||||
go.bug.st/serial v1.1.1 h1:5J1DpaIaSIruBi7jVnKXnhRS+YQ9+2PLJMtIZKoIgnc=
|
||||
go.bug.st/serial v1.1.1/go.mod h1:VmYBeyJWp5BnJ0tw2NUJHZdJTGl2ecBGABHlzRK1knY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190411193353-0480eff6dd7c/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -60,9 +93,26 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg=
|
||||
modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8=
|
||||
modernc.org/ebnfutil v1.0.0/go.mod h1:+2n/OnQXoild9pzrPa/2wmVtR+ufWjB/0fYkc0BV9sc=
|
||||
modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw=
|
||||
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
|
||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||
modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
|
||||
modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=
|
||||
modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk=
|
||||
modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8=
|
||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/ql v1.1.0/go.mod h1:Fj1ylcVyzcu/fgWZTrvBO9j/aEUg/ixLFnGtmzh7quI=
|
||||
modernc.org/sortutil v1.0.0/go.mod h1:1QO0q8IlIlmjBIwm6t/7sof874+xCfZouyqZMLIAtxM=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
|
||||
|
||||
Loading…
Reference in New Issue
Block a user