Browse Source

use gocron for scheduling auto-cert job

Improved error handling
0xJacky 3 years ago
parent
commit
21c6f403ce
6 changed files with 257 additions and 216 deletions
  1. 3 0
      go.mod
  2. 12 3
      go.sum
  3. 76 66
      main.go
  4. 91 72
      server/analytic/record.go
  5. 52 54
      server/api/install.go
  6. 23 21
      server/tool/cert.go

+ 3 - 0
go.mod

@@ -7,6 +7,7 @@ require (
 	github.com/gin-contrib/static v0.0.1
 	github.com/gin-gonic/gin v1.7.4
 	github.com/go-acme/lego/v4 v4.4.0
+	github.com/go-co-op/gocron v1.15.0
 	github.com/go-playground/locales v0.13.0
 	github.com/go-playground/universal-translator v0.17.0
 	github.com/go-playground/validator/v10 v10.4.1
@@ -38,10 +39,12 @@ require (
 	github.com/miekg/dns v1.1.40 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.1 // indirect
+	github.com/robfig/cron/v3 v3.0.1 // indirect
 	github.com/tklauser/go-sysconf v0.3.7 // indirect
 	github.com/tklauser/numcpus v0.2.3 // indirect
 	github.com/ugorji/go/codec v1.1.7 // indirect
 	golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d // indirect
+	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
 	golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
 	golang.org/x/text v0.3.4 // indirect
 	gopkg.in/square/go-jose.v2 v2.5.1 // indirect

+ 12 - 3
go.sum

@@ -115,6 +115,8 @@ github.com/go-acme/lego/v4 v4.4.0 h1:uHhU5LpOYQOdp3aDU+XY2bajseu8fuExphTL1Ss6/Fc
 github.com/go-acme/lego/v4 v4.4.0/go.mod h1:l3+tFUFZb590dWcqhWZegynUthtaHJbG2fevUpoOOE0=
 github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
 github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
+github.com/go-co-op/gocron v1.15.0 h1:XmiPazahD9aq0/QdK5toCVHfgTXfrZ/s83RpAgzr6SM=
+github.com/go-co-op/gocron v1.15.0/go.mod h1:On9zUZTv7FBeuj9D/cdYyAWcPUiLqqAx7nsPHd0EmKM=
 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -366,6 +368,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -406,13 +410,16 @@ github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
+github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tklauser/go-sysconf v0.3.7 h1:HT7h4+536gjqeq1ZIJPgOl1rg1XFatQGVZWp7Py53eg=
 github.com/tklauser/go-sysconf v0.3.7/go.mod h1:JZIdXh4RmBvZDBZ41ld2bGxRV3n4daiiqA3skYhAoQ4=
@@ -534,8 +541,9 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -707,8 +715,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
 gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
 gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=

+ 76 - 66
main.go

@@ -1,74 +1,84 @@
 package main
 
 import (
-	"context"
-	"flag"
-	"github.com/0xJacky/Nginx-UI/server/analytic"
-	"github.com/0xJacky/Nginx-UI/server/model"
-	"github.com/0xJacky/Nginx-UI/server/router"
-	"github.com/0xJacky/Nginx-UI/server/settings"
-	"github.com/0xJacky/Nginx-UI/server/tool"
-	"github.com/0xJacky/Nginx-UI/server/tool/nginx"
-	"github.com/gin-gonic/gin"
-	"log"
-	"mime"
-	"net/http"
-	"os/signal"
-	"syscall"
-	"time"
+    "context"
+    "flag"
+    "github.com/0xJacky/Nginx-UI/server/analytic"
+    "github.com/0xJacky/Nginx-UI/server/model"
+    "github.com/0xJacky/Nginx-UI/server/router"
+    "github.com/0xJacky/Nginx-UI/server/settings"
+    "github.com/0xJacky/Nginx-UI/server/tool"
+    "github.com/0xJacky/Nginx-UI/server/tool/nginx"
+    "github.com/gin-gonic/gin"
+    "github.com/go-co-op/gocron"
+    "log"
+    "mime"
+    "net/http"
+    "os/signal"
+    "syscall"
+    "time"
 )
 
 func main() {
-	// Create context that listens for the interrupt signal from the OS.
-	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
-	defer stop()
-
-	// Hack: fix wrong Content Type of .js file on some OS platforms
-	// See https://github.com/golang/go/issues/32350
-	_ = mime.AddExtensionType(".js", "text/javascript; charset=utf-8")
-
-	var confPath string
-	flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file")
-	flag.Parse()
-
-	gin.SetMode(settings.ServerSettings.RunMode)
-
-	settings.Init(confPath)
-	log.Printf("nginx config dir path: %s", nginx.GetNginxConfPath(""))
-	if "" != settings.ServerSettings.JwtSecret {
-		model.Init()
-		go tool.AutoCert()
-		go analytic.RecordServerAnalytic()
-	}
-
-	srv := &http.Server{
-		Addr:    ":" + settings.ServerSettings.HttpPort,
-		Handler: router.InitRouter(),
-	}
-
-	// Initializing the server in a goroutine so that
-	// it won't block the graceful shutdown handling below
-	go func() {
-		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
-			log.Fatalf("listen: %s\n", err)
-		}
-	}()
-
-	// Listen for the interrupt signal.
-	<-ctx.Done()
-
-	// Restore default behavior on the interrupt signal and notify user of shutdown.
-	stop()
-	log.Println("shutting down gracefully, press Ctrl+C again to force")
-
-	// The context is used to inform the server it has 5 seconds to finish
-	// the request it is currently handling
-	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
-	defer cancel()
-	if err := srv.Shutdown(ctx); err != nil {
-		log.Fatal("Server forced to shutdown: ", err)
-	}
-
-	log.Println("Server exiting")
+    // Create context that listens for the interrupt signal from the OS.
+    ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+    defer stop()
+
+    // Hack: fix wrong Content Type of .js file on some OS platforms
+    // See https://github.com/golang/go/issues/32350
+    _ = mime.AddExtensionType(".js", "text/javascript; charset=utf-8")
+
+    var confPath string
+    flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file")
+    flag.Parse()
+
+    gin.SetMode(settings.ServerSettings.RunMode)
+
+    settings.Init(confPath)
+    log.Printf("nginx config dir path: %s", nginx.GetNginxConfPath(""))
+    if "" != settings.ServerSettings.JwtSecret {
+        model.Init()
+
+        s := gocron.NewScheduler(time.UTC)
+        job, err := s.Every(1).Hour().SingletonMode().Do(tool.AutoCert)
+
+        if err != nil {
+            log.Fatalf("AutoCert Job: %v, Err: %v\n", job, err)
+        }
+
+        s.StartAsync()
+
+        go analytic.RecordServerAnalytic()
+    }
+
+    srv := &http.Server{
+        Addr:    ":" + settings.ServerSettings.HttpPort,
+        Handler: router.InitRouter(),
+    }
+
+    // Initializing the server in a goroutine so that
+    // it won't block the graceful shutdown handling below
+    go func() {
+        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+            log.Fatalf("listen: %s\n", err)
+        }
+    }()
+
+    // Listen for the interrupt signal.
+    <-ctx.Done()
+
+    // Restore default behavior on the interrupt signal and notify user of shutdown.
+    stop()
+    log.Println("shutting down gracefully, press Ctrl+C again to force")
+
+    // The context is used to inform the server it has 5 seconds to finish
+    // the request it is currently handling
+    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+    defer cancel()
+    if err := srv.Shutdown(ctx); err != nil {
+        log.Fatal("Server forced to shutdown: ", err)
+    }
+
+    log.Println("Server exiting")
 
 }

+ 91 - 72
server/analytic/record.go

@@ -1,96 +1,115 @@
 package analytic
 
 import (
-	"github.com/shirou/gopsutil/v3/cpu"
-	"github.com/shirou/gopsutil/v3/disk"
-	"github.com/shirou/gopsutil/v3/net"
-	"runtime"
-	"time"
+    "github.com/go-acme/lego/v4/log"
+    "github.com/shirou/gopsutil/v3/cpu"
+    "github.com/shirou/gopsutil/v3/disk"
+    "github.com/shirou/gopsutil/v3/net"
+    "runtime"
+    "time"
 )
 
 func getTotalDiskIO() (read, write uint64) {
-	diskIOCounters, _ := disk.IOCounters()
-	for _, v := range diskIOCounters {
-		write += v.WriteCount
-		read += v.ReadCount
-	}
-	return
+    diskIOCounters, err := disk.IOCounters()
+    if err != nil {
+        log.Println("getTotalDiskIO: get diskIOCounters err", err)
+        return
+    }
+    for _, v := range diskIOCounters {
+        write += v.WriteCount
+        read += v.ReadCount
+    }
+    return
 }
 
 func recordCpu(now time.Time) {
-	cpuTimesBefore, _ := cpu.Times(false)
-	time.Sleep(1000 * time.Millisecond)
-	cpuTimesAfter, _ := cpu.Times(false)
-	threadNum := runtime.GOMAXPROCS(0)
+    cpuTimesBefore, err := cpu.Times(false)
+    if err != nil {
+        log.Println("recordCpu: get cpuTimesBefore err", err)
+        return
+    }
+    time.Sleep(1000 * time.Millisecond)
+    cpuTimesAfter, err := cpu.Times(false)
+    if err != nil {
+        log.Println("recordCpu: get cpuTimesAfter err", err)
+        return
+    }
+    threadNum := runtime.GOMAXPROCS(0)
 
-	cpuUserUsage := (cpuTimesAfter[0].User - cpuTimesBefore[0].User) / (float64(1000*threadNum) / 1000)
-	cpuUserUsage *= 100
-	cpuSystemUsage := (cpuTimesAfter[0].System - cpuTimesBefore[0].System) / (float64(1000*threadNum) / 1000)
-	cpuSystemUsage *= 100
+    cpuUserUsage := (cpuTimesAfter[0].User - cpuTimesBefore[0].User) / (float64(1000*threadNum) / 1000)
+    cpuUserUsage *= 100
+    cpuSystemUsage := (cpuTimesAfter[0].System - cpuTimesBefore[0].System) / (float64(1000*threadNum) / 1000)
+    cpuSystemUsage *= 100
 
-	u := usage{
-		Time:  now,
-		Usage: cpuUserUsage,
-	}
+    u := usage{
+        Time:  now,
+        Usage: cpuUserUsage,
+    }
 
-	CpuUserRecord = append(CpuUserRecord, u)
+    CpuUserRecord = append(CpuUserRecord, u)
 
-	s := usage{
-		Time:  now,
-		Usage: cpuUserUsage + cpuSystemUsage,
-	}
+    s := usage{
+        Time:  now,
+        Usage: cpuUserUsage + cpuSystemUsage,
+    }
 
-	CpuTotalRecord = append(CpuTotalRecord, s)
+    CpuTotalRecord = append(CpuTotalRecord, s)
 
-	if len(CpuUserRecord) > 100 {
-		CpuUserRecord = CpuUserRecord[1:]
-	}
+    if len(CpuUserRecord) > 100 {
+        CpuUserRecord = CpuUserRecord[1:]
+    }
 
-	if len(CpuTotalRecord) > 100 {
-		CpuTotalRecord = CpuTotalRecord[1:]
-	}
+    if len(CpuTotalRecord) > 100 {
+        CpuTotalRecord = CpuTotalRecord[1:]
+    }
 }
 
 func recordNetwork(now time.Time) {
-	network, _ := net.IOCounters(false)
-	if len(network) == 0 {
-		return
-	}
-	NetRecvRecord = append(NetRecvRecord, usage{
-		Time:  now,
-		Usage: network[0].BytesRecv - LastNetRecv,
-	})
-	NetSentRecord = append(NetSentRecord, usage{
-		Time:  now,
-		Usage: network[0].BytesSent - LastNetSent,
-	})
-	LastNetRecv = network[0].BytesRecv
-	LastNetSent = network[0].BytesSent
-	if len(NetRecvRecord) > 100 {
-		NetRecvRecord = NetRecvRecord[1:]
-	}
-	if len(NetSentRecord) > 100 {
-		NetSentRecord = NetSentRecord[1:]
-	}
+    network, err := net.IOCounters(false)
+
+    if err != nil {
+        log.Println("recordNetwork: get network err", err)
+        return
+    }
+
+    if len(network) == 0 {
+        return
+    }
+    NetRecvRecord = append(NetRecvRecord, usage{
+        Time:  now,
+        Usage: network[0].BytesRecv - LastNetRecv,
+    })
+    NetSentRecord = append(NetSentRecord, usage{
+        Time:  now,
+        Usage: network[0].BytesSent - LastNetSent,
+    })
+    LastNetRecv = network[0].BytesRecv
+    LastNetSent = network[0].BytesSent
+    if len(NetRecvRecord) > 100 {
+        NetRecvRecord = NetRecvRecord[1:]
+    }
+    if len(NetSentRecord) > 100 {
+        NetSentRecord = NetSentRecord[1:]
+    }
 }
 
 func recordDiskIO(now time.Time) {
-	readCount, writeCount := getTotalDiskIO()
+    readCount, writeCount := getTotalDiskIO()
 
-	DiskReadRecord = append(DiskReadRecord, usage{
-		Time:  now,
-		Usage: readCount - LastDiskReads,
-	})
-	DiskWriteRecord = append(DiskWriteRecord, usage{
-		Time:  now,
-		Usage: writeCount - LastDiskWrites,
-	})
-	if len(DiskReadRecord) > 100 {
-		DiskReadRecord = DiskReadRecord[1:]
-	}
-	if len(DiskWriteRecord) > 100 {
-		DiskWriteRecord = DiskWriteRecord[1:]
-	}
-	LastDiskWrites = writeCount
-	LastDiskReads = readCount
+    DiskReadRecord = append(DiskReadRecord, usage{
+        Time:  now,
+        Usage: readCount - LastDiskReads,
+    })
+    DiskWriteRecord = append(DiskWriteRecord, usage{
+        Time:  now,
+        Usage: writeCount - LastDiskWrites,
+    })
+    if len(DiskReadRecord) > 100 {
+        DiskReadRecord = DiskReadRecord[1:]
+    }
+    if len(DiskWriteRecord) > 100 {
+        DiskWriteRecord = DiskWriteRecord[1:]
+    }
+    LastDiskWrites = writeCount
+    LastDiskReads = readCount
 }

+ 52 - 54
server/api/install.go

@@ -1,75 +1,73 @@
 package api
 
 import (
-	"github.com/0xJacky/Nginx-UI/server/model"
-	"github.com/0xJacky/Nginx-UI/server/settings"
-	"github.com/0xJacky/Nginx-UI/server/tool"
-	"github.com/gin-gonic/gin"
-	"github.com/google/uuid"
-	"golang.org/x/crypto/bcrypt"
-	"net/http"
+    "github.com/0xJacky/Nginx-UI/server/model"
+    "github.com/0xJacky/Nginx-UI/server/settings"
+    "github.com/gin-gonic/gin"
+    "github.com/google/uuid"
+    "golang.org/x/crypto/bcrypt"
+    "net/http"
 )
 
 func installLockStatus() bool {
-	return "" != settings.ServerSettings.JwtSecret
+    return "" != settings.ServerSettings.JwtSecret
 }
 
 func InstallLockCheck(c *gin.Context) {
-	c.JSON(http.StatusOK, gin.H{
-		"lock": installLockStatus(),
-	})
+    c.JSON(http.StatusOK, gin.H{
+        "lock": installLockStatus(),
+    })
 }
 
 type InstallJson struct {
-	Email    string `json:"email" binding:"required,email"`
-	Username string `json:"username" binding:"required,max=255"`
-	Password string `json:"password" binding:"required,max=255"`
-	Database string `json:"database"`
+    Email    string `json:"email" binding:"required,email"`
+    Username string `json:"username" binding:"required,max=255"`
+    Password string `json:"password" binding:"required,max=255"`
+    Database string `json:"database"`
 }
 
 func InstallNginxUI(c *gin.Context) {
-	// 安装过就别访问了
-	if installLockStatus() {
-		c.JSON(http.StatusForbidden, gin.H{
-			"message": "installed",
-		})
-		return
-	}
-	var json InstallJson
-	ok := BindAndValid(c, &json)
-	if !ok {
-		return
-	}
+    // 安装过就别访问了
+    if installLockStatus() {
+        c.JSON(http.StatusForbidden, gin.H{
+            "message": "installed",
+        })
+        return
+    }
+    var json InstallJson
+    ok := BindAndValid(c, &json)
+    if !ok {
+        return
+    }
 
-	settings.ServerSettings.JwtSecret = uuid.New().String()
-	settings.ServerSettings.Email = json.Email
-	if "" != json.Database {
-		settings.ServerSettings.Database = json.Database
-	}
-	settings.ReflectFrom()
+    settings.ServerSettings.JwtSecret = uuid.New().String()
+    settings.ServerSettings.Email = json.Email
+    if "" != json.Database {
+        settings.ServerSettings.Database = json.Database
+    }
+    settings.ReflectFrom()
 
-	err := settings.Save()
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
+    err := settings.Save()
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
 
-	// Init model and auto cert
-	model.Init()
-	go tool.AutoCert()
+    // Init model
+    model.Init()
 
-	curd := model.NewCurd(&model.Auth{})
-	pwd, _ := bcrypt.GenerateFromPassword([]byte(json.Password), bcrypt.DefaultCost)
-	err = curd.Add(&model.Auth{
-		Name:     json.Username,
-		Password: string(pwd),
-	})
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-	c.JSON(http.StatusOK, gin.H{
-		"message": "ok",
-	})
+    curd := model.NewCurd(&model.Auth{})
+    pwd, _ := bcrypt.GenerateFromPassword([]byte(json.Password), bcrypt.DefaultCost)
+    err = curd.Add(&model.Auth{
+        Name:     json.Username,
+        Password: string(pwd),
+    })
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+    c.JSON(http.StatusOK, gin.H{
+        "message": "ok",
+    })
 
 }

+ 23 - 21
server/tool/cert.go

@@ -44,28 +44,30 @@ func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
 }
 
 func AutoCert() {
-	for {
-		log.Println("[AutoCert] Start")
-		autoCertList := model.GetAutoCertList()
-		for i := range autoCertList {
-			domain := autoCertList[i].Domain
-			key, err := GetCertInfo(domain)
-			if err != nil {
-				log.Println("GetCertInfo Err", err)
-				// 获取证书信息失败,本次跳过
-				continue
-			}
-			// 未到一个月
-			if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
-				continue
-			}
-			// 过一个月了,重新申请证书
-			err = IssueCert(domain)
-			if err != nil {
-				log.Println(err)
-			}
+	defer func() {
+		if err := recover(); err != nil {
+			log.Println("[AutoCert] Recover", err)
+		}
+	}()
+	log.Println("[AutoCert] Start")
+	autoCertList := model.GetAutoCertList()
+	for i := range autoCertList {
+		domain := autoCertList[i].Domain
+		key, err := GetCertInfo(domain)
+		if err != nil {
+			log.Println("GetCertInfo Err", err)
+			// 获取证书信息失败,本次跳过
+			continue
+		}
+		// 未到一个月
+		if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
+			continue
+		}
+		// 过一个月了,重新申请证书
+		err = IssueCert(domain)
+		if err != nil {
+			log.Println(err)
 		}
-		time.Sleep(1 * time.Hour)
 	}
 }