all: sync with master
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
type ServiceWithConfig[ConfigType any] interface {
|
||||
service.Interface
|
||||
|
||||
// Config returns a deep clone of the configuration of the service.
|
||||
Config() (c ConfigType)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# AdGuard Home v0.108.0 Changelog DRAFT
|
||||
|
||||
This changelog should be merged into the main one once the next API matures
|
||||
enough.
|
||||
This changelog should be merged into the main one once the next API matures enough.
|
||||
|
||||
## [v0.108.0] - TODO
|
||||
|
||||
### Added
|
||||
|
||||
- The ability to change the port of the pprof debug API.
|
||||
|
||||
- The ability to log to stderr using `--logFile=stderr`.
|
||||
|
||||
- The new `--web-addr` flag to set the Web UI address in a `host:port` form.
|
||||
|
||||
- `SIGHUP` now reloads all configuration from the configuration file ([#5676]).
|
||||
|
||||
### Changed
|
||||
@@ -20,20 +22,21 @@ enough.
|
||||
|
||||
#### Other changes
|
||||
|
||||
- `-h` is now an alias for `--help` instead of the removed `--host`, see below.
|
||||
Use `--web-addr=host:port` to set an address on which to serve the Web UI.
|
||||
- `-h` is now an alias for `--help` instead of the removed `--host`, see below. Use `--web-addr=host:port` to set an address on which to serve the Web UI.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `--check-config` breaking the configuration file ([#4067]).
|
||||
|
||||
- Inconsistent application of `--work-dir/-w` ([#2598], [#2902]).
|
||||
|
||||
- The order of `-v/--verbose` and `--version` being significant ([#2893]).
|
||||
|
||||
### Removed
|
||||
|
||||
- The deprecated `--no-mem-optimization` and `--no-etc-hosts` flags.
|
||||
- `--host` and `-p/--port` flags. Use `--web-addr=host:port` to set an address
|
||||
on which to serve the Web UI. `-h` is now an alias for `--help`, see above.
|
||||
|
||||
- `--host` and `-p/--port` flags. Use `--web-addr=host:port` to set an address on which to serve the Web UI. `-h` is now an alias for `--help`, see above.
|
||||
|
||||
[#2598]: https://github.com/AdguardTeam/AdGuardHome/issues/2598
|
||||
[#2893]: https://github.com/AdguardTeam/AdGuardHome/issues/2893
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package configmgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
"github.com/AdguardTeam/golibs/validate"
|
||||
)
|
||||
|
||||
// config is the top-level on-disk configuration structure.
|
||||
@@ -19,10 +19,10 @@ type config struct {
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validator = (*config)(nil)
|
||||
var _ validate.Interface = (*config)(nil)
|
||||
|
||||
// validate implements the [validator] interface for *config.
|
||||
func (c *config) validate() (err error) {
|
||||
// Validate implements the [validate.Interface] interface for *config.
|
||||
func (c *config) Validate() (err error) {
|
||||
if c == nil {
|
||||
return errors.ErrNoValue
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (c *config) validate() (err error) {
|
||||
// TODO(a.garipov): Add more validations.
|
||||
|
||||
// Keep this in the same order as the fields in the config.
|
||||
validators := container.KeyValues[string, validator]{{
|
||||
validators := container.KeyValues[string, validate.Interface]{{
|
||||
Key: "dns",
|
||||
Value: c.DNS,
|
||||
}, {
|
||||
@@ -41,14 +41,12 @@ func (c *config) validate() (err error) {
|
||||
Value: c.Log,
|
||||
}}
|
||||
|
||||
var errs []error
|
||||
for _, kv := range validators {
|
||||
err = kv.Value.validate()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", kv.Key, err)
|
||||
}
|
||||
errs = validate.Append(errs, kv.Key, kv.Value)
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// dnsConfig is the on-disk DNS configuration.
|
||||
@@ -63,21 +61,19 @@ type dnsConfig struct {
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validator = (*dnsConfig)(nil)
|
||||
var _ validate.Interface = (*dnsConfig)(nil)
|
||||
|
||||
// validate implements the [validator] interface for *dnsConfig.
|
||||
// Validate implements the [validate.Interface] interface for *dnsConfig.
|
||||
//
|
||||
// TODO(a.garipov): Add more validations.
|
||||
func (c *dnsConfig) validate() (err error) {
|
||||
// TODO(a.garipov): Add more validations.
|
||||
switch {
|
||||
case c == nil:
|
||||
func (c *dnsConfig) Validate() (err error) {
|
||||
if c == nil {
|
||||
return errors.ErrNoValue
|
||||
case c.UpstreamTimeout.Duration <= 0:
|
||||
return newErrNotPositive("upstream_timeout", c.UpstreamTimeout)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Add more validations.
|
||||
|
||||
return validate.Positive("upstream_timeout", c.UpstreamTimeout)
|
||||
}
|
||||
|
||||
// httpConfig is the on-disk web API configuration.
|
||||
@@ -92,20 +88,23 @@ type httpConfig struct {
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validator = (*httpConfig)(nil)
|
||||
var _ validate.Interface = (*httpConfig)(nil)
|
||||
|
||||
// validate implements the [validator] interface for *httpConfig.
|
||||
// Validate implements the [validate.Interface] interface for *httpConfig.
|
||||
//
|
||||
// TODO(a.garipov): Add more validations.
|
||||
func (c *httpConfig) validate() (err error) {
|
||||
switch {
|
||||
case c == nil:
|
||||
func (c *httpConfig) Validate() (err error) {
|
||||
if c == nil {
|
||||
return errors.ErrNoValue
|
||||
case c.Timeout.Duration <= 0:
|
||||
return newErrNotPositive("timeout", c.Timeout)
|
||||
default:
|
||||
return c.Pprof.validate()
|
||||
}
|
||||
|
||||
errs := []error{
|
||||
validate.Positive("timeout", c.Timeout),
|
||||
}
|
||||
|
||||
errs = validate.Append(errs, "pprof", c.Pprof)
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// httpPprofConfig is the on-disk pprof configuration.
|
||||
@@ -115,10 +114,10 @@ type httpPprofConfig struct {
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validator = (*httpPprofConfig)(nil)
|
||||
var _ validate.Interface = (*httpPprofConfig)(nil)
|
||||
|
||||
// validate implements the [validator] interface for *httpPprofConfig.
|
||||
func (c *httpPprofConfig) validate() (err error) {
|
||||
// Validate implements the [validate.Interface] interface for *httpPprofConfig.
|
||||
func (c *httpPprofConfig) Validate() (err error) {
|
||||
if c == nil {
|
||||
return errors.ErrNoValue
|
||||
}
|
||||
@@ -128,17 +127,17 @@ func (c *httpPprofConfig) validate() (err error) {
|
||||
|
||||
// logConfig is the on-disk web API configuration.
|
||||
type logConfig struct {
|
||||
// TODO(a.garipov): Use.
|
||||
// TODO(a.garipov): Use.
|
||||
Verbose bool `yaml:"verbose"`
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validator = (*logConfig)(nil)
|
||||
var _ validate.Interface = (*logConfig)(nil)
|
||||
|
||||
// validate implements the [validator] interface for *logConfig.
|
||||
// Validate implements the [validate.Interface] interface for *logConfig.
|
||||
//
|
||||
// TODO(a.garipov): Add more validations.
|
||||
func (c *logConfig) validate() (err error) {
|
||||
func (c *logConfig) Validate() (err error) {
|
||||
if c == nil {
|
||||
return errors.ErrNoValue
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func Validate(fileName string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
err = conf.validate()
|
||||
err = conf.Validate()
|
||||
if err != nil {
|
||||
return fmt.Errorf("validating config: %w", err)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ func New(ctx context.Context, c *Config) (m *Manager, err error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = conf.validate()
|
||||
err = conf.Validate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("validating config: %w", err)
|
||||
}
|
||||
@@ -162,7 +162,7 @@ func (m *Manager) assemble(
|
||||
BootstrapServers: conf.DNS.BootstrapDNS,
|
||||
UpstreamServers: conf.DNS.UpstreamDNS,
|
||||
DNS64Prefixes: conf.DNS.DNS64Prefixes,
|
||||
UpstreamTimeout: conf.DNS.UpstreamTimeout.Duration,
|
||||
UpstreamTimeout: time.Duration(conf.DNS.UpstreamTimeout),
|
||||
BootstrapPreferIPv6: conf.DNS.BootstrapPreferIPv6,
|
||||
UseDNS64: conf.DNS.UseDNS64,
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func (m *Manager) assemble(
|
||||
Addresses: conf.HTTP.Addresses,
|
||||
SecureAddresses: conf.HTTP.SecureAddresses,
|
||||
OverrideAddress: webAddr,
|
||||
Timeout: conf.HTTP.Timeout.Duration,
|
||||
Timeout: time.Duration(conf.HTTP.Timeout),
|
||||
ForceHTTPS: conf.HTTP.ForceHTTPS,
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ func (m *Manager) updateCurrentDNS(c *dnssvc.Config) {
|
||||
m.current.DNS.BootstrapDNS = slices.Clone(c.BootstrapServers)
|
||||
m.current.DNS.UpstreamDNS = slices.Clone(c.UpstreamServers)
|
||||
m.current.DNS.DNS64Prefixes = slices.Clone(c.DNS64Prefixes)
|
||||
m.current.DNS.UpstreamTimeout = timeutil.Duration{Duration: c.UpstreamTimeout}
|
||||
m.current.DNS.UpstreamTimeout = timeutil.Duration(c.UpstreamTimeout)
|
||||
m.current.DNS.BootstrapPreferIPv6 = c.BootstrapPreferIPv6
|
||||
m.current.DNS.UseDNS64 = c.UseDNS64
|
||||
}
|
||||
@@ -318,6 +318,6 @@ func (m *Manager) updateCurrentWeb(c *websvc.Config) {
|
||||
|
||||
m.current.HTTP.Addresses = slices.Clone(c.Addresses)
|
||||
m.current.HTTP.SecureAddresses = slices.Clone(c.SecureAddresses)
|
||||
m.current.HTTP.Timeout = timeutil.Duration{Duration: c.Timeout}
|
||||
m.current.HTTP.Timeout = timeutil.Duration(c.Timeout)
|
||||
m.current.HTTP.ForceHTTPS = c.ForceHTTPS
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package configmgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// validator is the interface for configuration entities that can validate
|
||||
// themselves.
|
||||
type validator interface {
|
||||
// validate returns an error if the entity isn't valid.
|
||||
validate() (err error)
|
||||
}
|
||||
|
||||
// numberOrDuration is the constraint for integer types along with
|
||||
// timeutil.Duration.
|
||||
type numberOrDuration interface {
|
||||
constraints.Integer | timeutil.Duration
|
||||
}
|
||||
|
||||
// newErrNotPositive returns an error about the value that must be positive but
|
||||
// isn't. prop is the name of the property to mention in the error message.
|
||||
//
|
||||
// TODO(a.garipov): Consider moving such helpers to golibs and use in AdGuardDNS
|
||||
// as well.
|
||||
func newErrNotPositive[T numberOrDuration](prop string, v T) (err error) {
|
||||
return fmt.Errorf("%s: %w, got %v", prop, errors.ErrNotPositive, v)
|
||||
}
|
||||
43
internal/next/jsonpatch/jsonpatch.go
Normal file
43
internal/next/jsonpatch/jsonpatch.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Package jsonpatch contains utilities for JSON Merge Patch APIs.
|
||||
//
|
||||
// See https://www.rfc-editor.org/rfc/rfc7396.
|
||||
package jsonpatch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
)
|
||||
|
||||
// NonRemovable is a type that prevents JSON null from being used to try and
|
||||
// remove a value.
|
||||
type NonRemovable[T any] struct {
|
||||
Value T
|
||||
IsSet bool
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ json.Unmarshaler = (*NonRemovable[struct{}])(nil)
|
||||
|
||||
// UnmarshalJSON implements the [json.Unmarshaler] interface for *NonRemovable.
|
||||
func (v *NonRemovable[T]) UnmarshalJSON(b []byte) (err error) {
|
||||
if v == nil {
|
||||
return errors.Error("jsonpatch.NonRemovable is nil")
|
||||
}
|
||||
|
||||
if bytes.Equal(b, []byte("null")) {
|
||||
return errors.Error("property cannot be removed")
|
||||
}
|
||||
|
||||
v.IsSet = true
|
||||
|
||||
return json.Unmarshal(b, &v.Value)
|
||||
}
|
||||
|
||||
// Set sets ptr if the value has been provided.
|
||||
func (v NonRemovable[T]) Set(ptr *T) {
|
||||
if v.IsSet {
|
||||
*ptr = v.Value
|
||||
}
|
||||
}
|
||||
29
internal/next/jsonpatch/jsonpatch_test.go
Normal file
29
internal/next/jsonpatch/jsonpatch_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package jsonpatch_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/jsonpatch"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNonRemovable(t *testing.T) {
|
||||
type T struct {
|
||||
Value jsonpatch.NonRemovable[int] `json:"value"`
|
||||
}
|
||||
|
||||
var v T
|
||||
|
||||
err := json.Unmarshal([]byte(`{"value":null}`), &v)
|
||||
testutil.AssertErrorMsg(t, "property cannot be removed", err)
|
||||
|
||||
err = json.Unmarshal([]byte(`{"value":42}`), &v)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var got int
|
||||
v.Value.Set(&got)
|
||||
|
||||
assert.Equal(t, 42, got)
|
||||
}
|
||||
@@ -5,10 +5,9 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/jsonpatch"
|
||||
)
|
||||
|
||||
// ReqPatchSettingsDNS describes the request to the PATCH /api/v1/settings/dns
|
||||
@@ -16,13 +15,15 @@ import (
|
||||
type ReqPatchSettingsDNS struct {
|
||||
// TODO(a.garipov): Add more as we go.
|
||||
|
||||
Addresses []netip.AddrPort `json:"addresses"`
|
||||
BootstrapServers []string `json:"bootstrap_servers"`
|
||||
UpstreamServers []string `json:"upstream_servers"`
|
||||
DNS64Prefixes []netip.Prefix `json:"dns64_prefixes"`
|
||||
UpstreamTimeout aghhttp.JSONDuration `json:"upstream_timeout"`
|
||||
BootstrapPreferIPv6 bool `json:"bootstrap_prefer_ipv6"`
|
||||
UseDNS64 bool `json:"use_dns64"`
|
||||
Addresses jsonpatch.NonRemovable[[]netip.AddrPort] `json:"addresses"`
|
||||
BootstrapServers jsonpatch.NonRemovable[[]string] `json:"bootstrap_servers"`
|
||||
UpstreamServers jsonpatch.NonRemovable[[]string] `json:"upstream_servers"`
|
||||
DNS64Prefixes jsonpatch.NonRemovable[[]netip.Prefix] `json:"dns64_prefixes"`
|
||||
|
||||
UpstreamTimeout jsonpatch.NonRemovable[aghhttp.JSONDuration] `json:"upstream_timeout"`
|
||||
|
||||
BootstrapPreferIPv6 jsonpatch.NonRemovable[bool] `json:"bootstrap_prefer_ipv6"`
|
||||
UseDNS64 jsonpatch.NonRemovable[bool] `json:"use_dns64"`
|
||||
}
|
||||
|
||||
// HTTPAPIDNSSettings are the DNS settings as used by the HTTP API. See the
|
||||
@@ -42,13 +43,7 @@ type HTTPAPIDNSSettings struct {
|
||||
// handlePatchSettingsDNS is the handler for the PATCH /api/v1/settings/dns HTTP
|
||||
// API.
|
||||
func (svc *Service) handlePatchSettingsDNS(w http.ResponseWriter, r *http.Request) {
|
||||
req := &ReqPatchSettingsDNS{
|
||||
Addresses: []netip.AddrPort{},
|
||||
BootstrapServers: []string{},
|
||||
UpstreamServers: []string{},
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Validate nulls and proper JSON patch.
|
||||
req := &ReqPatchSettingsDNS{}
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
@@ -57,16 +52,20 @@ func (svc *Service) handlePatchSettingsDNS(w http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
|
||||
newConf := &dnssvc.Config{
|
||||
Logger: svc.logger,
|
||||
Addresses: req.Addresses,
|
||||
BootstrapServers: req.BootstrapServers,
|
||||
UpstreamServers: req.UpstreamServers,
|
||||
DNS64Prefixes: req.DNS64Prefixes,
|
||||
UpstreamTimeout: time.Duration(req.UpstreamTimeout),
|
||||
BootstrapPreferIPv6: req.BootstrapPreferIPv6,
|
||||
UseDNS64: req.UseDNS64,
|
||||
}
|
||||
dnsSvc := svc.confMgr.DNS()
|
||||
newConf := dnsSvc.Config()
|
||||
|
||||
// TODO(a.garipov): Add more as we go.
|
||||
|
||||
req.Addresses.Set(&newConf.Addresses)
|
||||
req.BootstrapServers.Set(&newConf.BootstrapServers)
|
||||
req.UpstreamServers.Set(&newConf.UpstreamServers)
|
||||
req.DNS64Prefixes.Set(&newConf.DNS64Prefixes)
|
||||
|
||||
req.UpstreamTimeout.Set((*aghhttp.JSONDuration)(&newConf.UpstreamTimeout))
|
||||
|
||||
req.BootstrapPreferIPv6.Set(&newConf.BootstrapPreferIPv6)
|
||||
req.UseDNS64.Set(&newConf.UseDNS64)
|
||||
|
||||
ctx := r.Context()
|
||||
err = svc.confMgr.UpdateDNS(ctx, newConf)
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestService_HandlePatchSettingsDNS(t *testing.T) {
|
||||
return nil
|
||||
},
|
||||
OnShutdown: func(_ context.Context) (err error) { panic("not implemented") },
|
||||
OnConfig: func() (c *dnssvc.Config) { panic("not implemented") },
|
||||
OnConfig: func() (c *dnssvc.Config) { return &dnssvc.Config{} },
|
||||
}
|
||||
}
|
||||
confMgr.onUpdateDNS = func(ctx context.Context, c *dnssvc.Config) (err error) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/jsonpatch"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
)
|
||||
|
||||
@@ -20,9 +21,12 @@ type ReqPatchSettingsHTTP struct {
|
||||
//
|
||||
// TODO(a.garipov): Add wait time.
|
||||
|
||||
Addresses []netip.AddrPort `json:"addresses"`
|
||||
SecureAddresses []netip.AddrPort `json:"secure_addresses"`
|
||||
Timeout aghhttp.JSONDuration `json:"timeout"`
|
||||
Addresses jsonpatch.NonRemovable[[]netip.AddrPort] `json:"addresses"`
|
||||
SecureAddresses jsonpatch.NonRemovable[[]netip.AddrPort] `json:"secure_addresses"`
|
||||
|
||||
Timeout jsonpatch.NonRemovable[aghhttp.JSONDuration] `json:"timeout"`
|
||||
|
||||
ForceHTTPS jsonpatch.NonRemovable[bool] `json:"force_https"`
|
||||
}
|
||||
|
||||
// HTTPAPIHTTPSettings are the HTTP settings as used by the HTTP API. See the
|
||||
@@ -41,8 +45,6 @@ type HTTPAPIHTTPSettings struct {
|
||||
func (svc *Service) handlePatchSettingsHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
req := &ReqPatchSettingsHTTP{}
|
||||
|
||||
// TODO(a.garipov): Validate nulls and proper JSON patch.
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
aghhttp.WriteJSONResponseError(w, r, fmt.Errorf("decoding: %w", err))
|
||||
@@ -50,20 +52,14 @@ func (svc *Service) handlePatchSettingsHTTP(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
newConf := &Config{
|
||||
Logger: svc.logger,
|
||||
Pprof: &PprofConfig{
|
||||
Port: svc.pprofPort,
|
||||
Enabled: svc.pprof != nil,
|
||||
},
|
||||
ConfigManager: svc.confMgr,
|
||||
Frontend: svc.frontend,
|
||||
TLS: svc.tls,
|
||||
Addresses: req.Addresses,
|
||||
SecureAddresses: req.SecureAddresses,
|
||||
Timeout: time.Duration(req.Timeout),
|
||||
ForceHTTPS: svc.forceHTTPS,
|
||||
}
|
||||
newConf := svc.Config()
|
||||
|
||||
// TODO(a.garipov): Add more as we go.
|
||||
|
||||
req.Addresses.Set(&newConf.Addresses)
|
||||
req.SecureAddresses.Set(&newConf.SecureAddresses)
|
||||
req.Timeout.Set((*aghhttp.JSONDuration)(&newConf.Timeout))
|
||||
req.ForceHTTPS.Set(&newConf.ForceHTTPS)
|
||||
|
||||
aghhttp.WriteJSONResponseOK(w, r, &HTTPAPIHTTPSettings{
|
||||
Addresses: newConf.Addresses,
|
||||
|
||||
Reference in New Issue
Block a user