partial subscriptions

not really partial. they just happen per peripheral now
This commit is contained in:
2026-09-23 17:41:06 +01:00
parent a519cf473e
commit 2952528a60
12 changed files with 172 additions and 110 deletions
+56 -32
View File
@@ -29,13 +29,14 @@ type IRacing struct {
mut sync.Mutex
data *telemetry.TelemetryData
updaters [telemetry.MaxFields]func(*telemetry.TelemetryField)
// Field Subscription management
boundFields map[telemetry.FieldID]bool
// Timing information
ticker *time.Ticker // ticker will keep polling intervals constant
// Stream
wg sync.WaitGroup
// streamCh chan telemetry.TelemetryData
wg sync.WaitGroup
streamCancel context.CancelFunc
}
@@ -55,6 +56,8 @@ func NewIRacingProvider(
logger: logger,
SDK: sdk,
data: telemetry.NewTelemetryData(),
// Field subscription management
boundFields: make(map[telemetry.FieldID]bool, telemetry.MaxFields),
// TODO: make this configurable from the user side
ticker: time.NewTicker(time.Second / 60),
}
@@ -225,46 +228,67 @@ func (i *IRacing) StopStream() {
i.streamCancel = nil
}
func (i *IRacing) Subscribe(requestFields []telemetry.FieldID) {
i.logger.Debug(fmt.Sprintf("Len Req: %d\n", len(requestFields)))
// TODO: this function is exactly the same in BeamNG drive now, and I reckon it will be the same
// In plenty other things. I should make it TelemetryData method
func (i *IRacing) subscribe(fields []telemetry.FieldID) []string {
newSubscriptions := make([]string, 0, telemetry.MaxFields)
i.data.ActiveBinds = make([]telemetry.BoundField, 0, len(requestFields))
i.mut.Lock()
defer i.mut.Unlock()
// First we must add the virtual fields
// we will add their dependencies and the primitives to a slice
pendingBinds := make([]telemetry.FieldID, 0, telemetry.MaxFields)
for _, id := range requestFields {
switch id {
case telemetry.RPMStateColour:
i.data.VirtualBinds = append(i.data.VirtualBinds, telemetry.NewRPMLights())
case telemetry.FCCurrentLap:
i.data.VirtualBinds = append(i.data.VirtualBinds,
telemetry.NewFuelCalculator(i.logger.WithGroup("FUEL CALC")))
default:
// primitive telemetry field
pendingBinds = append(pendingBinds, id)
}
}
boundCheck := make(map[telemetry.FieldID]bool)
// Now that we know all the fields we need to bind we follow the binding procedure
for _, id := range pendingBinds {
// Check if we already bound this FieldID
if boundCheck[id] {
for _, id := range fields {
if i.boundFields[id] {
continue
}
binding := telemetry.BoundField{
i.data.ActiveBinds[id] = telemetry.BoundField{
ID: id,
}
i.data.ActiveBinds = append(i.data.ActiveBinds, binding)
boundCheck[id] = true
i.boundFields[id] = true
newSubscriptions = append(newSubscriptions, telemetry.FieldNames[id])
}
// unsubscribe from fields we many not need anymore
for key, bound := range i.boundFields {
if _, ok := i.data.ActiveBinds[key]; bound && !ok {
delete(i.data.ActiveBinds, key)
i.boundFields[key] = false
}
}
return newSubscriptions
}
func (i *IRacing) Subscribe(requestFields []telemetry.FieldID) []string {
i.logger.Debug(fmt.Sprintf("Len Req: %d\n", len(requestFields)))
// First we must add the virtual fields
// we will add their dependencies and the primitives to a slice
toBind := make([]telemetry.FieldID, 0, telemetry.MaxFields)
i.mut.Lock()
for _, id := range requestFields {
switch id {
case telemetry.RPMStateColour:
rpmLights := telemetry.NewRPMLights()
i.data.VirtualBinds[rpmLights.Name()] = rpmLights
toBind = append(toBind, rpmLights.EnsureSubscribed()...)
case telemetry.FCCurrentLap:
fuelCalc := telemetry.NewFuelCalculator(i.logger.WithGroup("FUEL CALC"))
i.data.VirtualBinds[fuelCalc.Name()] = fuelCalc
toBind = append(toBind, fuelCalc.EnsureSubscribed()...)
default:
// primitive telemetry field
toBind = append(toBind, id)
}
}
i.mut.Unlock()
newSubs := i.subscribe(toBind)
i.logger.Debug(fmt.Sprintf("Subscribed: %+v\n", i.data.ActiveBinds))
return newSubs
}
func (i *IRacing) Name() string {