made the mechanism resilient enough to detect stalled data
This commit is contained in:
@@ -181,7 +181,7 @@ func (sdk *BeamNGSDK) Update() (int, error) {
|
|||||||
nBytes, err = sdk.reader.Next(sdk.buffer)
|
nBytes, err = sdk.reader.Next(sdk.buffer)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nBytes, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sdk.Opts.ExportData {
|
if sdk.Opts.ExportData {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer sdk.Close()
|
defer sdk.Close()
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Second / 60)
|
ticker := time.NewTicker(time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|||||||
+6
-7
@@ -1,14 +1,15 @@
|
|||||||
package bngsdk
|
package bngsdk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"log/slog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OgUDPReader struct {
|
type OgUDPReader struct {
|
||||||
udpConnection *UDPTransport
|
udpConnection *UDPTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrInvalidOutgaugeData = errors.New("data is of different size than outgauge")
|
||||||
|
|
||||||
func NewOgUDPReader(ip string, port int) (*OgUDPReader, error) {
|
func NewOgUDPReader(ip string, port int) (*OgUDPReader, error) {
|
||||||
conn, err := NewUDPReader(ip, port)
|
conn, err := NewUDPReader(ip, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -34,17 +35,15 @@ func (ogr *OgUDPReader) Reset() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ogr *OgUDPReader) Next(buffer []byte) (int, error) {
|
func (ogr *OgUDPReader) Next(buffer []byte) (int, error) {
|
||||||
slog.Debug("Reading")
|
|
||||||
|
|
||||||
nBytes, err := ogr.udpConnection.Read(buffer)
|
nBytes, err := ogr.udpConnection.Read(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if enough data was received to fill our struct
|
// Check if enough data was received to fill our struct
|
||||||
if nBytes < outgaugeSize {
|
if nBytes != outgaugeSize {
|
||||||
return 0, fmt.Errorf("received data is smaller than outgauge size")
|
return 0, ErrInvalidOutgaugeData
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, nil
|
return nBytes, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-6
@@ -1,12 +1,23 @@
|
|||||||
package bngsdk
|
package bngsdk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrReaderDisabled = errors.New("reader is currently turned off")
|
||||||
|
var (
|
||||||
|
ErrNoData = errors.New("no new data available")
|
||||||
|
readTimeout = (time.Second / 60) * 5 // N missed frames at 60fps
|
||||||
)
|
)
|
||||||
|
|
||||||
type UDPTransport struct {
|
type UDPTransport struct {
|
||||||
address *net.UDPAddr
|
address *net.UDPAddr
|
||||||
connection *net.UDPConn
|
connection *net.UDPConn
|
||||||
|
dataChan chan []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUDPReader(ip string, port int) (*UDPTransport, error) {
|
func NewUDPReader(ip string, port int) (*UDPTransport, error) {
|
||||||
@@ -21,10 +32,15 @@ func NewUDPReader(ip string, port int) (*UDPTransport, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &UDPTransport{
|
udpT := UDPTransport{
|
||||||
address: addr,
|
address: addr,
|
||||||
connection: conn,
|
connection: conn,
|
||||||
}, nil
|
dataChan: make(chan []byte, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
go udpT.udpSink()
|
||||||
|
|
||||||
|
return &udpT, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUDPWriter(ip string, port int) (*UDPTransport, error) {
|
func NewUDPWriter(ip string, port int) (*UDPTransport, error) {
|
||||||
@@ -45,17 +61,41 @@ func NewUDPWriter(ip string, port int) (*UDPTransport, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// udpSink is a loop that will consume the most recent packets on the port
|
||||||
|
// instead of letting them pile up
|
||||||
|
func (ut *UDPTransport) udpSink() {
|
||||||
|
defer close(ut.dataChan)
|
||||||
|
|
||||||
|
for {
|
||||||
|
ut.connection.SetReadDeadline(time.Now().Add(readTimeout))
|
||||||
|
|
||||||
|
buf := make([]byte, unsafe.Sizeof(Outgauge{}))
|
||||||
|
nBytes, _, err := ut.connection.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ut.dataChan <- buf[:nBytes]:
|
||||||
|
default:
|
||||||
|
<-ut.dataChan
|
||||||
|
ut.dataChan <- buf[:nBytes]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ut *UDPTransport) Write(data []byte) (int, error) {
|
func (ut *UDPTransport) Write(data []byte) (int, error) {
|
||||||
return ut.connection.Write(data)
|
return ut.connection.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ut *UDPTransport) Read(buffer []byte) (int, error) {
|
func (ut *UDPTransport) Read(buffer []byte) (int, error) {
|
||||||
n, _, err := ut.connection.ReadFromUDP(buffer)
|
data, ok := <-ut.dataChan
|
||||||
if err != nil {
|
if !ok {
|
||||||
return 0, err
|
slog.Error(ErrNoData.Error())
|
||||||
|
return 0, ErrNoData
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, nil
|
return copy(buffer, data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ut *UDPTransport) Close() error {
|
func (ut *UDPTransport) Close() error {
|
||||||
|
|||||||
Reference in New Issue
Block a user