package main import ( "bytes" "fmt" nested "github.com/antonfisher/nested-logrus-formatter" "github.com/labstack/gommon/log" "github.com/patrickmn/go-cache" "github.com/robfig/cron/v3" "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/driver/sqlite" "gorm.io/gorm" "io" "next-terminal/pkg/api" "next-terminal/pkg/config" "next-terminal/pkg/global" "next-terminal/pkg/handle" "next-terminal/pkg/model" "next-terminal/pkg/utils" "os" "strconv" "strings" "time" ) const Version = "v0.2.7" func main() { log.Fatal(Run()) } func Run() error { fmt.Printf(` _______ __ ___________ .__ .__ \ \ ____ ___ ____/ |_ \__ ___/__________ _____ |__| ____ _____ | | / | \_/ __ \\ \/ /\ __\ | |_/ __ \_ __ \/ \| |/ \\__ \ | | / | \ ___/ > < | | | |\ ___/| | \/ Y Y \ | | \/ __ \| |__ \____|__ /\___ >__/\_ \ |__| |____| \___ >__| |__|_| /__|___| (____ /____/ \/ \/ \/ \/ \/ \/ \/ ` + Version + "\n\n") var err error //logrus.SetReportCaller(true) logrus.SetLevel(logrus.DebugLevel) logrus.SetFormatter(&nested.Formatter{ HideKeys: true, FieldsOrder: []string{"component", "category"}, }) writer1 := &bytes.Buffer{} writer2 := os.Stdout writer3, err := os.OpenFile("next-terminal.log", os.O_WRONLY|os.O_CREATE, 0755) if err != nil { log.Fatalf("create file log.txt failed: %v", err) } logrus.SetOutput(io.MultiWriter(writer1, writer2, writer3)) global.Config, err = config.SetupConfig() if err != nil { return err } fmt.Printf("当前数据库模式为:%v\n", global.Config.DB) if global.Config.DB == "mysql" { dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", global.Config.Mysql.Username, global.Config.Mysql.Password, global.Config.Mysql.Hostname, global.Config.Mysql.Port, global.Config.Mysql.Database, ) global.DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ //Logger: logger.Default.LogMode(logger.Info), }) } else { global.DB, err = gorm.Open(sqlite.Open(global.Config.Sqlite.File), &gorm.Config{ //Logger: logger.Default.LogMode(logger.Info), }) } if err != nil { logrus.Errorf("连接数据库异常:%v", err.Error()) return err } if err := global.DB.AutoMigrate(&model.User{}); err != nil { return err } users := model.FindAllUser() if len(users) == 0 { initPassword := "admin" var pass []byte if pass, err = utils.Encoder.Encode([]byte(initPassword)); err != nil { return err } user := model.User{ ID: utils.UUID(), Username: "admin", Password: string(pass), Nickname: "超级管理员", Type: model.TypeAdmin, Created: utils.NowJsonTime(), } if err := model.CreateNewUser(&user); err != nil { return err } logrus.Infof("初始用户创建成功,账号:「%v」密码:「%v」", user.Username, initPassword) } else { for i := range users { // 修正默认用户类型为管理员 if users[i].Type == "" { user := model.User{ Type: model.TypeAdmin, } model.UpdateUserById(&user, users[i].ID) logrus.Infof("自动修正用户「%v」ID「%v」类型为管理员", users[i].Nickname, users[i].ID) } } } if err := global.DB.AutoMigrate(&model.Asset{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.AssetAttribute{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.Session{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.Command{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.Credential{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.Property{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.ResourceSharer{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.UserGroup{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.UserGroupMember{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.LoginLog{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.Num{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.Job{}); err != nil { return err } if len(model.FindAllTemp()) == 0 { for i := 0; i <= 30; i++ { if err := model.CreateNewTemp(&model.Num{I: strconv.Itoa(i)}); err != nil { return err } } } // 配置缓存器 global.Cache = cache.New(5*time.Minute, 10*time.Minute) global.Cache.OnEvicted(func(key string, value interface{}) { if strings.HasPrefix(key, api.Token) { token := strings.Split(key, ":")[1] logrus.Debugf("用户Token「%v」过期", token) model.Logout(token) } }) global.Store = global.NewStore() global.Cron = cron.New(cron.WithSeconds()) //精确到秒 jobs, err := model.FindJobByFunc(model.FuncCheckAssetStatusJob) if err != nil { return err } if jobs == nil || len(jobs) == 0 { job := model.Job{ ID: utils.UUID(), Name: "资产状态检测", Func: model.FuncCheckAssetStatusJob, Cron: "0 0 0/1 * * ?", Status: model.JobStatusRunning, Created: utils.NowJsonTime(), Updated: utils.NowJsonTime(), } if err := model.CreateNewJob(&job); err != nil { return err } } jobs, err = model.FindJobByFunc(model.FuncDelTimeoutSessionJob) if err != nil { return err } if jobs == nil || len(jobs) == 0 { job := model.Job{ ID: utils.UUID(), Name: "超时会话检测", Func: model.FuncDelTimeoutSessionJob, Cron: "0 0 0 * * ?", Status: model.JobStatusRunning, Created: utils.NowJsonTime(), Updated: utils.NowJsonTime(), } if err := model.CreateNewJob(&job); err != nil { return err } } loginLogs, err := model.FindAliveLoginLogs() if err != nil { return err } for i := range loginLogs { loginLog := loginLogs[i] token := loginLog.ID user, err := model.FindUserById(loginLog.UserId) if err != nil { logrus.Debugf("用户「%v」获取失败,忽略", loginLog.UserId) continue } authorization := api.Authorization{ Token: token, Remember: loginLog.Remember, User: user, } cacheKey := strings.Join([]string{api.Token, token}, ":") if authorization.Remember { // 记住登录有效期两周 global.Cache.Set(cacheKey, authorization, api.RememberEffectiveTime) } else { global.Cache.Set(cacheKey, authorization, api.NotRememberEffectiveTime) } logrus.Debugf("重新加载用户「%v」授权Token「%v」到缓存", user.Nickname, token) } e := api.SetupRoutes() if err := handle.InitProperties(); err != nil { return err } // 启动定时任务 go handle.RunTicker() go handle.RunDataFix() if global.Config.Server.Cert != "" && global.Config.Server.Key != "" { return e.StartTLS(global.Config.Server.Addr, global.Config.Server.Cert, global.Config.Server.Key) } else { return e.Start(global.Config.Server.Addr) } }