From dbfc8ae3620333a1b3f9fe6a61896f509b74b934 Mon Sep 17 00:00:00 2001
From: Ainar Garipov <A.Garipov@AdGuard.COM>
Date: Fri, 9 Sep 2022 14:25:48 +0300
Subject: [PATCH] all: mv v1 to next; imp tests, docs

---
 Makefile                                      |  4 +-
 internal/aghchan/aghchan.go                   | 24 ++++--
 internal/{v1 => next}/agh/agh.go              |  0
 internal/{v1 => next}/cmd/cmd.go              |  2 +-
 internal/{v1 => next}/cmd/signal.go           |  2 +-
 internal/{v1 => next}/dnssvc/dnssvc.go        |  5 +-
 internal/{v1 => next}/dnssvc/dnssvc_test.go   |  2 +-
 internal/{v1 => next}/websvc/dns.go           |  2 +-
 internal/{v1 => next}/websvc/http.go          |  2 +
 internal/{v1 => next}/websvc/json.go          |  0
 .../{v1 => next}/websvc/json_internal_test.go |  0
 internal/{v1 => next}/websvc/middleware.go    |  0
 internal/{v1 => next}/websvc/path.go          |  0
 internal/{v1 => next}/websvc/settings.go      |  3 +-
 internal/next/websvc/settings_test.go         | 75 +++++++++++++++++++
 internal/{v1 => next}/websvc/system.go        |  0
 internal/{v1 => next}/websvc/system_test.go   |  2 +-
 internal/{v1 => next}/websvc/waitlistener.go  |  0
 .../websvc/waitlistener_internal_test.go      |  0
 internal/{v1 => next}/websvc/websvc.go        |  7 +-
 .../websvc/websvc_internal_test.go            |  0
 internal/{v1 => next}/websvc/websvc_test.go   |  4 +-
 internal/v1/websvc/settings_test.go           | 61 ---------------
 main.go                                       |  4 +-
 main_v1.go => main_next.go                    |  6 +-
 scripts/make/go-lint.sh                       |  4 +-
 26 files changed, 122 insertions(+), 87 deletions(-)
 rename internal/{v1 => next}/agh/agh.go (100%)
 rename internal/{v1 => next}/cmd/cmd.go (96%)
 rename internal/{v1 => next}/cmd/signal.go (96%)
 rename internal/{v1 => next}/dnssvc/dnssvc.go (97%)
 rename internal/{v1 => next}/dnssvc/dnssvc_test.go (97%)
 rename internal/{v1 => next}/websvc/dns.go (97%)
 rename internal/{v1 => next}/websvc/http.go (96%)
 rename internal/{v1 => next}/websvc/json.go (100%)
 rename internal/{v1 => next}/websvc/json_internal_test.go (100%)
 rename internal/{v1 => next}/websvc/middleware.go (100%)
 rename internal/{v1 => next}/websvc/path.go (100%)
 rename internal/{v1 => next}/websvc/settings.go (96%)
 create mode 100644 internal/next/websvc/settings_test.go
 rename internal/{v1 => next}/websvc/system.go (100%)
 rename internal/{v1 => next}/websvc/system_test.go (93%)
 rename internal/{v1 => next}/websvc/waitlistener.go (100%)
 rename internal/{v1 => next}/websvc/waitlistener_internal_test.go (100%)
 rename internal/{v1 => next}/websvc/websvc.go (97%)
 rename internal/{v1 => next}/websvc/websvc_internal_test.go (100%)
 rename internal/{v1 => next}/websvc/websvc_test.go (97%)
 delete mode 100644 internal/v1/websvc/settings_test.go
 rename main_v1.go => main_next.go (79%)

diff --git a/Makefile b/Makefile
index b4823bb7..cca89017 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ YARN_INSTALL_FLAGS = $(YARN_FLAGS) --network-timeout 120000 --silent\
 	--ignore-engines --ignore-optional --ignore-platform\
 	--ignore-scripts
 
-V1API = 0
+NEXTAPI = 0
 
 # Macros for the build-release target.  If FRONTEND_PREBUILT is 0, the
 # default, the macro $(BUILD_RELEASE_DEPS_$(FRONTEND_PREBUILT)) expands
@@ -63,7 +63,7 @@ ENV = env\
 	PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\
 	RACE='$(RACE)'\
 	SIGN='$(SIGN)'\
-	V1API='$(V1API)'\
+	NEXTAPI='$(NEXTAPI)'\
 	VERBOSE='$(VERBOSE)'\
 	VERSION='$(VERSION)'\
 
diff --git a/internal/aghchan/aghchan.go b/internal/aghchan/aghchan.go
index 5e504e45..1da1790a 100644
--- a/internal/aghchan/aghchan.go
+++ b/internal/aghchan/aghchan.go
@@ -6,14 +6,28 @@ import (
 	"time"
 )
 
-// MustReceive panics if it cannot receive a value form c before timeout runs
-// out.
-func MustReceive[T any](c <-chan T, timeout time.Duration) (v T, ok bool) {
+// Receive returns an error if it cannot receive a value form c before timeout
+// runs out.
+func Receive[T any](c <-chan T, timeout time.Duration) (v T, ok bool, err error) {
+	var zero T
 	timeoutCh := time.After(timeout)
 	select {
 	case <-timeoutCh:
-		panic(fmt.Errorf("did not receive after %s", timeout))
+		// TODO(a.garipov): Consider implementing [errors.Aser] for
+		// os.ErrTimeout.
+		return zero, false, fmt.Errorf("did not receive after %s", timeout)
 	case v, ok = <-c:
-		return v, ok
+		return v, ok, nil
 	}
 }
+
+// MustReceive panics if it cannot receive a value form c before timeout runs
+// out.
+func MustReceive[T any](c <-chan T, timeout time.Duration) (v T, ok bool) {
+	v, ok, err := Receive(c, timeout)
+	if err != nil {
+		panic(err)
+	}
+
+	return v, ok
+}
diff --git a/internal/v1/agh/agh.go b/internal/next/agh/agh.go
similarity index 100%
rename from internal/v1/agh/agh.go
rename to internal/next/agh/agh.go
diff --git a/internal/v1/cmd/cmd.go b/internal/next/cmd/cmd.go
similarity index 96%
rename from internal/v1/cmd/cmd.go
rename to internal/next/cmd/cmd.go
index d6f35251..5b329abf 100644
--- a/internal/v1/cmd/cmd.go
+++ b/internal/next/cmd/cmd.go
@@ -11,7 +11,7 @@ import (
 	"net/netip"
 	"time"
 
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/websvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
 	"github.com/AdguardTeam/golibs/log"
 )
 
diff --git a/internal/v1/cmd/signal.go b/internal/next/cmd/signal.go
similarity index 96%
rename from internal/v1/cmd/signal.go
rename to internal/next/cmd/signal.go
index b66075f6..122f3f2c 100644
--- a/internal/v1/cmd/signal.go
+++ b/internal/next/cmd/signal.go
@@ -4,7 +4,7 @@ import (
 	"os"
 
 	"github.com/AdguardTeam/AdGuardHome/internal/aghos"
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/agh"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
 	"github.com/AdguardTeam/golibs/log"
 )
 
diff --git a/internal/v1/dnssvc/dnssvc.go b/internal/next/dnssvc/dnssvc.go
similarity index 97%
rename from internal/v1/dnssvc/dnssvc.go
rename to internal/next/dnssvc/dnssvc.go
index 31860fa0..b62d3e51 100644
--- a/internal/v1/dnssvc/dnssvc.go
+++ b/internal/next/dnssvc/dnssvc.go
@@ -12,7 +12,7 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/agh"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
 	// TODO(a.garipov): Add a “dnsproxy proxy” package to shield us from changes
 	// and replacement of module dnsproxy.
 	"github.com/AdguardTeam/dnsproxy/proxy"
@@ -51,6 +51,9 @@ type Service struct {
 	// running is an atomic boolean value.  Keep it the first value in the
 	// struct to ensure atomic alignment.  0 means that the service is not
 	// running, 1 means that it is running.
+	//
+	// TODO(a.garipov): Use [atomic.Bool] in Go 1.19 or get rid of it
+	// completely.
 	running uint64
 
 	proxy      *proxy.Proxy
diff --git a/internal/v1/dnssvc/dnssvc_test.go b/internal/next/dnssvc/dnssvc_test.go
similarity index 97%
rename from internal/v1/dnssvc/dnssvc_test.go
rename to internal/next/dnssvc/dnssvc_test.go
index 5bc3b562..8205897c 100644
--- a/internal/v1/dnssvc/dnssvc_test.go
+++ b/internal/next/dnssvc/dnssvc_test.go
@@ -7,7 +7,7 @@ import (
 	"time"
 
 	"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/dnssvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
 	"github.com/AdguardTeam/dnsproxy/upstream"
 	"github.com/miekg/dns"
 	"github.com/stretchr/testify/assert"
diff --git a/internal/v1/websvc/dns.go b/internal/next/websvc/dns.go
similarity index 97%
rename from internal/v1/websvc/dns.go
rename to internal/next/websvc/dns.go
index b536aedd..4b86dfc1 100644
--- a/internal/v1/websvc/dns.go
+++ b/internal/next/websvc/dns.go
@@ -6,7 +6,7 @@ import (
 	"net/http"
 	"net/netip"
 
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/dnssvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
 	"github.com/AdguardTeam/golibs/timeutil"
 )
 
diff --git a/internal/v1/websvc/http.go b/internal/next/websvc/http.go
similarity index 96%
rename from internal/v1/websvc/http.go
rename to internal/next/websvc/http.go
index 6a2b206d..f7145bdd 100644
--- a/internal/v1/websvc/http.go
+++ b/internal/next/websvc/http.go
@@ -36,6 +36,7 @@ type HTTPAPIHTTPSettings struct {
 	Addresses       []netip.AddrPort  `json:"addresses"`
 	SecureAddresses []netip.AddrPort  `json:"secure_addresses"`
 	Timeout         timeutil.Duration `json:"timeout"`
+	ForceHTTPS      bool              `json:"force_https"`
 }
 
 // handlePatchSettingsHTTP is the handler for the PATCH /api/v1/settings/http
@@ -65,6 +66,7 @@ func (svc *Service) handlePatchSettingsHTTP(w http.ResponseWriter, r *http.Reque
 		Addresses:       newConf.Addresses,
 		SecureAddresses: newConf.SecureAddresses,
 		Timeout:         timeutil.Duration{Duration: newConf.Timeout},
+		ForceHTTPS:      newConf.ForceHTTPS,
 	})
 
 	cancelUpd := func() {}
diff --git a/internal/v1/websvc/json.go b/internal/next/websvc/json.go
similarity index 100%
rename from internal/v1/websvc/json.go
rename to internal/next/websvc/json.go
diff --git a/internal/v1/websvc/json_internal_test.go b/internal/next/websvc/json_internal_test.go
similarity index 100%
rename from internal/v1/websvc/json_internal_test.go
rename to internal/next/websvc/json_internal_test.go
diff --git a/internal/v1/websvc/middleware.go b/internal/next/websvc/middleware.go
similarity index 100%
rename from internal/v1/websvc/middleware.go
rename to internal/next/websvc/middleware.go
diff --git a/internal/v1/websvc/path.go b/internal/next/websvc/path.go
similarity index 100%
rename from internal/v1/websvc/path.go
rename to internal/next/websvc/path.go
diff --git a/internal/v1/websvc/settings.go b/internal/next/websvc/settings.go
similarity index 96%
rename from internal/v1/websvc/settings.go
rename to internal/next/websvc/settings.go
index 1d076263..9052e471 100644
--- a/internal/v1/websvc/settings.go
+++ b/internal/next/websvc/settings.go
@@ -8,8 +8,6 @@ import (
 
 // All Settings Handlers
 
-// TODO(a.garipov): !! Write tests!
-
 // RespGetV1SettingsAll describes the response of the GET /api/v1/settings/all
 // HTTP API.
 type RespGetV1SettingsAll struct {
@@ -40,6 +38,7 @@ func (svc *Service) handleGetSettingsAll(w http.ResponseWriter, r *http.Request)
 			Addresses:       httpConf.Addresses,
 			SecureAddresses: httpConf.SecureAddresses,
 			Timeout:         timeutil.Duration{Duration: httpConf.Timeout},
+			ForceHTTPS:      httpConf.ForceHTTPS,
 		},
 	})
 }
diff --git a/internal/next/websvc/settings_test.go b/internal/next/websvc/settings_test.go
new file mode 100644
index 00000000..a1652230
--- /dev/null
+++ b/internal/next/websvc/settings_test.go
@@ -0,0 +1,75 @@
+package websvc_test
+
+import (
+	"crypto/tls"
+	"encoding/json"
+	"net/http"
+	"net/netip"
+	"net/url"
+	"testing"
+	"time"
+
+	"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
+	"github.com/AdguardTeam/golibs/timeutil"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestService_HandleGetSettingsAll(t *testing.T) {
+	// TODO(a.garipov): Add all currently supported parameters.
+
+	wantDNS := &websvc.HTTPAPIDNSSettings{
+		Addresses:        []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53")},
+		BootstrapServers: []string{"94.140.14.140", "94.140.14.141"},
+		UpstreamServers:  []string{"94.140.14.14", "1.1.1.1"},
+		UpstreamTimeout:  timeutil.Duration{Duration: 1 * time.Second},
+	}
+
+	wantWeb := &websvc.HTTPAPIHTTPSettings{
+		Addresses:       []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:80")},
+		SecureAddresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:443")},
+		Timeout:         timeutil.Duration{Duration: 5 * time.Second},
+		ForceHTTPS:      true,
+	}
+
+	confMgr := newConfigManager()
+	confMgr.onDNS = func() (c *dnssvc.Service) {
+		c, err := dnssvc.New(&dnssvc.Config{
+			Addresses:        wantDNS.Addresses,
+			UpstreamServers:  wantDNS.UpstreamServers,
+			BootstrapServers: wantDNS.BootstrapServers,
+			UpstreamTimeout:  wantDNS.UpstreamTimeout.Duration,
+		})
+		require.NoError(t, err)
+
+		return c
+	}
+
+	confMgr.onWeb = func() (c *websvc.Service) {
+		return websvc.New(&websvc.Config{
+			TLS: &tls.Config{
+				Certificates: []tls.Certificate{{}},
+			},
+			Addresses:       wantWeb.Addresses,
+			SecureAddresses: wantWeb.SecureAddresses,
+			Timeout:         wantWeb.Timeout.Duration,
+			ForceHTTPS:      true,
+		})
+	}
+
+	_, addr := newTestServer(t, confMgr)
+	u := &url.URL{
+		Scheme: "http",
+		Host:   addr.String(),
+		Path:   websvc.PathV1SettingsAll,
+	}
+
+	body := httpGet(t, u, http.StatusOK)
+	resp := &websvc.RespGetV1SettingsAll{}
+	err := json.Unmarshal(body, resp)
+	require.NoError(t, err)
+
+	assert.Equal(t, wantDNS, resp.DNS)
+	assert.Equal(t, wantWeb, resp.HTTP)
+}
diff --git a/internal/v1/websvc/system.go b/internal/next/websvc/system.go
similarity index 100%
rename from internal/v1/websvc/system.go
rename to internal/next/websvc/system.go
diff --git a/internal/v1/websvc/system_test.go b/internal/next/websvc/system_test.go
similarity index 93%
rename from internal/v1/websvc/system_test.go
rename to internal/next/websvc/system_test.go
index ad81637f..acbdcba2 100644
--- a/internal/v1/websvc/system_test.go
+++ b/internal/next/websvc/system_test.go
@@ -8,7 +8,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/websvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
diff --git a/internal/v1/websvc/waitlistener.go b/internal/next/websvc/waitlistener.go
similarity index 100%
rename from internal/v1/websvc/waitlistener.go
rename to internal/next/websvc/waitlistener.go
diff --git a/internal/v1/websvc/waitlistener_internal_test.go b/internal/next/websvc/waitlistener_internal_test.go
similarity index 100%
rename from internal/v1/websvc/waitlistener_internal_test.go
rename to internal/next/websvc/waitlistener_internal_test.go
diff --git a/internal/v1/websvc/websvc.go b/internal/next/websvc/websvc.go
similarity index 97%
rename from internal/v1/websvc/websvc.go
rename to internal/next/websvc/websvc.go
index 6bbdf7ec..5247dbf1 100644
--- a/internal/v1/websvc/websvc.go
+++ b/internal/next/websvc/websvc.go
@@ -1,5 +1,8 @@
 // Package websvc contains the AdGuard Home HTTP API service.
 //
+// NOTE: Packages other than cmd must not import this package, as it imports
+// most other packages.
+//
 // TODO(a.garipov): Add tests.
 package websvc
 
@@ -14,8 +17,8 @@ import (
 	"sync"
 	"time"
 
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/agh"
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/dnssvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
 	"github.com/AdguardTeam/golibs/errors"
 	"github.com/AdguardTeam/golibs/log"
 	httptreemux "github.com/dimfeld/httptreemux/v5"
diff --git a/internal/v1/websvc/websvc_internal_test.go b/internal/next/websvc/websvc_internal_test.go
similarity index 100%
rename from internal/v1/websvc/websvc_internal_test.go
rename to internal/next/websvc/websvc_internal_test.go
diff --git a/internal/v1/websvc/websvc_test.go b/internal/next/websvc/websvc_test.go
similarity index 97%
rename from internal/v1/websvc/websvc_test.go
rename to internal/next/websvc/websvc_test.go
index affb9ad5..476fbc01 100644
--- a/internal/v1/websvc/websvc_test.go
+++ b/internal/next/websvc/websvc_test.go
@@ -10,8 +10,8 @@ import (
 	"time"
 
 	"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/dnssvc"
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/websvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
 	"github.com/AdguardTeam/golibs/testutil"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
diff --git a/internal/v1/websvc/settings_test.go b/internal/v1/websvc/settings_test.go
deleted file mode 100644
index a92b5b32..00000000
--- a/internal/v1/websvc/settings_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package websvc_test
-
-import (
-	"encoding/json"
-	"net/http"
-	"net/netip"
-	"net/url"
-	"testing"
-	"time"
-
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/dnssvc"
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/websvc"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestService_HandleGetSettingsAll(t *testing.T) {
-	// TODO(a.garipov): Add all currently supported parameters.
-
-	dnsAddrs := []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53")}
-	upsSrvs := []string{"94.140.14.14", "1.1.1.1"}
-
-	webAddrs := []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:80")}
-	const webTimeout = 5 * time.Second
-
-	confMgr := newConfigManager()
-	confMgr.onDNS = func() (c *dnssvc.Service) {
-		c, err := dnssvc.New(&dnssvc.Config{
-			Addresses:       dnsAddrs,
-			UpstreamServers: upsSrvs,
-		})
-		require.NoError(t, err)
-
-		return c
-	}
-
-	confMgr.onWeb = func() (c *websvc.Service) {
-		return websvc.New(&websvc.Config{
-			Addresses: webAddrs,
-			Timeout:   webTimeout,
-		})
-	}
-
-	_, addr := newTestServer(t, confMgr)
-	u := &url.URL{
-		Scheme: "http",
-		Host:   addr.String(),
-		Path:   websvc.PathV1SettingsAll,
-	}
-
-	body := httpGet(t, u, http.StatusOK)
-	resp := &websvc.RespGetV1SettingsAll{}
-	err := json.Unmarshal(body, resp)
-	require.NoError(t, err)
-
-	assert.Equal(t, dnsAddrs, resp.DNS.Addresses)
-	assert.Equal(t, upsSrvs, resp.DNS.UpstreamServers)
-
-	assert.Equal(t, webAddrs, resp.HTTP.Addresses)
-	assert.Equal(t, webTimeout, resp.HTTP.Timeout.Duration)
-}
diff --git a/main.go b/main.go
index 03ad2f03..615a8a86 100644
--- a/main.go
+++ b/main.go
@@ -1,5 +1,5 @@
-//go:build !v1
-// +build !v1
+//go:build !next
+// +build !next
 
 package main
 
diff --git a/main_v1.go b/main_next.go
similarity index 79%
rename from main_v1.go
rename to main_next.go
index 6b5f3dea..0006e87b 100644
--- a/main_v1.go
+++ b/main_next.go
@@ -1,12 +1,12 @@
-//go:build v1
-// +build v1
+//go:build next
+// +build next
 
 package main
 
 import (
 	"embed"
 
-	"github.com/AdguardTeam/AdGuardHome/internal/v1/cmd"
+	"github.com/AdguardTeam/AdGuardHome/internal/next/cmd"
 )
 
 // Embed the prebuilt client here since we strive to keep .go files inside the
diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh
index 2cdcc90d..e04af725 100644
--- a/scripts/make/go-lint.sh
+++ b/scripts/make/go-lint.sh
@@ -136,11 +136,11 @@ underscores() {
 			-e '_freebsd.go'\
 			-e '_linux.go'\
 			-e '_little.go'\
+			-e '_next.go'\
 			-e '_openbsd.go'\
 			-e '_others.go'\
 			-e '_test.go'\
 			-e '_unix.go'\
-			-e '_v1.go'\
 			-e '_windows.go' \
 			-v\
 			| sed -e 's/./\t\0/'
@@ -229,7 +229,7 @@ gocyclo --over 13 ./internal/filtering/
 # Apply stricter standards to new or somewhat refactored code.
 gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\
 	./internal/aghtest/ ./internal/dnsforward/ ./internal/stats/\
-	./internal/tools/ ./internal/updater/ ./internal/v1/ ./internal/version/\
+	./internal/tools/ ./internal/updater/ ./internal/next/ ./internal/version/\
 	./main.go
 
 ineffassign ./...