Loops and HTTP control server rework (#308)
- CRUD REST HTTP server - `/v1` HTTP server prefix - Retrocompatible with older routes (redirects to v1 or handles the requests directly) - DNS, Updater and Openvpn refactored to have a REST-like state with new methods to change their states synchronously - Openvpn, Unbound and Updater status, see #287
This commit is contained in:
76
internal/server/dns.go
Normal file
76
internal/server/dns.go
Normal file
@@ -0,0 +1,76 @@
|
||||
//nolint:dupl
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/dns"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
func newDNSHandler(looper dns.Looper, logger logging.Logger) http.Handler {
|
||||
return &dnsHandler{
|
||||
looper: looper,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
type dnsHandler struct {
|
||||
looper dns.Looper
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (h *dnsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
r.RequestURI = strings.TrimPrefix(r.RequestURI, "/dns")
|
||||
switch r.RequestURI {
|
||||
case "/status": //nolint:goconst
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
h.getStatus(w)
|
||||
case http.MethodPut:
|
||||
h.setStatus(w, r)
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *dnsHandler) getStatus(w http.ResponseWriter) {
|
||||
status := h.looper.GetStatus()
|
||||
encoder := json.NewEncoder(w)
|
||||
data := statusWrapper{Status: string(status)}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *dnsHandler) setStatus(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var data statusWrapper
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
status, err := data.getStatus()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
outcome, err := h.looper.SetStatus(status)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(outcomeWrapper{Outcome: outcome}); err != nil {
|
||||
h.logger.Warn(err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/dns"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
@@ -17,54 +17,33 @@ func newHandler(logger logging.Logger, logging bool,
|
||||
unboundLooper dns.Looper,
|
||||
updaterLooper updater.Looper,
|
||||
) http.Handler {
|
||||
return &handler{
|
||||
logger: logger,
|
||||
logging: logging,
|
||||
buildInfo: buildInfo,
|
||||
openvpnLooper: openvpnLooper,
|
||||
unboundLooper: unboundLooper,
|
||||
updaterLooper: updaterLooper,
|
||||
}
|
||||
handler := &handler{}
|
||||
|
||||
openvpn := newOpenvpnHandler(openvpnLooper, logger)
|
||||
dns := newDNSHandler(unboundLooper, logger)
|
||||
updater := newUpdaterHandler(updaterLooper, logger)
|
||||
|
||||
handler.v0 = newHandlerV0(logger, openvpnLooper, unboundLooper, updaterLooper)
|
||||
handler.v1 = newHandlerV1(logger, buildInfo, openvpn, dns, updater)
|
||||
|
||||
handlerWithLog := withLogMiddleware(handler, logger, logging)
|
||||
handler.setLogEnabled = handlerWithLog.setEnabled
|
||||
|
||||
return handlerWithLog
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
logger logging.Logger
|
||||
logging bool
|
||||
buildInfo models.BuildInformation
|
||||
openvpnLooper openvpn.Looper
|
||||
unboundLooper dns.Looper
|
||||
updaterLooper updater.Looper
|
||||
v0 http.Handler
|
||||
v1 http.Handler
|
||||
setLogEnabled func(enabled bool)
|
||||
}
|
||||
|
||||
func (h *handler) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
if h.logging {
|
||||
h.logger.Info("HTTP %s %s", request.Method, request.RequestURI)
|
||||
}
|
||||
switch request.Method {
|
||||
case http.MethodGet:
|
||||
switch request.RequestURI {
|
||||
case "/version":
|
||||
h.getVersion(responseWriter)
|
||||
responseWriter.WriteHeader(http.StatusOK)
|
||||
case "/openvpn/actions/restart":
|
||||
h.openvpnLooper.Restart()
|
||||
responseWriter.WriteHeader(http.StatusOK)
|
||||
case "/unbound/actions/restart":
|
||||
h.unboundLooper.Restart()
|
||||
responseWriter.WriteHeader(http.StatusOK)
|
||||
case "/openvpn/portforwarded":
|
||||
h.getPortForwarded(responseWriter)
|
||||
case "/openvpn/settings":
|
||||
h.getOpenvpnSettings(responseWriter)
|
||||
case "/updater/restart":
|
||||
h.updaterLooper.Restart()
|
||||
responseWriter.WriteHeader(http.StatusOK)
|
||||
default:
|
||||
errString := fmt.Sprintf("Nothing here for %s %s", request.Method, request.RequestURI)
|
||||
http.Error(responseWriter, errString, http.StatusBadRequest)
|
||||
}
|
||||
default:
|
||||
errString := fmt.Sprintf("Nothing here for %s %s", request.Method, request.RequestURI)
|
||||
http.Error(responseWriter, errString, http.StatusBadRequest)
|
||||
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
r.RequestURI = strings.TrimSuffix(r.RequestURI, "/")
|
||||
if !strings.HasPrefix(r.RequestURI, "/v1/") && r.RequestURI != "/v1" {
|
||||
h.v0.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
r.RequestURI = strings.TrimPrefix(r.RequestURI, "/v1")
|
||||
h.v1.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
69
internal/server/handlerv0.go
Normal file
69
internal/server/handlerv0.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/dns"
|
||||
"github.com/qdm12/gluetun/internal/openvpn"
|
||||
"github.com/qdm12/gluetun/internal/updater"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
func newHandlerV0(logger logging.Logger,
|
||||
openvpn openvpn.Looper, dns dns.Looper, updater updater.Looper) http.Handler {
|
||||
return &handlerV0{
|
||||
logger: logger,
|
||||
openvpn: openvpn,
|
||||
dns: dns,
|
||||
updater: updater,
|
||||
}
|
||||
}
|
||||
|
||||
type handlerV0 struct {
|
||||
logger logging.Logger
|
||||
openvpn openvpn.Looper
|
||||
dns dns.Looper
|
||||
updater updater.Looper
|
||||
}
|
||||
|
||||
func (h *handlerV0) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "unversioned API: only supports GET method", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
switch r.RequestURI {
|
||||
case "/version":
|
||||
http.Redirect(w, r, "/v1/version", http.StatusPermanentRedirect)
|
||||
case "/openvpn/actions/restart":
|
||||
outcome, _ := h.openvpn.SetStatus(constants.Stopped)
|
||||
h.logger.Info("openvpn: %s", outcome)
|
||||
outcome, _ = h.openvpn.SetStatus(constants.Running)
|
||||
h.logger.Info("openvpn: %s", outcome)
|
||||
if _, err := w.Write([]byte("openvpn restarted, please consider using the /v1/ API in the future.")); err != nil {
|
||||
h.logger.Warn(err)
|
||||
}
|
||||
case "/unbound/actions/restart":
|
||||
outcome, _ := h.dns.SetStatus(constants.Stopped)
|
||||
h.logger.Info("dns: %s", outcome)
|
||||
outcome, _ = h.dns.SetStatus(constants.Running)
|
||||
h.logger.Info("dns: %s", outcome)
|
||||
if _, err := w.Write([]byte("dns restarted, please consider using the /v1/ API in the future.")); err != nil {
|
||||
h.logger.Warn(err)
|
||||
}
|
||||
case "/openvpn/portforwarded":
|
||||
http.Redirect(w, r, "/v1/openvpn/portforwarded", http.StatusPermanentRedirect)
|
||||
case "/openvpn/settings":
|
||||
http.Redirect(w, r, "/v1/openvpn/settings", http.StatusPermanentRedirect)
|
||||
case "/updater/restart":
|
||||
outcome, _ := h.updater.SetStatus(constants.Stopped)
|
||||
h.logger.Info("updater: %s", outcome)
|
||||
outcome, _ = h.updater.SetStatus(constants.Running)
|
||||
h.logger.Info("updater: %s", outcome)
|
||||
if _, err := w.Write([]byte("updater restarted, please consider using the /v1/ API in the future.")); err != nil {
|
||||
h.logger.Warn(err)
|
||||
}
|
||||
default:
|
||||
http.Error(w, "unversioned API: requested URI not found", http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
58
internal/server/handlerv1.go
Normal file
58
internal/server/handlerv1.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
func newHandlerV1(logger logging.Logger, buildInfo models.BuildInformation,
|
||||
openvpn, dns, updater http.Handler) http.Handler {
|
||||
return &handlerV1{
|
||||
logger: logger,
|
||||
buildInfo: buildInfo,
|
||||
openvpn: openvpn,
|
||||
dns: dns,
|
||||
updater: updater,
|
||||
}
|
||||
}
|
||||
|
||||
type handlerV1 struct {
|
||||
logger logging.Logger
|
||||
buildInfo models.BuildInformation
|
||||
openvpn http.Handler
|
||||
dns http.Handler
|
||||
updater http.Handler
|
||||
}
|
||||
|
||||
func (h *handlerV1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.RequestURI == "/version" && r.Method == http.MethodGet:
|
||||
h.getVersion(w)
|
||||
case strings.HasPrefix(r.RequestURI, "/openvpn"):
|
||||
h.openvpn.ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.RequestURI, "/dns"):
|
||||
h.dns.ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.RequestURI, "/updater"):
|
||||
h.updater.ServeHTTP(w, r)
|
||||
default:
|
||||
errString := fmt.Sprintf("%s %s not found", r.Method, r.RequestURI)
|
||||
http.Error(w, errString, http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handlerV1) getVersion(w http.ResponseWriter) {
|
||||
data, err := json.Marshal(h.buildInfo)
|
||||
if err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := w.Write(data); err != nil {
|
||||
h.logger.Warn(err)
|
||||
}
|
||||
}
|
||||
75
internal/server/log.go
Normal file
75
internal/server/log.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
func withLogMiddleware(childHandler http.Handler, logger logging.Logger, enabled bool) *logMiddleware {
|
||||
return &logMiddleware{
|
||||
childHandler: childHandler,
|
||||
logger: logger,
|
||||
timeNow: time.Now,
|
||||
enabled: enabled,
|
||||
}
|
||||
}
|
||||
|
||||
type logMiddleware struct {
|
||||
childHandler http.Handler
|
||||
logger logging.Logger
|
||||
timeNow func() time.Time
|
||||
enabled bool
|
||||
enabledMu sync.RWMutex
|
||||
}
|
||||
|
||||
func (m *logMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if !m.isEnabled() {
|
||||
m.childHandler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
tStart := m.timeNow()
|
||||
statefulWriter := &statefulResponseWriter{httpWriter: w}
|
||||
m.childHandler.ServeHTTP(statefulWriter, r)
|
||||
duration := m.timeNow().Sub(tStart)
|
||||
m.logger.Info("%d %s %s wrote %dB to %s in %s",
|
||||
statefulWriter.statusCode, r.Method, r.RequestURI, statefulWriter.length, r.RemoteAddr, duration)
|
||||
}
|
||||
|
||||
func (m *logMiddleware) setEnabled(enabled bool) {
|
||||
m.enabledMu.Lock()
|
||||
defer m.enabledMu.Unlock()
|
||||
m.enabled = enabled
|
||||
}
|
||||
|
||||
func (m *logMiddleware) isEnabled() (enabled bool) {
|
||||
m.enabledMu.RLock()
|
||||
defer m.enabledMu.RUnlock()
|
||||
return m.enabled
|
||||
}
|
||||
|
||||
type statefulResponseWriter struct {
|
||||
httpWriter http.ResponseWriter
|
||||
statusCode int
|
||||
length int
|
||||
}
|
||||
|
||||
func (w *statefulResponseWriter) Write(b []byte) (n int, err error) {
|
||||
n, err = w.httpWriter.Write(b)
|
||||
if w.statusCode == 0 {
|
||||
w.statusCode = http.StatusOK
|
||||
}
|
||||
w.length += n
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (w *statefulResponseWriter) WriteHeader(statusCode int) {
|
||||
w.statusCode = statusCode
|
||||
w.httpWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
func (w *statefulResponseWriter) Header() http.Header {
|
||||
return w.httpWriter.Header()
|
||||
}
|
||||
@@ -3,34 +3,110 @@ package server
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/openvpn"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
func (h *handler) getPortForwarded(w http.ResponseWriter) {
|
||||
port := h.openvpnLooper.GetPortForwarded()
|
||||
data, err := json.Marshal(struct {
|
||||
Port uint16 `json:"port"`
|
||||
}{port})
|
||||
if err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := w.Write(data); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
func newOpenvpnHandler(looper openvpn.Looper, logger logging.Logger) http.Handler {
|
||||
return &openvpnHandler{
|
||||
looper: looper,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) getOpenvpnSettings(w http.ResponseWriter) {
|
||||
settings := h.openvpnLooper.GetSettings()
|
||||
data, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
type openvpnHandler struct {
|
||||
looper openvpn.Looper
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (h *openvpnHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
r.RequestURI = strings.TrimPrefix(r.RequestURI, "/openvpn")
|
||||
switch r.RequestURI {
|
||||
case "/status":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
h.getStatus(w)
|
||||
case http.MethodPut:
|
||||
h.setStatus(w, r)
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
case "/settings":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
h.getSettings(w)
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
case "/portforwarded":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
h.getPortForwarded(w)
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *openvpnHandler) getStatus(w http.ResponseWriter) {
|
||||
status := h.looper.GetStatus()
|
||||
encoder := json.NewEncoder(w)
|
||||
data := statusWrapper{Status: string(status)}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := w.Write(data); err != nil {
|
||||
}
|
||||
|
||||
func (h *openvpnHandler) setStatus(w http.ResponseWriter, r *http.Request) { //nolint:dupl
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var data statusWrapper
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
status, err := data.getStatus()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
outcome, err := h.looper.SetStatus(status)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(outcomeWrapper{Outcome: outcome}); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *openvpnHandler) getSettings(w http.ResponseWriter) {
|
||||
settings := h.looper.GetSettings()
|
||||
settings.User = "redacted"
|
||||
settings.Password = "redacted"
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(settings); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *openvpnHandler) getPortForwarded(w http.ResponseWriter) {
|
||||
port := h.looper.GetPortForwarded()
|
||||
encoder := json.NewEncoder(w)
|
||||
data := portWrapper{Port: port}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ type server struct {
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func New(address string, logging bool, logger logging.Logger, buildInfo models.BuildInformation,
|
||||
func New(address string, logging bool, logger logging.Logger,
|
||||
buildInfo models.BuildInformation,
|
||||
openvpnLooper openvpn.Looper, unboundLooper dns.Looper, updaterLooper updater.Looper) Server {
|
||||
serverLogger := logger.WithPrefix("http server: ")
|
||||
handler := newHandler(serverLogger, logging, buildInfo, openvpnLooper, unboundLooper, updaterLooper)
|
||||
|
||||
78
internal/server/updater.go
Normal file
78
internal/server/updater.go
Normal file
@@ -0,0 +1,78 @@
|
||||
//nolint:dupl
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/updater"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
func newUpdaterHandler(
|
||||
looper updater.Looper,
|
||||
logger logging.Logger) http.Handler {
|
||||
return &updaterHandler{
|
||||
looper: looper,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
type updaterHandler struct {
|
||||
looper updater.Looper
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (h *updaterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
r.RequestURI = strings.TrimPrefix(r.RequestURI, "/updater")
|
||||
switch r.RequestURI {
|
||||
case "/status":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
h.getStatus(w)
|
||||
case http.MethodPut:
|
||||
h.setStatus(w, r)
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
default:
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *updaterHandler) getStatus(w http.ResponseWriter) {
|
||||
status := h.looper.GetStatus()
|
||||
encoder := json.NewEncoder(w)
|
||||
data := statusWrapper{Status: string(status)}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *updaterHandler) setStatus(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var data statusWrapper
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
status, err := data.getStatus()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
outcome, err := h.looper.SetStatus(status)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(outcomeWrapper{Outcome: outcome}); err != nil {
|
||||
h.logger.Warn(err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (h *handler) getVersion(w http.ResponseWriter) {
|
||||
data, err := json.Marshal(h.buildInfo)
|
||||
if err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := w.Write(data); err != nil {
|
||||
h.logger.Warn(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
32
internal/server/wrappers.go
Normal file
32
internal/server/wrappers.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
type statusWrapper struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (sw *statusWrapper) getStatus() (status models.LoopStatus, err error) {
|
||||
status = models.LoopStatus(sw.Status)
|
||||
switch status {
|
||||
case constants.Stopped, constants.Running:
|
||||
return status, nil
|
||||
default:
|
||||
return "", fmt.Errorf(
|
||||
"invalid status %q: possible values are: %s, %s",
|
||||
sw.Status, constants.Stopped, constants.Running)
|
||||
}
|
||||
}
|
||||
|
||||
type portWrapper struct {
|
||||
Port uint16 `json:"port"`
|
||||
}
|
||||
|
||||
type outcomeWrapper struct {
|
||||
Outcome string `json:"outcome"`
|
||||
}
|
||||
Reference in New Issue
Block a user