package cmd import ( "context" "fmt" "github.com/gin-contrib/pprof" "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" "github.com/robfig/cron/v3" "github.com/spf13/cobra" "github.com/zh-five/xdaemon" "html/template" "io/ioutil" "kefu/common" "kefu/controller" "kefu/middleware" "kefu/models" "kefu/router" "kefu/service" "kefu/static" "kefu/tools" "kefu/ws" "log" "net/http" "os" "time" ) var ( port string daemon bool rootPath string ) var serverCmd = &cobra.Command{ Use: "server", Short: "启动客服http服务", Example: "kefu server", Run: run, } func init() { serverCmd.PersistentFlags().StringVarP(&rootPath, "rootPath", "r", "", "程序根目录") serverCmd.PersistentFlags().StringVarP(&port, "port", "p", "8081", "监听端口号") serverCmd.PersistentFlags().BoolVarP(&daemon, "daemon", "d", false, "是否为守护进程模式") } func run(cmd *cobra.Command, args []string) { //初始化目录 initDir() //初始化守护进程 initDaemon() baseServer := "0.0.0.0:" + port //if common.RpcStatus { // go frpc.NewRpcServer(common.RpcServer) // log.Println("start rpc server...\r\ngo:tcp://" + common.RpcServer) //} engine := gin.Default() //模板函数 engine.SetFuncMap(template.FuncMap{ "DateFormat": tools.DateFormat, //格式化日期 }) //是否编译模板 if common.IsCompireTemplate { templ := template.Must(template.New("").ParseFS(static.TemplatesEmbed, "templates/**/*.html")) engine.SetHTMLTemplate(templ) } else { engine.LoadHTMLGlob(common.StaticDirPath + "templates/**/*") } engine.Static("/static", common.StaticDirPath) engine.Static("/h5", common.RootPath+"/h5") store := cookie.NewStore([]byte("secret")) sessionNames := []string{"go-session", "go-session-a", "go-session-b"} engine.Use(sessions.SessionsMany(sessionNames, store)) //engine.Use(tools.Session("kefu")) engine.Use(middleware.CrossSite) router.InitViewRouter(engine) router.InitApiRouter(engine) //限流类 tools.NewLimitQueue() //清理 //ws.CleanVisitorExpire() //后端websocket //go ws.WsServerBackend() //初始化数据 //logger := lib.NewLogger() err := models.NewConnect(common.ConfigDirPath + "/mysql.json") if err != nil { common.MySQLConnectFaild = true } //后端定时客服 //go ws.UpdateVisitorStatusCron() //初始化定时任务 // 创建定时任务调度器 cr := cron.New() // 添加定时任务,每分钟执行一次 cr.AddFunc("*/1 * * * *", func() { log.Println("定时任务执行:", time.Now().Format("2006-01-02 15:04:05"), "给客服websocket链接发送ping") // 这里可以添加你的定时任务逻辑 ws.SendPingToKefuClient() }) // 添加定时任务,每小时执行一次,更新抖音 douyinClientKey := models.FindConfig("DouyinClientKey") douyinClientSecret := models.FindConfig("DouyinClientSecret") if douyinClientKey != "" && douyinClientSecret != "" { cr.AddFunc("0 */1 * * *", func() { log.Println("定时任务执行:", time.Now().Format("2006-01-02 15:04:05"), "更新抖音access_token,refresh_token") service.UpdateDouyinAccessToken() }) } // 启动定时任务调度器 cr.Start() defer cr.Stop() log.Println("服务开始运行:" + baseServer) //性能监控 pprof.Register(engine) //engine.Run(baseServer) srv := &http.Server{ Addr: baseServer, Handler: engine, } go func() { if err := srv.ListenAndServe(); err != nil { log.Printf("服务监听: %s\n", err) } }() <-controller.StopSign log.Println("关闭服务...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("服务关闭失败:", err) } log.Println("服务已关闭") } // 初始化目录 func initDir() { if rootPath == "" { rootPath = tools.GetRootPath() } log.Println("服务运行路径:" + rootPath) common.RootPath = rootPath common.LogDirPath = rootPath + "/logs/" common.ConfigDirPath = rootPath + "/config/" common.StaticDirPath = rootPath + "/static/" common.UploadDirPath = rootPath + "/static/upload/" if noExist, _ := tools.IsFileNotExist(common.RootPath + "/install.lock"); noExist { panic("未检测到" + common.RootPath + "/install.lock,请先安装服务!") } if noExist, _ := tools.IsFileNotExist(common.LogDirPath); noExist { if err := os.MkdirAll(common.LogDirPath, 0777); err != nil { log.Println(err.Error()) } } isMainUploadExist, _ := tools.IsFileExist(common.UploadDirPath) if !isMainUploadExist { os.Mkdir(common.UploadDirPath, os.ModePerm) } } // 初始化守护进程 func initDaemon() { if daemon == true { d := xdaemon.NewDaemon(common.LogDirPath + "kefu.log") d.MaxError = 5 d.Run() } //记录pid ioutil.WriteFile(common.RootPath+"/kefu.sock", []byte(fmt.Sprintf("%d %d", os.Getppid(), os.Getpid())), 0666) }