circuitbreaker/run.go
2023-01-09 18:43:59 +01:00

179 lines
3.7 KiB
Go

package main
import (
"context"
"embed"
"io/fs"
"net"
"net/http"
"os"
"path/filepath"
"time"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/lightningequipment/circuitbreaker/circuitbreakerrpc"
"github.com/urfave/cli"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/reflection"
)
//go:embed webui-build
var content embed.FS
func run(c *cli.Context) error {
ctx := context.Background()
confDir := c.String("configdir")
err := os.MkdirAll(confDir, os.ModePerm)
if err != nil {
return err
}
dbPath := filepath.Join(confDir, dbFn)
log.Infow("Opening database", "path", dbPath)
// Open database.
db, err := NewDb(dbPath)
if err != nil {
return err
}
stub := c.Bool(stubFlag.Name)
var client lndclient
if stub {
stubClient := newStubClient()
client = stubClient
} else {
// First, we'll parse the args from the command.
tlsCertPath, macPath, err := extractPathArgs(c)
if err != nil {
return err
}
lndCfg := LndConfig{
RpcServer: c.GlobalString("rpcserver"),
TlsCertPath: tlsCertPath,
MacPath: macPath,
Log: log,
}
lndClient, err := NewLndClient(&lndCfg)
if err != nil {
return err
}
defer lndClient.Close()
client = lndClient
}
limits, err := db.GetLimits(ctx)
if err != nil {
return err
}
p := NewProcess(client, log, limits)
grpcServer := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer()),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer()),
)
reflection.Register(grpcServer)
server := NewServer(log, p, client, db)
circuitbreakerrpc.RegisterServiceServer(
grpcServer, server,
)
listenAddress := c.String("listen")
grpcInternalListener, err := net.Listen("tcp", listenAddress)
if err != nil {
return err
}
// Create a client connection to the gRPC server we just started
// This is where the gRPC-Gateway proxies the requests
conn, err := grpc.DialContext(
ctx,
listenAddress,
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
return err
}
// Create http server.
gwmux := runtime.NewServeMux()
err = circuitbreakerrpc.RegisterServiceHandler(ctx, gwmux, conn)
if err != nil {
return err
}
serverRoot, err := fs.Sub(content, "webui-build")
if err != nil {
log.Fatal(err)
}
fs := http.FileServer(http.FS(serverRoot))
mux := http.NewServeMux()
mux.Handle("/api/", http.StripPrefix("/api", gwmux))
mux.HandleFunc("/", fs.ServeHTTP)
httpListen := c.String(httpListenFlag.Name)
gwServer := &http.Server{
Addr: httpListen,
Handler: mux,
ReadHeaderTimeout: time.Second * 10,
}
group, ctx := errgroup.WithContext(ctx)
// Run circuitbreaker core.
group.Go(func() error {
return p.Run(ctx)
})
// Run grpc server.
group.Go(func() error {
log.Infow("Grpc server starting", "listenAddress", listenAddress)
err := grpcServer.Serve(grpcInternalListener)
if err != nil && err != grpc.ErrServerStopped {
log.Errorw("grpc server error", "err", err)
}
return err
})
// Run http server.
group.Go(func() error {
log.Infow("HTTP server starting", "listenAddress", httpListen)
return gwServer.ListenAndServe()
})
// Stop servers when context is cancelled.
group.Go(func() error {
<-ctx.Done()
// Stop http server.
log.Infof("Stopping http server")
err := gwServer.Shutdown(context.Background()) //nolint:contextcheck
if err != nil {
log.Errorw("Error shutting down http server", "err", err)
}
// Stop grpc server.
log.Infof("Stopping grpc server")
grpcServer.Stop()
return nil
})
return group.Wait()
}