func (a *API) Patch(ctx context.Context, req *http.Request) api.Response {
	defer req.Body.Close()
	d, err := api.GetDaemon(ctx)
	if err != nil {
		return api.InternalError(err)
	}
	var info ServerUpdate
	if err := json.Read(req.Body, &info); err != nil {
		return api.BadRequest(err)
	}
	if info.Config == nil {
		return api.EmptySyncResponse()
	}
	render, err := readConfig(d.Cluster(), d.Node(), d.ClusterConfigSchema(), d.NodeConfigSchema())
	if err != nil {
		return api.SmartError(err)
	}
	if err := etag.Check(req, render); err != nil {
		return api.PreconditionFailed(err)
	}
	return update(d, info, true)
}
Patch defines a service for calling "PATCH" method and returns a response.
package root
import (
	"context"
	"net/http"
	"os"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/spoke-d/thermionic/internal/cert"
	"github.com/spoke-d/thermionic/internal/cluster"
	clusterconfig "github.com/spoke-d/thermionic/internal/cluster/config"
	"github.com/spoke-d/thermionic/internal/config"
	"github.com/spoke-d/thermionic/internal/db"
	"github.com/spoke-d/thermionic/internal/etag"
	"github.com/spoke-d/thermionic/internal/json"
	"github.com/spoke-d/thermionic/internal/net"
	"github.com/spoke-d/thermionic/internal/node"
	"github.com/spoke-d/thermionic/pkg/api"
)
type API struct {
	api.DefaultService
	nodeConfigSchema config.Schema
	logger           log.Logger
}
func NewAPI(nodeConfigSchema config.Schema, options ...Option) *API {
	opts := newOptions()
	for _, option := range options {
		option(opts)
	}
	return &API{
		nodeConfigSchema: nodeConfigSchema,
		logger:           opts.logger,
	}
}
func (a *API) Name() string {
	return ""
}
func (a *API) Get(ctx context.Context, req *http.Request) api.Response {
	defer req.Body.Close()
	d, err := api.GetDaemon(ctx)
	if err != nil {
		return api.InternalError(err)
	}
	var trusted bool
	nonce := req.FormValue("nonce")
	if d.Nonce() == nonce {
		trusted = true
	}
	address, err := node.HTTPSAddress(d.Node(), a.nodeConfigSchema)
	if err != nil {
		return api.InternalError(err)
	}
	addresses, err := net.ListenAddresses(address)
	if err != nil {
		return api.InternalError(err)
	}
	clustered, err := cluster.Enabled(d.Node())
	if err != nil {
		return api.SmartError(err)
	}
	var serverName string
	if clustered {
		if err := d.Cluster().Transaction(func(tx *db.ClusterTx) error {
			var err error
			serverName, err = tx.NodeName()
			return err
		}); err != nil {
			return api.SmartError(err)
		}
	} else {
		if serverName, err = os.Hostname(); err != nil {
			return api.SmartError(err)
		}
	}
	var certificateFingerprint string
	certificate := string(d.Endpoints().NetworkPublicKey())
	if certificate != "" {
		if certificateFingerprint, err = cert.FingerprintStr(certificate); err != nil {
			return api.InternalError(err)
		}
	}
	config, err := readConfig(d.Cluster(), d.Node(), d.ClusterConfigSchema(), d.NodeConfigSchema())
	if err != nil {
		return api.InternalError(err)
	}
	server := Server{
		Environment: Environment{
			Addresses:              addresses,
			Certificate:            certificate,
			CertificateFingerprint: certificateFingerprint,
			Server:                 "therm",
			ServerPid:              os.Getpid(),
			ServerVersion:          d.Version(),
			ServerClustered:        clustered,
			ServerName:             serverName,
		},
		Config: config,
	}
	if trusted {
		key := string(d.Endpoints().NetworkPrivateKey())
		server.Environment.CertificateKey = key
	}
	return api.SyncResponseETag(true, server, server.Config)
}
func (a *API) Put(ctx context.Context, req *http.Request) api.Response {
	defer req.Body.Close()
	d, err := api.GetDaemon(ctx)
	if err != nil {
		return api.InternalError(err)
	}
	var info ServerUpdate
	if err := json.Read(req.Body, &info); err != nil {
		return api.BadRequest(err)
	}
	if api.IsClusterNotification(req) {
		level.Debug(a.logger).Log("msg", "Handling config change notification")
		changed := make(map[string]string)
		for key, value := range info.Config {
			if v, ok := value.(string); ok {
				changed[key] = v
			}
		}
		var config *clusterconfig.Config
		if err := d.Cluster().Transaction(func(tx *db.ClusterTx) error {
			var err error
			config, err = clusterconfig.Load(tx, d.ClusterConfigSchema())
			return err
		}); err != nil {
			return api.SmartError(err)
		}
		if err := updateClusterTriggers(d, changed, config); err != nil {
			return api.SmartError(err)
		}
		return api.EmptySyncResponse()
	}
	render, err := readConfig(d.Cluster(), d.Node(), d.ClusterConfigSchema(), d.NodeConfigSchema())
	if err != nil {
		return api.SmartError(err)
	}
	if err := etag.Check(req, render); err != nil {
		return api.PreconditionFailed(err)
	}
	return update(d, info, false)
}