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 { initOnce sync.Once ln net.Listener notifyCtrlChan chan *simulator.ControlMsg notifyCarChan chan *simulator.CarConfigMsg notifyCamChan chan *simulator.CamConfigMsg } 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 } 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) { c.initOnce.Do(c.init) reader := bufio.NewReader(conn) writer := bufio.NewWriter(conn) for { rawMsg, err := reader.ReadBytes('\n') if err != nil { if err == io.EOF { log.Debug("connection closed") break } log.Errorf("unable to read request: %v", err) return } var msg simulator.Msg err = json.Unmarshal(rawMsg, &msg) if err != nil { log.Errorf("unable to unmarshal msg \"%v\": %v", string(rawMsg), err) continue } 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 } } } 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) } if c.notifyCtrlChan != nil { close(c.notifyCtrlChan) } if c.notifyCarChan != nil { close(c.notifyCarChan) } if c.notifyCamChan != nil { close(c.notifyCamChan) } 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 }