func setupLogging(cfg *Config, interceptor signal.Interceptor) error {
	if cfg.DebugLevel == "" {
		cfg.DebugLevel = defaultLogLevel
	}
	SetupLoggers(logWriter, interceptor)
	logFile := filepath.Join(apertureDataDir, defaultLogFilename)
	if cfg.BaseDir != "" {
		logFile = filepath.Join(cfg.BaseDir, defaultLogFilename)
	}
	err := logWriter.InitLogRotator(
		logFile, defaultMaxLogFileSize, defaultMaxLogFiles,
	)
	if err != nil {
		return err
	}
	return build.ParseAndSetDebugLevels(cfg.DebugLevel, logWriter)
}
setupLogging parses the debug level and initializes the log file rotator.
package aperture
import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"
	flags "github.com/jessevdk/go-flags"
	"github.com/lightninglabs/aperture/auth"
	"github.com/lightninglabs/aperture/mint"
	"github.com/lightninglabs/aperture/proxy"
	"github.com/lightningnetwork/lnd"
	"github.com/lightningnetwork/lnd/build"
	"github.com/lightningnetwork/lnd/cert"
	"github.com/lightningnetwork/lnd/lnrpc"
	"github.com/lightningnetwork/lnd/signal"
	"github.com/lightningnetwork/lnd/tor"
	clientv3 "go.etcd.io/etcd/client/v3"
	"golang.org/x/crypto/acme/autocert"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"
	"gopkg.in/yaml.v2"
)
const (
	topLevelKey = "lsat/proxy"
	etcdKeyDelimeter = "/"
	selfSignedCertOrganization = "aperture autogenerated cert"
	selfSignedCertValidity = time.Hour * 24 * 820
	selfSignedCertExpiryMargin = selfSignedCertValidity / 2
)
var (
	http2TLSCipherSuites = []uint16{
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
		tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
	}
)
func Main() {
	err := run()
	flagErr, isFlagErr := errors.Unwrap(err).(*flags.Error)
	isHelpErr := isFlagErr && flagErr.Type == flags.ErrHelp
	if err == nil || isHelpErr {
		os.Exit(0)
	}
	_, _ = fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}
func run() error {
	interceptor, err := signal.Intercept()
	if err != nil {
		return err
	}
	cfg, err := getConfig()
	if err != nil {
		return fmt.Errorf("unable to parse config file: %w", err)
	}
	err = setupLogging(cfg, interceptor)
	if err != nil {
		return fmt.Errorf("unable to set up logging: %v", err)
	}
	errChan := make(chan error)
	a := NewAperture(cfg)
	if err := a.Start(errChan); err != nil {
		return fmt.Errorf("unable to start aperture: %v", err)
	}
	select {
	case <-interceptor.ShutdownChannel():
		log.Infof("Received interrupt signal, shutting down aperture.")
	case err := <-errChan:
		log.Errorf("Error while running aperture: %v", err)
	}
	return a.Stop()
}
type Aperture struct {
	cfg *Config
	etcdClient    *clientv3.Client
	challenger    *LndChallenger
	httpsServer   *http.Server
	torHTTPServer *http.Server
	proxy         *proxy.Proxy
	wg   sync.WaitGroup
	quit chan struct{}
}
func NewAperture(cfg *Config) *Aperture {
	return &Aperture{
		cfg:  cfg,
		quit: make(chan struct{}),
	}
}
func (a *Aperture) Start(errChan chan error) error {
	var err error
	a.etcdClient, err = clientv3.New(clientv3.Config{
		Endpoints:   []string{a.cfg.Etcd.Host},
		DialTimeout: 5 * time.Second,
		Username:    a.cfg.Etcd.User,
		Password:    a.cfg.Etcd.Password,
	})
	if err != nil {
		return fmt.Errorf("unable to connect to etcd: %v", err)
	}
	genInvoiceReq := func(price int64) (*lnrpc.Invoice, error) {
		return &lnrpc.Invoice{
			Memo:  "LSAT",
			Value: price,
		}, nil
	}
	if !a.cfg.Authenticator.Disable {
		a.challenger, err = NewLndChallenger(
			a.cfg.Authenticator, genInvoiceReq, errChan,
		)
		if err != nil {
			return err
		}
		err = a.challenger.Start()
		if err != nil {
			return err
		}
	}
	a.proxy, err = createProxy(a.cfg, a.challenger, a.etcdClient)
	if err != nil {
		return err
	}
	handler := http.HandlerFunc(a.proxy.ServeHTTP)
	a.httpsServer = &http.Server{
		Addr:    a.cfg.ListenAddr,
		Handler: handler,
	}
	var serveFn func() error
	if a.cfg.Insecure {
		serveFn = a.httpsServer.ListenAndServe
		a.httpsServer.Handler = h2c.NewHandler(handler, &http2.Server{})
	} else {
		a.httpsServer.TLSConfig, err = getTLSConfig(
			a.cfg.ServerName, a.cfg.BaseDir, a.cfg.AutoCert,
		)
		if err != nil {
			return err
		}
		serveFn = func() error {
			return a.httpsServer.ListenAndServeTLS("", "")
		}
	}
	log.Infof("Starting the server, listening on %s.", a.cfg.ListenAddr)
	a.wg.Add(1)
	go func() {
		defer a.wg.Done()
		select {
		case errChan <- serveFn():
		case <-a.quit:
		}
	}()
	if a.cfg.Tor != nil && (a.cfg.Tor.V2 || a.cfg.Tor.V3) {
		torController, err := initTorListener(a.cfg, a.etcdClient)
		if err != nil {
			return err
		}
		defer func() {
			_ = torController.Stop()
		}()
		a.torHTTPServer = &http.Server{
			Addr:    fmt.Sprintf("localhost:%d", a.cfg.Tor.ListenPort),
			Handler: h2c.NewHandler(handler, &http2.Server{}),
		}
		a.wg.Add(1)
		go func() {
			defer a.wg.Done()
			select {
			case errChan <- a.torHTTPServer.ListenAndServe():
			case <-a.quit:
			}
		}()
	}
	return nil
}
func (a *Aperture) UpdateServices(services []*proxy.Service) error {
	return a.proxy.UpdateServices(services)
}
func (a *Aperture) Stop() error {
	var returnErr error
	if a.challenger != nil {
		a.challenger.Stop()
	}
	cleanup(a.etcdClient, a.httpsServer, a.proxy)
	if a.torHTTPServer != nil {
		returnErr = a.torHTTPServer.Close()
	}
	close(a.quit)
	a.wg.Wait()
	return returnErr
}
func fileExists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}
func getConfig() (*Config, error) {
	cfg := &Config{}
	if _, err := flags.Parse(cfg); err != nil {
		return nil, err
	}
	var mustExist bool
	configFile := filepath.Join(apertureDataDir, defaultConfigFilename)
	if cfg.BaseDir != "" {
		configFile = filepath.Join(cfg.BaseDir, defaultConfigFilename)
	}
	if cfg.ConfigFile != "" {
		configFile = lnd.CleanAndExpandPath(cfg.ConfigFile)
		mustExist = true
	}
	b, err := ioutil.ReadFile(configFile)
	switch {
	case err == nil:
		err = yaml.Unmarshal(b, cfg)
		if err != nil {
			return nil, err
		}
	case !os.IsNotExist(err):
		return nil, err
	case mustExist && os.IsNotExist(err):
		return nil, fmt.Errorf("config file: %v must exist: %w",
			configFile, err)
	}
	if _, err := flags.Parse(cfg); err != nil {
		return nil, err
	}
	cfg.BaseDir = lnd.CleanAndExpandPath(cfg.BaseDir)
	cfg.Authenticator.TLSPath = lnd.CleanAndExpandPath(
		cfg.Authenticator.TLSPath,
	)
	cfg.Authenticator.MacDir = lnd.CleanAndExpandPath(
		cfg.Authenticator.MacDir,
	)
	if err := cfg.validate(); err != nil {
		return nil, err
	}
	return cfg, nil
}