COntinue on values
This commit is contained in:
8
go.mod
8
go.mod
@@ -3,12 +3,10 @@ module gargoton.petite-maison-orange.fr/eric/pmomusic
|
||||
go 1.24.2
|
||||
|
||||
require (
|
||||
github.com/beevik/etree v1.5.1
|
||||
github.com/globusdigital/soap v1.4.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/koron/go-ssdp v0.0.6
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
)
|
||||
require golang.org/x/sys v0.32.0 // indirect
|
||||
|
||||
14
go.sum
14
go.sum
@@ -1,22 +1,24 @@
|
||||
github.com/beevik/etree v1.5.1 h1:TC3zyxYp+81wAmbsi8SWUpZCurbxa6S8RITYRSkNRwo=
|
||||
github.com/beevik/etree v1.5.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/globusdigital/soap v1.4.0 h1:nQDpWelZr3zKg6Oe1e5SqWd4PfiUvsl5/44oWUXy3II=
|
||||
github.com/globusdigital/soap v1.4.0/go.mod h1:p8hjOZ4FmK0jXBTcIZ6e5M2QBfcsxBUKWBYsHM2eZRw=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU=
|
||||
github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI=
|
||||
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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
384
internal/upnp/statevalue.go
Normal file
384
internal/upnp/statevalue.go
Normal file
@@ -0,0 +1,384 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type EventType string
|
||||
|
||||
const (
|
||||
EventEnabled EventType = "yes"
|
||||
EventDisabled EventType = "no"
|
||||
EventConditional EventType = "conditional"
|
||||
)
|
||||
|
||||
type StateConditionFunc func(instance *StateValueInstance) bool
|
||||
|
||||
type TypeModifier int
|
||||
|
||||
const (
|
||||
ModifierAtomic TypeModifier = iota // Valeur simple (par défaut)
|
||||
ModifierList // Liste d'éléments
|
||||
ModifierMap // Tableau associatif
|
||||
ModifierStruct // Structure nommée
|
||||
)
|
||||
|
||||
// StateValue represents a UPnP state variable with value constraints and eventing capabilities.
|
||||
// It encapsulates:
|
||||
// - Value type (StateVarType)
|
||||
// - Value range constraints (min/max)
|
||||
// - Allowed value list
|
||||
// - Eventing configuration
|
||||
// graph TD
|
||||
// A[StateValue] --> B[baseType: Type sérialisé]
|
||||
// A --> C[modifier: Structure des données]
|
||||
// C --> D[Liste]
|
||||
// C --> E[Map]
|
||||
// C --> F[Structure]
|
||||
// D --> G[elementType: Type des éléments]
|
||||
// E --> H[keyType: Type des clés]
|
||||
// E --> I[elementType: Type des valeurs]
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// state := StateValue{
|
||||
// name: "Volume",
|
||||
// baseType: StateType_UI2,
|
||||
// }
|
||||
// state.SetRange(0, 100) // Set 0-100 range
|
||||
// state.AppendAllowedValue(25, 50, 75) // Add specific allowed values
|
||||
type StateValue struct {
|
||||
name string
|
||||
baseType StateVarType // Renommé pour plus de clarté
|
||||
modifier TypeModifier
|
||||
step interface{}
|
||||
minDelta interface{}
|
||||
modifiable bool
|
||||
eventConditions []StateConditionFunc
|
||||
description string
|
||||
defaultValue interface{}
|
||||
valueRange *ValueRange
|
||||
allowedValues []interface{}
|
||||
sendEvents bool
|
||||
elementType StateVarType // Pour listes et valeurs de maps
|
||||
keyType StateVarType // Type des clés (pour les maps)
|
||||
structFields map[string]StateVarType // Champs (pour les structures)
|
||||
|
||||
}
|
||||
|
||||
// Name returns the state variable's name (e.g., "Volume", "Brightness").
|
||||
func (state *StateValue) Name() string {
|
||||
return state.name
|
||||
}
|
||||
|
||||
// Type returns the UPnP data type of the state variable.
|
||||
func (state *StateValue) Type() StateVarType {
|
||||
return state.baseType
|
||||
}
|
||||
|
||||
func (state *StateValue) AddEventCondition(condition StateConditionFunc) {
|
||||
state.eventConditions = append(state.eventConditions, condition)
|
||||
}
|
||||
|
||||
// ClearEventConditions réinitialise toutes les conditions
|
||||
func (state *StateValue) ClearEventConditions() {
|
||||
state.eventConditions = nil
|
||||
}
|
||||
|
||||
func (state *StateValue) SetDefault(value interface{}) error {
|
||||
if state.IsValidValue(value) {
|
||||
cvalue, _ := state.baseType.Cast(value)
|
||||
state.defaultValue = cvalue
|
||||
log.Debugf("🐞 Setting default value for %v to %v", state.name, cvalue)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid default value for %v (%v)", state.name, value)
|
||||
}
|
||||
|
||||
func (state *StateValue) HasDefault() bool {
|
||||
return state.defaultValue != nil
|
||||
}
|
||||
|
||||
func (state *StateValue) DefaultValue() interface{} {
|
||||
if !state.HasDefault() {
|
||||
return state.baseType.DefaultValue()
|
||||
}
|
||||
|
||||
return state.DefaultValue()
|
||||
}
|
||||
|
||||
// HasRange indicates if a value range constraint is defined.
|
||||
// Returns true if min/max boundaries are set.
|
||||
func (state *StateValue) HasRange() bool {
|
||||
return state.valueRange != nil
|
||||
}
|
||||
|
||||
// Maximum returns the upper bound of the value range.
|
||||
// Returns nil if no range is defined.
|
||||
func (state *StateValue) Maximum() interface{} {
|
||||
if state.valueRange == nil {
|
||||
return nil
|
||||
}
|
||||
return state.valueRange.max
|
||||
}
|
||||
|
||||
// Minimum returns the lower bound of the value range.
|
||||
// Returns nil if no range is defined.
|
||||
func (state *StateValue) Minimum() interface{} {
|
||||
if state.valueRange == nil {
|
||||
return nil
|
||||
}
|
||||
return state.valueRange.min
|
||||
}
|
||||
|
||||
// SetRange defines the inclusive value range [min, max].
|
||||
// Validates and casts values to the state variable's type.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// min: Lower boundary value
|
||||
// max: Upper boundary value
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// error: If values can't be cast to the type or are nil
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// err := volumeState.SetRange(0, 100) // 0-100 range for volume
|
||||
func (state *StateValue) SetRange(min, max interface{}) error {
|
||||
if min == nil || max == nil {
|
||||
return fmt.Errorf("min and max must not be nil")
|
||||
}
|
||||
limits, err := state.baseType.ValueRange(min, max)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting range: %v", err)
|
||||
}
|
||||
state.valueRange = limits
|
||||
|
||||
log.Debugf("🐞 Setting range of %s to [%v, %v]", state.name, min, max)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateMinimalValue dynamically updates the lower range boundary.
|
||||
// Requires an existing range to be set.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// value: New minimum value
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// error: If no range exists or value can't be cast
|
||||
func (state *StateValue) UpdateMinimalValue(value interface{}) error {
|
||||
if state.valueRange == nil {
|
||||
return fmt.Errorf("no range set for value %v", state.name)
|
||||
}
|
||||
cvalue, err := state.baseType.Cast(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("casting value: %v", err)
|
||||
}
|
||||
state.valueRange.min = cvalue
|
||||
|
||||
log.Debugf("🐞 Updating minimal value of %s to %v", state.name, cvalue)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateMaximalValue dynamically updates the upper range boundary.
|
||||
// Requires an existing range to be set.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// value: New maximum value
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// error: If no range exists or value can't be cast
|
||||
func (state *StateValue) UpdateMaximalValue(value interface{}) error {
|
||||
if state.valueRange == nil {
|
||||
return fmt.Errorf("no range set for value %v", state.name)
|
||||
}
|
||||
cvalue, err := state.baseType.Cast(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("casting value: %v", err)
|
||||
}
|
||||
state.valueRange.max = cvalue
|
||||
|
||||
log.Debugf("🐞 Updating maximal value of %s to %v", state.name, cvalue)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValueInRange checks if a value falls within the defined range.
|
||||
// Always returns true if no range is set.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// value: Value to check
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// bool: True if within range or no range defined
|
||||
func (state *StateValue) IsValueInRange(value interface{}) bool {
|
||||
return state.baseType.InRange(value, state.valueRange)
|
||||
}
|
||||
|
||||
// IsSendingEvents indicates if state changes trigger UPnP events.
|
||||
func (state *StateValue) IsSendingEvents() bool {
|
||||
return state.sendEvents
|
||||
}
|
||||
|
||||
// SetSendingEvents enables event notifications for state changes.
|
||||
func (state *StateValue) SetSendingEvents() {
|
||||
state.sendEvents = true
|
||||
log.Debugf("🐞 Enabling event sending for %s", state.name)
|
||||
}
|
||||
|
||||
// UnsetSendingEvents disables event notifications for state changes.
|
||||
func (state *StateValue) UnsetSendingEvents() {
|
||||
state.sendEvents = false
|
||||
log.Debugf("🐞 Disabling event sending for %s", state.name)
|
||||
}
|
||||
|
||||
// HasAllowedValues indicates if an allowed value list is defined.
|
||||
func (state *StateValue) HasAllowedValues() bool {
|
||||
return len(state.allowedValues) > 0
|
||||
}
|
||||
|
||||
// AllowedValues returns the list of permitted values.
|
||||
// Returns an empty slice if no values are defined.
|
||||
func (state *StateValue) AllowedValues() []interface{} {
|
||||
return state.allowedValues
|
||||
}
|
||||
|
||||
// AppendAllowedValue adds values to the permitted value list.
|
||||
// Values are cast to the state variable's type before adding.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// value: One or more values to add
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// error: If any value can't be cast to the type
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// err := state.AppendAllowedValue("PLAYING", "PAUSED", "STOPPED")
|
||||
func (state *StateValue) AppendAllowedValue(value ...interface{}) error {
|
||||
state.allowedValues = slices.Grow(state.allowedValues, len(value))
|
||||
for _, v := range value {
|
||||
cv, err := state.baseType.Cast(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("casting allowed value: %v", err)
|
||||
}
|
||||
state.allowedValues = append(state.allowedValues, cv)
|
||||
}
|
||||
|
||||
log.Debugf("🐞 Added allowed values to %s: %v", state.name, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValueAllowed checks if a value exists in the allowed value list.
|
||||
// Always returns true if no allowed values are defined.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// value: Value to check
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// bool: True if value is permitted or no list defined
|
||||
func (state *StateValue) IsValueAllowed(value interface{}) bool {
|
||||
if !state.HasAllowedValues() {
|
||||
return true // No list = any value valid
|
||||
}
|
||||
|
||||
cvalue, err := state.baseType.Cast(value)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, allowed := range state.allowedValues {
|
||||
if reflect.DeepEqual(cvalue, allowed) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsValidValue performs full validation against all constraints.
|
||||
// Checks (in order):
|
||||
// 1. Value can be cast to the type
|
||||
// 2. Value is within range (if defined)
|
||||
// 3. Value is in allowed list (if defined)
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// bool: True if value passes all applicable constraints
|
||||
func (state *StateValue) IsValidValue(value interface{}) bool {
|
||||
cvalue, err := state.baseType.Cast(value)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return state.IsValueInRange(cvalue) && state.IsValueAllowed(cvalue)
|
||||
}
|
||||
|
||||
func (state *StateValue) HasDescription() bool {
|
||||
return len(state.description) > 0
|
||||
}
|
||||
|
||||
func (state *StateValue) Description() string {
|
||||
return state.description
|
||||
}
|
||||
|
||||
func (state *StateValue) SetDescription(desc string) {
|
||||
state.description = strings.TrimSpace(desc)
|
||||
}
|
||||
|
||||
func (state *StateValue) IsConstant() bool {
|
||||
return !state.modifiable
|
||||
}
|
||||
|
||||
func (state *StateValue) SetConstant() {
|
||||
state.modifiable = false
|
||||
}
|
||||
|
||||
func (state *StateValue) SetModifiable() {
|
||||
state.modifiable = true
|
||||
}
|
||||
|
||||
func (state *StateValue) SetStep(step interface{}) error {
|
||||
// Validation que le step correspond au type de la variable
|
||||
if _, err := state.baseType.Cast(step); err != nil {
|
||||
return fmt.Errorf("invalid step type: %v", err)
|
||||
}
|
||||
state.step = step
|
||||
return nil
|
||||
}
|
||||
|
||||
func (state *StateValue) UnsetStep() {
|
||||
state.step = nil
|
||||
}
|
||||
|
||||
func (state *StateValue) HasStep() bool {
|
||||
return state.step != nil
|
||||
}
|
||||
|
||||
func (state *StateValue) Step() interface{} {
|
||||
return state.step
|
||||
}
|
||||
|
||||
func (state *StateValue) NewInstance() *StateValueInstance {
|
||||
return &StateValueInstance{
|
||||
model: state,
|
||||
value: state.DefaultValue(),
|
||||
lastChange: time.Now(),
|
||||
lastEvent: time.Unix(int64(1718985600), 0).UTC(),
|
||||
}
|
||||
}
|
||||
29
internal/upnp/statevalueinstance.go
Normal file
29
internal/upnp/statevalueinstance.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package upnp
|
||||
|
||||
import "time"
|
||||
|
||||
type StateValueInstance struct {
|
||||
model *StateValue
|
||||
value interface{}
|
||||
previousValue interface{}
|
||||
lastChange time.Time
|
||||
lastEvent time.Time
|
||||
}
|
||||
|
||||
func (instance *StateValueInstance) Model() *StateValue {
|
||||
return instance.model
|
||||
}
|
||||
|
||||
func (instance *StateValueInstance) Value() interface{} {
|
||||
return instance.value
|
||||
}
|
||||
|
||||
// ShouldTriggerEvent vérifie toutes les conditions
|
||||
func (instance *StateValueInstance) ShouldTriggerEvent() bool {
|
||||
for _, condition := range instance.model.eventConditions {
|
||||
if !condition(instance) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -379,8 +379,134 @@ func (t StateVarType) Cmp(v1, v2 interface{}) int {
|
||||
//
|
||||
// range := ValueRange{min: uint16(10), max: uint16(100)}
|
||||
// StateType_UI2.InRange(uint16(50), range) // true
|
||||
func (t StateVarType) InRange(val interface{}, interval ValueRange) bool {
|
||||
return t.Cmp(val, interval.min) >= 0 && t.Cmp(val, interval.max) <= 0
|
||||
func (t StateVarType) InRange(val interface{}, interval *ValueRange) bool {
|
||||
return interval == nil || t.Cmp(val, interval.min) >= 0 && t.Cmp(val, interval.max) <= 0
|
||||
}
|
||||
|
||||
// ValueRange creates a valid value range for the UPnP type.
|
||||
//
|
||||
// This method casts the provided min and max values to the UPnP type and returns
|
||||
// a ValueRange struct suitable for range validation. If either value cannot be
|
||||
// cast to the type, it returns an error.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// min: Minimum value of the range (inclusive)
|
||||
// max: Maximum value of the range (inclusive)
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// ValueRange: Valid range structure if cast succeeds
|
||||
// error: If min or max cannot be cast to the type
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Create a range for UI2 (uint16) values
|
||||
// r, err := StateType_UI2.ValueRange(10, 100)
|
||||
// if err != nil { /* handle error */ }
|
||||
// valid := StateType_UI2.InRange(50, r) // true
|
||||
//
|
||||
// Notes:
|
||||
// - The range is inclusive: [min, max]
|
||||
// - Values must be comparable using the type's comparison logic
|
||||
// - For time types, min and max must be valid time values
|
||||
func (t StateVarType) ValueRange(min, max interface{}) (*ValueRange, error) {
|
||||
cmin, error := t.Cast(min)
|
||||
if error != nil {
|
||||
return nil, fmt.Errorf("min value %v is not castable to type %s", min, t.String())
|
||||
}
|
||||
cmax, error := t.Cast(max)
|
||||
if error != nil {
|
||||
return nil, fmt.Errorf("max value %v is not castable to type %s", min, t.String())
|
||||
}
|
||||
|
||||
return &ValueRange{min: cmin, max: cmax}, nil
|
||||
}
|
||||
|
||||
// NewAtomicValue crée une valeur simple
|
||||
func (t StateVarType) NewAtomicValue(name string) *StateValue {
|
||||
return &StateValue{
|
||||
name: name,
|
||||
baseType: t,
|
||||
modifier: ModifierAtomic,
|
||||
}
|
||||
}
|
||||
|
||||
// NewListValue crée une liste
|
||||
func (t StateVarType) NewListValue(name string, elementType StateVarType) *StateValue {
|
||||
return &StateValue{
|
||||
name: name,
|
||||
baseType: t,
|
||||
modifier: ModifierList,
|
||||
elementType: elementType,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMapValue crée une map
|
||||
func (t StateVarType) NewMapValue(
|
||||
name string,
|
||||
keyType StateVarType,
|
||||
valueType StateVarType,
|
||||
) *StateValue {
|
||||
return &StateValue{
|
||||
name: name,
|
||||
baseType: t,
|
||||
modifier: ModifierMap,
|
||||
keyType: keyType,
|
||||
elementType: valueType, // elementType = valeur de la map
|
||||
}
|
||||
}
|
||||
|
||||
// NewStructValue crée une valeur de type struct
|
||||
func (t StateVarType) NewStructValue(name string, fields map[string]StateVarType) *StateValue {
|
||||
return &StateValue{
|
||||
name: name,
|
||||
baseType: t,
|
||||
modifier: ModifierStruct,
|
||||
structFields: fields,
|
||||
}
|
||||
}
|
||||
|
||||
func (t StateVarType) DefaultValue() interface{} {
|
||||
switch t {
|
||||
case StateType_Unknown:
|
||||
|
||||
case StateType_UI1, StateType_UI2, StateType_UI4:
|
||||
return uint64(0)
|
||||
|
||||
case StateType_I1, StateType_I2, StateType_I4, StateType_Int:
|
||||
return int64(0)
|
||||
|
||||
case StateType_R4, StateType_R8, StateType_Number, StateType_Fixed14_4:
|
||||
return float64(0)
|
||||
|
||||
case StateType_Char, StateType_String:
|
||||
return ""
|
||||
case StateType_Boolean:
|
||||
return false
|
||||
|
||||
case StateType_BinBase64:
|
||||
return ""
|
||||
case StateType_BinHex:
|
||||
return ""
|
||||
case StateType_Date:
|
||||
return time.Unix(int64(1718985600), 0).UTC()
|
||||
case StateType_DateTime:
|
||||
return time.Unix(int64(1718985600), 0).UTC()
|
||||
case StateType_DateTimeTZ:
|
||||
return time.Unix(int64(1718985600), 0).UTC()
|
||||
case StateType_Time:
|
||||
return time.Unix(int64(1718985600), 0).UTC()
|
||||
case StateType_TimeTZ:
|
||||
return time.Unix(int64(1718985600), 0).UTC()
|
||||
case StateType_UUID:
|
||||
return ""
|
||||
case StateType_URI:
|
||||
return ""
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// toInt converts various types to signed integer with specified bit size.
|
||||
|
||||
15
internal/upnp/valuerange.go
Normal file
15
internal/upnp/valuerange.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package upnp
|
||||
|
||||
// ValueRange represents an inclusive range constraint for a state variable value.
|
||||
// It defines the minimum and maximum allowable values for a given UPnP type.
|
||||
//
|
||||
// Usage:
|
||||
// - For numeric types: min/max must be numeric types
|
||||
// - For time types: min/max must be time.Time values
|
||||
// - For strings/UUIDs: min/max must be string values
|
||||
//
|
||||
// Use with StateVarType.InRange() to check if values fall within the range.
|
||||
type ValueRange struct {
|
||||
min interface{}
|
||||
max interface{}
|
||||
}
|
||||
Reference in New Issue
Block a user