Browse Source

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

this allows to detect errors during cloning
pull/1610/head
Alessandro Ros 3 years ago committed by GitHub
parent
commit
bca3013bd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      internal/conf/authmethod.go
  2. 19
      internal/conf/conf.go
  3. 7
      internal/conf/encryption.go
  4. 24
      internal/conf/hlsvariant.go
  5. 5
      internal/conf/logdestination.go
  6. 7
      internal/conf/loglevel.go
  7. 17
      internal/conf/path.go
  8. 5
      internal/conf/protocol.go
  9. 6
      internal/conf/sourceprotocol.go
  10. 36
      internal/core/api.go
  11. 5
      internal/core/path_manager.go

7
internal/conf/authmethod.go

@ -21,8 +21,11 @@ func (d AuthMethods) MarshalJSON() ([]byte, error) { @@ -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 { @@ -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)
}
}

19
internal/conf/conf.go

@ -13,6 +13,7 @@ import ( @@ -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) { @@ -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 { @@ -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")
}

7
internal/conf/encryption.go

@ -26,8 +26,11 @@ func (d Encryption) MarshalJSON() ([]byte, error) { @@ -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 { @@ -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

24
internal/conf/hlsvariant.go

@ -10,26 +10,22 @@ import ( @@ -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 { @@ -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

5
internal/conf/logdestination.go

@ -27,8 +27,11 @@ func (d LogDestinations) MarshalJSON() ([]byte, error) { @@ -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

7
internal/conf/loglevel.go

@ -24,8 +24,11 @@ func (d LogLevel) MarshalJSON() ([]byte, error) { @@ -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 { @@ -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
internal/conf/path.go

@ -1,6 +1,7 @@ @@ -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 { @@ -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://") ||

5
internal/conf/protocol.go

@ -30,8 +30,11 @@ func (d Protocols) MarshalJSON() ([]byte, error) { @@ -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

6
internal/conf/sourceprotocol.go

@ -26,8 +26,11 @@ func (d SourceProtocol) MarshalJSON() ([]byte, error) { @@ -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 { @@ -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)

36
internal/core/api.go

@ -36,11 +36,6 @@ func fillStruct(dest interface{}, source interface{}) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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)
}

5
internal/core/path_manager.go

@ -11,8 +11,7 @@ import ( @@ -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 @@ -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 {

Loading…
Cancel
Save