general: add Clone() method to Conf and PathConf (#1633)

this allows to detect errors during cloning
This commit is contained in:
Alessandro Ros
2023-03-31 16:22:08 +02:00
committed by GitHub
parent 5b61983fa6
commit bca3013bd0
11 changed files with 89 additions and 49 deletions
+5 -2
View File
@@ -21,8 +21,11 @@ func (d AuthMethods) MarshalJSON() ([]byte, error) {
case headers.AuthBasic:
out[i] = "basic"
default:
case headers.AuthDigest:
out[i] = "digest"
default:
return nil, fmt.Errorf("invalid authentication method: %v", v)
}
}
@@ -47,7 +50,7 @@ func (d *AuthMethods) UnmarshalJSON(b []byte) error {
*d = append(*d, headers.AuthDigest)
default:
return fmt.Errorf("invalid authentication method: %s", v)
return fmt.Errorf("invalid authentication method: '%s'", v)
}
}
+18 -1
View File
@@ -13,6 +13,7 @@ import (
"github.com/aler9/gortsplib/v2"
"github.com/aler9/gortsplib/v2/pkg/headers"
"github.com/bluenviron/gohlslib"
"golang.org/x/crypto/nacl/secretbox"
"gopkg.in/yaml.v2"
@@ -264,6 +265,22 @@ func Load(fpath string) (*Conf, bool, error) {
return conf, found, nil
}
// Clone clones the configuration.
func (conf Conf) Clone() *Conf {
enc, err := json.Marshal(conf)
if err != nil {
panic(err)
}
var dest Conf
err = json.Unmarshal(enc, &dest)
if err != nil {
panic(err)
}
return &dest
}
// CheckAndFillMissing checks the configuration for errors and fills missing parameters.
func (conf *Conf) CheckAndFillMissing() error {
// general
@@ -392,7 +409,7 @@ func (conf *Conf) CheckAndFillMissing() error {
conf.HLSAllowOrigin = "*"
}
switch conf.HLSVariant {
case HLSVariantLowLatency:
case HLSVariant(gohlslib.MuxerVariantLowLatency):
if conf.HLSSegmentCount < 7 {
return fmt.Errorf("Low-Latency HLS requires at least 7 segments")
}
+5 -2
View File
@@ -26,8 +26,11 @@ func (d Encryption) MarshalJSON() ([]byte, error) {
case EncryptionOptional:
out = "optional"
default:
case EncryptionStrict:
out = "strict"
default:
return nil, fmt.Errorf("invalid encryption: %v", d)
}
return json.Marshal(out)
@@ -51,7 +54,7 @@ func (d *Encryption) UnmarshalJSON(b []byte) error {
*d = EncryptionStrict
default:
return fmt.Errorf("invalid encryption value: '%s'", in)
return fmt.Errorf("invalid encryption: '%s'", in)
}
return nil
+10 -14
View File
@@ -10,26 +10,22 @@ import (
// HLSVariant is the hlsVariant parameter.
type HLSVariant gohlslib.MuxerVariant
// supported HLS variants.
const (
HLSVariantMPEGTS HLSVariant = HLSVariant(gohlslib.MuxerVariantMPEGTS)
HLSVariantFMP4 HLSVariant = HLSVariant(gohlslib.MuxerVariantFMP4)
HLSVariantLowLatency HLSVariant = HLSVariant(gohlslib.MuxerVariantLowLatency)
)
// MarshalJSON implements json.Marshaler.
func (d HLSVariant) MarshalJSON() ([]byte, error) {
var out string
switch d {
case HLSVariantMPEGTS:
case HLSVariant(gohlslib.MuxerVariantMPEGTS):
out = "mpegts"
case HLSVariantFMP4:
case HLSVariant(gohlslib.MuxerVariantFMP4):
out = "fmp4"
default:
case HLSVariant(gohlslib.MuxerVariantLowLatency):
out = "lowLatency"
default:
return nil, fmt.Errorf("invalid HLS variant: %v", d)
}
return json.Marshal(out)
@@ -44,16 +40,16 @@ func (d *HLSVariant) UnmarshalJSON(b []byte) error {
switch in {
case "mpegts":
*d = HLSVariantMPEGTS
*d = HLSVariant(gohlslib.MuxerVariantMPEGTS)
case "fmp4":
*d = HLSVariantFMP4
*d = HLSVariant(gohlslib.MuxerVariantFMP4)
case "lowLatency":
*d = HLSVariantLowLatency
*d = HLSVariant(gohlslib.MuxerVariantLowLatency)
default:
return fmt.Errorf("invalid hlsVariant value: '%s'", in)
return fmt.Errorf("invalid HLS variant: '%s'", in)
}
return nil
+4 -1
View File
@@ -27,8 +27,11 @@ func (d LogDestinations) MarshalJSON() ([]byte, error) {
case logger.DestinationFile:
v = "file"
default:
case logger.DestinationSyslog:
v = "syslog"
default:
return nil, fmt.Errorf("invalid log destination: %v", p)
}
out[i] = v
+5 -2
View File
@@ -24,8 +24,11 @@ func (d LogLevel) MarshalJSON() ([]byte, error) {
case LogLevel(logger.Info):
out = "info"
default:
case LogLevel(logger.Debug):
out = "debug"
default:
return nil, fmt.Errorf("invalid log level: %v", d)
}
return json.Marshal(out)
@@ -52,7 +55,7 @@ func (d *LogLevel) UnmarshalJSON(b []byte) error {
*d = LogLevel(logger.Debug)
default:
return fmt.Errorf("invalid log level: %s", in)
return fmt.Errorf("invalid log level: '%s'", in)
}
return nil
+17
View File
@@ -1,6 +1,7 @@
package conf
import (
"encoding/json"
"fmt"
"net"
gourl "net/url"
@@ -341,6 +342,22 @@ func (pconf *PathConf) Equal(other *PathConf) bool {
return reflect.DeepEqual(pconf, other)
}
// Clone clones the configuration.
func (pconf PathConf) Clone() *PathConf {
enc, err := json.Marshal(pconf)
if err != nil {
panic(err)
}
var dest PathConf
err = json.Unmarshal(enc, &dest)
if err != nil {
panic(err)
}
return &dest
}
// HasStaticSource checks whether the path has a static source.
func (pconf PathConf) HasStaticSource() bool {
return strings.HasPrefix(pconf.Source, "rtsp://") ||
+4 -1
View File
@@ -30,8 +30,11 @@ func (d Protocols) MarshalJSON() ([]byte, error) {
case Protocol(gortsplib.TransportUDPMulticast):
v = "multicast"
default:
case Protocol(gortsplib.TransportTCP):
v = "tcp"
default:
return nil, fmt.Errorf("invalid protocol: %v", p)
}
out[i] = v
+5 -1
View File
@@ -26,8 +26,11 @@ func (d SourceProtocol) MarshalJSON() ([]byte, error) {
case gortsplib.TransportUDPMulticast:
out = "multicast"
default:
case gortsplib.TransportTCP:
out = "tcp"
default:
return nil, fmt.Errorf("invalid protocol: %v", d.Transport)
}
}
@@ -55,6 +58,7 @@ func (d *SourceProtocol) UnmarshalJSON(b []byte) error {
d.Transport = &v
case "automatic":
d.Transport = nil
default:
return fmt.Errorf("invalid protocol '%s'", in)
+14 -22
View File
@@ -36,11 +36,6 @@ func fillStruct(dest interface{}, source interface{}) {
}
}
func cloneStruct(dest interface{}, source interface{}) {
enc, _ := json.Marshal(source)
_ = json.Unmarshal(enc, dest)
}
func generateStructWithOptionalFields(model interface{}) interface{} {
var fields []reflect.StructField
@@ -242,9 +237,9 @@ func (a *api) onConfigSet(ctx *gin.Context) {
a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf
cloneStruct(&newConf, a.conf)
fillStruct(&newConf, in)
newConf := a.conf.Clone()
fillStruct(newConf, in)
err = newConf.CheckAndFillMissing()
if err != nil {
@@ -252,11 +247,11 @@ func (a *api) onConfigSet(ctx *gin.Context) {
return
}
a.conf = &newConf
a.conf = newConf
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.apiConfigSet(&newConf)
go a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
@@ -278,8 +273,7 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf
cloneStruct(&newConf, a.conf)
newConf := a.conf.Clone()
if _, ok := newConf.Paths[name]; ok {
ctx.AbortWithStatus(http.StatusBadRequest)
@@ -297,11 +291,11 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
return
}
a.conf = &newConf
a.conf = newConf
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.apiConfigSet(&newConf)
go a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
@@ -323,8 +317,7 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf
cloneStruct(&newConf, a.conf)
newConf := a.conf.Clone()
newConfPath, ok := newConf.Paths[name]
if !ok {
@@ -340,11 +333,11 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
return
}
a.conf = &newConf
a.conf = newConf
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.apiConfigSet(&newConf)
go a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
@@ -360,8 +353,7 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf
cloneStruct(&newConf, a.conf)
newConf := a.conf.Clone()
if _, ok := newConf.Paths[name]; !ok {
ctx.AbortWithStatus(http.StatusBadRequest)
@@ -376,11 +368,11 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
return
}
a.conf = &newConf
a.conf = newConf
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.apiConfigSet(&newConf)
go a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
+2 -3
View File
@@ -11,8 +11,7 @@ import (
)
func pathConfCanBeUpdated(oldPathConf *conf.PathConf, newPathConf *conf.PathConf) bool {
var copy conf.PathConf
cloneStruct(&copy, oldPathConf)
copy := oldPathConf.Clone()
copy.RPICameraBrightness = newPathConf.RPICameraBrightness
copy.RPICameraContrast = newPathConf.RPICameraContrast
@@ -27,7 +26,7 @@ func pathConfCanBeUpdated(oldPathConf *conf.PathConf, newPathConf *conf.PathConf
copy.RPICameraEV = newPathConf.RPICameraEV
copy.RPICameraFPS = newPathConf.RPICameraFPS
return newPathConf.Equal(&copy)
return newPathConf.Equal(copy)
}
type pathManagerHLSServer interface {