2021-01-15 10:31:37 +00:00
|
|
|
package gateway
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"github.com/cyrilix/robocar-simulator/pkg/simulator"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Gw2SimMock struct {
|
2021-02-16 16:46:10 +00:00
|
|
|
initOnce sync.Once
|
2021-01-15 10:31:37 +00:00
|
|
|
|
|
|
|
ln net.Listener
|
2021-02-16 16:46:10 +00:00
|
|
|
notifyCtrlChan chan *simulator.ControlMsg
|
|
|
|
notifyCarChan chan *simulator.CarConfigMsg
|
|
|
|
notifyCamChan chan *simulator.CamConfigMsg
|
2021-01-15 10:31:37 +00:00
|
|
|
}
|
|
|
|
|
2021-02-16 16:46:10 +00:00
|
|
|
func (c *Gw2SimMock) init(){
|
|
|
|
c.notifyCtrlChan = make(chan *simulator.ControlMsg)
|
|
|
|
c.notifyCarChan = make(chan *simulator.CarConfigMsg)
|
|
|
|
c.notifyCamChan = make(chan *simulator.CamConfigMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Gw2SimMock) NotifyCtrl() <-chan *simulator.ControlMsg {
|
|
|
|
c.initOnce.Do(c.init)
|
|
|
|
return c.notifyCtrlChan
|
|
|
|
}
|
|
|
|
func (c *Gw2SimMock) NotifyCar() <-chan *simulator.CarConfigMsg {
|
|
|
|
c.initOnce.Do(c.init)
|
|
|
|
return c.notifyCarChan
|
|
|
|
}
|
|
|
|
func (c *Gw2SimMock) NotifyCamera() <-chan *simulator.CamConfigMsg {
|
|
|
|
c.initOnce.Do(c.init)
|
|
|
|
return c.notifyCamChan
|
2021-01-15 10:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Gw2SimMock) listen() error {
|
|
|
|
ln, err := net.Listen("tcp", "127.0.0.1:")
|
|
|
|
c.ln = ln
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return fmt.Errorf("unable to listen on port: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
conn, err := c.ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
log.Debugf("connection close: %v", err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
go c.handleConnection(conn)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Gw2SimMock) Addr() string {
|
|
|
|
return c.ln.Addr().String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Gw2SimMock) handleConnection(conn net.Conn) {
|
2021-02-16 16:46:10 +00:00
|
|
|
c.initOnce.Do(c.init)
|
2021-01-15 10:31:37 +00:00
|
|
|
reader := bufio.NewReader(conn)
|
2021-02-16 16:46:10 +00:00
|
|
|
writer := bufio.NewWriter(conn)
|
|
|
|
|
2021-01-15 10:31:37 +00:00
|
|
|
for {
|
2021-02-16 16:46:10 +00:00
|
|
|
rawMsg, err := reader.ReadBytes('\n')
|
2021-01-15 10:31:37 +00:00
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
log.Debug("connection closed")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
log.Errorf("unable to read request: %v", err)
|
|
|
|
return
|
|
|
|
}
|
2021-02-16 16:46:10 +00:00
|
|
|
var msg simulator.Msg
|
|
|
|
err = json.Unmarshal(rawMsg, &msg)
|
2021-01-15 10:31:37 +00:00
|
|
|
if err != nil {
|
2021-02-16 16:46:10 +00:00
|
|
|
log.Errorf("unable to unmarshal msg \"%v\": %v", string(rawMsg), err)
|
2021-01-15 10:31:37 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-02-16 16:46:10 +00:00
|
|
|
switch msg.MsgType {
|
|
|
|
case simulator.MsgTypeControl:
|
|
|
|
var msgControl simulator.ControlMsg
|
|
|
|
err = json.Unmarshal(rawMsg, &msgControl)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to unmarshal control msg \"%v\": %v", string(rawMsg), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
c.notifyCtrlChan <- &msgControl
|
|
|
|
case simulator.MsgTypeCarConfig:
|
|
|
|
var msgCar simulator.CarConfigMsg
|
|
|
|
err = json.Unmarshal(rawMsg, &msgCar)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to unmarshal car msg \"%v\": %v", string(rawMsg), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
c.notifyCarChan <- &msgCar
|
|
|
|
carLoadedMsg := simulator.Msg{MsgType: simulator.MsgTypeCarLoaded}
|
|
|
|
resp, err := json.Marshal(&carLoadedMsg)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to generate car loaded response: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
_, err = writer.WriteString(string(resp) + "\n")
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to write car loaded response: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
err = writer.Flush()
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to flush car loaded response: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
case simulator.MsgTypeCameraConfig:
|
|
|
|
var msgCam simulator.CamConfigMsg
|
|
|
|
err = json.Unmarshal(rawMsg, &msgCam)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to unmarshal camera msg \"%v\": %v", string(rawMsg), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
c.notifyCamChan <- &msgCam
|
|
|
|
}
|
2021-01-15 10:31:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Gw2SimMock) Close() error {
|
|
|
|
log.Debugf("close mock server")
|
|
|
|
err := c.ln.Close()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to close mock server: %v", err)
|
|
|
|
}
|
2021-02-16 16:46:10 +00:00
|
|
|
if c.notifyCtrlChan != nil {
|
|
|
|
close(c.notifyCtrlChan)
|
|
|
|
}
|
|
|
|
if c.notifyCarChan != nil {
|
|
|
|
close(c.notifyCarChan)
|
|
|
|
}
|
|
|
|
if c.notifyCamChan != nil {
|
|
|
|
close(c.notifyCamChan)
|
2021-01-15 10:31:37 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type Sim2GwMock struct {
|
|
|
|
ln net.Listener
|
|
|
|
muConn sync.Mutex
|
|
|
|
conn net.Conn
|
|
|
|
writer *bufio.Writer
|
|
|
|
newConnection chan net.Conn
|
|
|
|
logger *log.Entry
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Sim2GwMock) EmitMsg(p string) (err error) {
|
|
|
|
c.muConn.Lock()
|
|
|
|
defer c.muConn.Unlock()
|
|
|
|
_, err = c.writer.WriteString(p + "\n")
|
|
|
|
if err != nil {
|
|
|
|
c.logger.Errorf("unable to write response: %v", err)
|
|
|
|
}
|
|
|
|
if err == io.EOF {
|
|
|
|
c.logger.Info("Connection closed")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = c.writer.Flush()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Sim2GwMock) WaitConnection() {
|
|
|
|
c.muConn.Lock()
|
|
|
|
defer c.muConn.Unlock()
|
|
|
|
c.logger.Debug("simulator waiting connection")
|
|
|
|
if c.conn != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.logger.Debug("new connection")
|
|
|
|
conn := <-c.newConnection
|
|
|
|
|
|
|
|
c.conn = conn
|
|
|
|
c.writer = bufio.NewWriter(conn)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Sim2GwMock) Start() error {
|
|
|
|
c.logger = log.WithField("simulator", "mock")
|
|
|
|
c.newConnection = make(chan net.Conn)
|
|
|
|
ln, err := net.Listen("tcp", "127.0.0.1:")
|
|
|
|
c.ln = ln
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to listen on port: %v", err)
|
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
conn, err := c.ln.Accept()
|
|
|
|
if err != nil && err == io.EOF {
|
|
|
|
c.logger.Errorf("connection close: %v", err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if c.newConnection == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
c.newConnection <- conn
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Sim2GwMock) Addr() string {
|
|
|
|
return c.ln.Addr().String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Sim2GwMock) Close() error {
|
|
|
|
c.logger.Debug("close mock server")
|
|
|
|
|
|
|
|
if c == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
close(c.newConnection)
|
|
|
|
c.newConnection = nil
|
|
|
|
err := c.ln.Close()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to close mock server: %v", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|