1
0
mirror of https://github.com/khorevaa/kubodin.git synced 2025-03-03 15:32:43 +02:00
kubodin/cmd/mainCommand.go
2021-03-04 16:38:09 +03:00

263 lines
6.0 KiB
Go

package cmd
import (
"fmt"
"github.com/gofiber/fiber/v2/middleware/pprof"
"github.com/khorevaa/kubodin/api"
db "github.com/khorevaa/kubodin/database"
"github.com/khorevaa/kubodin/models"
"github.com/khorevaa/kubodin/service"
"github.com/khorevaa/kubodin/service/cache"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
"log"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
swagger "github.com/arsmn/fiber-swagger/v2"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
rec "github.com/gofiber/fiber/v2/middleware/recover"
_ "github.com/khorevaa/kubodin/docs" // docs is generated by Swag CLI, you have to import it.
)
type MainCommand struct {
debug bool
port string
appServer string
Version string
BuildBy string
Date string
}
func (c *MainCommand) Run(context *cli.Context) error {
server := fiber.New(fiber.Config{
DisableStartupMessage: true,
})
memoryCache := &cache.Memory{
Expiration: 30 * time.Minute,
}
memoryCache.Connect()
rep := db.NewMemoryRepository()
addr, port := parseAddr(c.appServer)
err := rep.AddAppServer(models.AppServer{
Name: "default",
Addr: addr,
Port: port,
Description: "default app server",
})
if err != nil {
log.Println("ERROR: Connect to ras server")
}
serv, err := service.NewService(memoryCache, rep)
if err != nil {
return err
}
// Middleware
server.Use(rec.New())
server.Use(service.Middleware(serv))
if c.debug {
server.Use(logger.New())
server.Use(pprof.New())
}
api.Routes(server, serv)
server.Use("/docs", swagger.Handler) // default
// Handle not founds
server.Use(api.NotFound)
go func() {
c.startupMessage(c.port, false, c.debug, serv)
log.Fatal(server.Listen(c.port)) // go run main.go -port=:3000
}()
gracefullyShutdownInit(server)
return nil
}
func (c *MainCommand) Flags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Destination: &c.port, Name: "port",
Value: ":3001", Usage: "port to listen on"},
&cli.StringFlag{
Destination: &c.appServer, Name: "server",
Value: "localhost:1545", Usage: "ras client address with port"},
&cli.BoolFlag{
Destination: &c.debug, Name: "debug",
Value: false, Usage: "debug mode"},
}
}
func (c *MainCommand) startupMessage(addr string, tls bool, debug bool, serv service.Service) {
if len(os.Getenv("FIBER_PREFORK_CHILD")) > 0 {
// Для подчиненных процессов мы не выводим сообщение
return
}
var logo string
logo += "%s"
logo += " ┌───────────────────────────────────────────────────┐\n"
logo += " │ %s │\n"
logo += " │ %s │\n"
logo += " │ %s │\n"
logo += " │ %s │\n"
logo += " │ %s │\n"
logo += " │ %s │\n"
logo += " │ │\n"
logo += " │ Built by: %s Built at: %s │\n"
logo += " │ Cache: %s DB: %s │\n"
logo += " └───────────────────────────────────────────────────┘"
logo += "%s"
const (
cBlack = "\u001b[90m"
// cRed = "\u001b[91m"
cCyan = "\u001b[96m"
// cGreen = "\u001b[92m"
cYellow = "\u001b[93m"
// cBlue = "\u001b[94m"
// cMagenta = "\u001b[95m"
// cWhite = "\u001b[97m"
cReset = "\u001b[0m"
)
value := func(s string, width int) string {
pad := width - len(s)
str := ""
for i := 0; i < pad; i++ {
str += "."
}
if s == "Disabled" {
str += " " + s
} else {
str += fmt.Sprintf(" %s%s%s", cYellow, s, cBlack)
}
return str
}
center := func(s string, width int) string {
pad := strconv.Itoa((width - len(s)) / 2)
str := fmt.Sprintf("%"+pad+"s", " ")
str += s
str += fmt.Sprintf("%"+pad+"s", " ")
if len(str) < width {
str += " "
}
return str
}
centerValue := func(s string, width int) string {
pad := strconv.Itoa((width - len(s)) / 2)
str := fmt.Sprintf("%"+pad+"s", " ")
str += fmt.Sprintf("%s%s%s", cCyan, s, cBlack)
str += fmt.Sprintf("%"+pad+"s", " ")
if len(str)-10 < width {
str += " "
}
return str
}
host, port := parseAddr(addr)
if host == "" || host == "0.0.0.0" {
host = "127.0.0.1"
}
addr = "http://" + host + ":" + port
if tls {
addr = "https://" + host + ":" + port
}
t, _ := time.Parse(time.RFC3339, c.Date)
cacheInfo := "redis"
switch serv.GetCache().(type) {
case *cache.Memory:
cacheInfo = "in memory"
}
dbInfo := "pudge"
pprofInfo := ""
if debug {
pprofInfo = " Pprof: " + addr + "/debug/pprof"
}
switch serv.Repository().(type) {
case *db.InMemory:
dbInfo = "in memory"
}
mainLogo := fmt.Sprintf(logo,
cBlack,
centerValue(" KUBODIN "+c.Version, 49),
center("Remote Administration", 49),
center("for 1S.Enterprise Application Servers", 49),
centerValue(" API: "+addr+"/api/v1", 49),
centerValue(" Docs: "+addr+"/docs", 49),
centerValue(pprofInfo, 49),
value(c.BuildBy, 13), value(t.Format("2006-01-02"), 13),
value(cacheInfo, 16), value(dbInfo, 19),
cReset,
)
out := colorable.NewColorableStdout()
if os.Getenv("TERM") == "dumb" ||
(!isatty.IsTerminal(os.Stdout.Fd()) &&
!isatty.IsCygwinTerminal(os.Stdout.Fd())) {
out = colorable.NewNonColorable(os.Stdout)
}
fmt.Fprintln(out, mainLogo)
}
func parseAddr(raw string) (host, port string) {
if i := strings.LastIndex(raw, ":"); i != -1 {
return raw[:i], raw[i+1:]
}
return raw, ""
}
func gracefullyShutdownInit(app *fiber.App) {
// Wait for interrupt signal to gracefully shutdown the server with
// setup signal catching
quit := make(chan os.Signal, 1)
// catch all signals since not explicitly listing
signal.Notify(quit, syscall.SIGQUIT, os.Interrupt, os.Kill)
q := <-quit
if q != nil {
println(fmt.Sprintf("RECEIVED SIGNAL: %s", q))
}
println("Shutdown Server ...")
if err := app.Shutdown(); err != nil {
log.Println("Server Shutdown:", err)
}
time.Sleep(2 * time.Second)
_ = cli.Exit("Shutdown complete", 0)
}