general: add Clone() method to Conf and PathConf (#1633)
this allows to detect errors during cloning
This commit is contained in:
@@ -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
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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://") ||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func pathConfCanBeUpdated(oldPathConf *conf.PathConf, newPathConf *conf.PathConf) bool {
|
||||
var copy conf.PathConf
|
||||
cloneStruct(©, 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(©)
|
||||
return newPathConf.Equal(copy)
|
||||
}
|
||||
|
||||
type pathManagerHLSServer interface {
|
||||
|
||||
Reference in New Issue
Block a user