github.com/infraboard/keyauth@v0.8.1/cmd/start.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"os/signal"
     9  	"strings"
    10  	"syscall"
    11  
    12  	"github.com/infraboard/mcube/app"
    13  	"github.com/infraboard/mcube/cache"
    14  	"github.com/infraboard/mcube/cache/memory"
    15  	"github.com/infraboard/mcube/cache/redis"
    16  	"github.com/infraboard/mcube/logger"
    17  	"github.com/infraboard/mcube/logger/zap"
    18  	"github.com/spf13/cobra"
    19  
    20  	"github.com/infraboard/keyauth/conf"
    21  	"github.com/infraboard/keyauth/protocol"
    22  
    23  	// 加载所有服务
    24  	_ "github.com/infraboard/keyauth/apps/all"
    25  )
    26  
    27  var (
    28  	// pusher service config option
    29  	confType string
    30  	confFile string
    31  )
    32  
    33  // startCmd represents the start command
    34  var serviceCmd = &cobra.Command{
    35  	Use:   "start",
    36  	Short: "启动权限中心服务",
    37  	Long:  `启动权限中心服务`,
    38  	RunE: func(cmd *cobra.Command, args []string) error {
    39  		// 初始化全局变量
    40  		if err := loadGlobalConfig(confType); err != nil {
    41  			return err
    42  		}
    43  
    44  		// 初始化全局组件
    45  		if err := loadGlobalComponent(); err != nil {
    46  			return err
    47  		}
    48  
    49  		// 初始化所有服务
    50  		if err := app.InitAllApp(); err != nil {
    51  			return err
    52  		}
    53  
    54  		conf := conf.C()
    55  		// 启动服务
    56  		ch := make(chan os.Signal, 1)
    57  		signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP, syscall.SIGQUIT)
    58  
    59  		// 初始化服务
    60  		svr, err := newService(conf)
    61  		if err != nil {
    62  			return err
    63  		}
    64  
    65  		// 等待信号处理
    66  		go svr.waitSign(ch)
    67  
    68  		// 启动服务
    69  		if err := svr.start(); err != nil {
    70  			if !strings.Contains(err.Error(), "http: Server closed") {
    71  				return err
    72  			}
    73  		}
    74  
    75  		return nil
    76  	},
    77  }
    78  
    79  func newService(cnf *conf.Config) (*service, error) {
    80  	log := zap.L().Named("CLI")
    81  	http := protocol.NewHTTPService()
    82  	grpc := protocol.NewGRPCService()
    83  
    84  	// 初始化总线
    85  	// bm, err := newBus()
    86  	// if err != nil {
    87  	// 	log.Errorf("new bus error, %s", err)
    88  	// }
    89  
    90  	svr := &service{
    91  		http: http,
    92  		grpc: grpc,
    93  		// bm:   bm,
    94  		log: log,
    95  	}
    96  
    97  	return svr, nil
    98  }
    99  
   100  type service struct {
   101  	http *protocol.HTTPService
   102  	grpc *protocol.GRPCService
   103  	// bm   bus.Manager
   104  
   105  	log  logger.Logger
   106  	stop context.CancelFunc
   107  }
   108  
   109  func (s *service) start() error {
   110  	// if s.bm != nil {
   111  	// 	if err := s.bm.Connect(); err != nil {
   112  	// 		s.log.Errorf("connect bus error, %s", err)
   113  	// 	}
   114  	// }
   115  
   116  	s.log.Infof("loaded grpc app: %s", app.LoadedGrpcApp())
   117  	s.log.Infof("loaded http app: %s", app.LoadedHttpApp())
   118  	s.log.Infof("loaded internal app: %s", app.LoadedInternalApp())
   119  
   120  	go s.grpc.Start()
   121  	return s.http.Start()
   122  }
   123  
   124  // config 为全局变量, 只需要load 即可全局可用户
   125  func loadGlobalConfig(configType string) error {
   126  	// 配置加载
   127  	switch configType {
   128  	case "file":
   129  		err := conf.LoadConfigFromToml(confFile)
   130  		if err != nil {
   131  			return err
   132  		}
   133  	case "env":
   134  		err := conf.LoadConfigFromEnv()
   135  		if err != nil {
   136  			return err
   137  		}
   138  		return nil
   139  	default:
   140  		return errors.New("unknown config type")
   141  	}
   142  
   143  	return nil
   144  }
   145  
   146  func loadGlobalComponent() error {
   147  	// 初始化全局日志配置
   148  	if err := loadGlobalLogger(); err != nil {
   149  		return err
   150  	}
   151  
   152  	// 加载缓存
   153  	if err := loadCache(); err != nil {
   154  		return err
   155  	}
   156  	return nil
   157  }
   158  
   159  // log 为全局变量, 只需要load 即可全局可用户, 依赖全局配置先初始化
   160  func loadGlobalLogger() error {
   161  	var (
   162  		logInitMsg string
   163  		level      zap.Level
   164  	)
   165  
   166  	lc := conf.C().Log
   167  	lv, err := zap.NewLevel(lc.Level)
   168  	if err != nil {
   169  		logInitMsg = fmt.Sprintf("%s, use default level INFO", err)
   170  		level = zap.InfoLevel
   171  	} else {
   172  		level = lv
   173  		logInitMsg = fmt.Sprintf("log level: %s", lv)
   174  	}
   175  
   176  	zapConfig := zap.DefaultConfig()
   177  	zapConfig.Level = level
   178  
   179  	switch lc.To {
   180  	case conf.ToStdout:
   181  		zapConfig.ToStderr = true
   182  		zapConfig.ToFiles = false
   183  	case conf.ToFile:
   184  		zapConfig.Files.Name = "api.log"
   185  		zapConfig.Files.Path = lc.PathDir
   186  	}
   187  
   188  	switch lc.Format {
   189  	case conf.JSONFormat:
   190  		zapConfig.JSON = true
   191  	}
   192  
   193  	if err := zap.Configure(zapConfig); err != nil {
   194  		return err
   195  	}
   196  
   197  	zap.L().Named("INIT").Info(logInitMsg)
   198  	return nil
   199  }
   200  
   201  func loadCache() error {
   202  	l := zap.L().Named("INIT")
   203  	c := conf.C()
   204  	// 设置全局缓存
   205  	switch c.Cache.Type {
   206  	case "memory", "":
   207  		ins := memory.NewCache(c.Cache.Memory)
   208  		cache.SetGlobal(ins)
   209  		l.Info("use cache in local memory")
   210  	case "redis":
   211  		ins := redis.NewCache(c.Cache.Redis)
   212  		cache.SetGlobal(ins)
   213  		l.Info("use redis to cache")
   214  	default:
   215  		return fmt.Errorf("unknown cache type: %s", c.Cache.Type)
   216  	}
   217  
   218  	return nil
   219  }
   220  
   221  // func newBus() (bus.Manager, error) {
   222  // 	c := conf.C()
   223  // 	if c.Nats != nil {
   224  // 		ns, err := nats.NewBroker(c.Nats)
   225  // 		if err != nil {
   226  // 			return nil, err
   227  // 		}
   228  // 		bus.SetPublisher(ns)
   229  // 		return ns, nil
   230  // 	}
   231  
   232  // 	if c.Kafka != nil {
   233  // 		ks, err := kafka.NewPublisher(c.Kafka)
   234  // 		if err != nil {
   235  // 			return nil, err
   236  // 		}
   237  // 		bus.SetPublisher(ks)
   238  // 		return ks, nil
   239  // 	}
   240  
   241  // 	return nil, fmt.Errorf("bus not config, nats or kafka required")
   242  // }
   243  
   244  func (s *service) waitSign(sign chan os.Signal) {
   245  	for {
   246  		select {
   247  		case sg := <-sign:
   248  			switch v := sg.(type) {
   249  			default:
   250  				s.log.Infof("receive signal '%v', start graceful shutdown", v.String())
   251  				if err := s.grpc.Stop(); err != nil {
   252  					s.log.Errorf("grpc graceful shutdown err: %s, force exit", err)
   253  				}
   254  				s.log.Info("grpc service stop complete")
   255  				if err := s.http.Stop(); err != nil {
   256  					s.log.Errorf("http graceful shutdown err: %s, force exit", err)
   257  				}
   258  				s.log.Infof("http service stop complete")
   259  				return
   260  			}
   261  		}
   262  	}
   263  }
   264  
   265  func init() {
   266  	serviceCmd.Flags().StringVarP(&confType, "config-type", "t", "file", "the service config type [file/env/etcd]")
   267  	serviceCmd.Flags().StringVarP(&confFile, "config-file", "f", "etc/keyauth.toml", "the service config from file")
   268  	RootCmd.AddCommand(serviceCmd)
   269  }