github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/main.go (about) 1 package main 2 3 import ( 4 "context" 5 _ "embed" 6 "flag" 7 "io/fs" 8 "net" 9 "net/http" 10 "os" 11 "os/signal" 12 "path/filepath" 13 "syscall" 14 "time" 15 16 "github.com/cloudreve/Cloudreve/v3/bootstrap" 17 model "github.com/cloudreve/Cloudreve/v3/models" 18 "github.com/cloudreve/Cloudreve/v3/pkg/cache" 19 "github.com/cloudreve/Cloudreve/v3/pkg/conf" 20 "github.com/cloudreve/Cloudreve/v3/pkg/util" 21 "github.com/cloudreve/Cloudreve/v3/routers" 22 ) 23 24 var ( 25 isEject bool 26 confPath string 27 scriptName string 28 ) 29 30 //go:embed assets.zip 31 var staticZip string 32 33 var staticFS fs.FS 34 35 func init() { 36 flag.StringVar(&confPath, "c", util.RelativePath("conf.ini"), "Path to the config file.") 37 flag.BoolVar(&isEject, "eject", false, "Eject all embedded static files.") 38 flag.StringVar(&scriptName, "database-script", "", "Name of database util script.") 39 flag.Parse() 40 41 staticFS = bootstrap.NewFS(staticZip) 42 bootstrap.Init(confPath, staticFS) 43 } 44 45 func main() { 46 // 关闭数据库连接 47 defer func() { 48 if model.DB != nil { 49 model.DB.Close() 50 } 51 }() 52 53 if isEject { 54 // 开始导出内置静态资源文件 55 bootstrap.Eject(staticFS) 56 return 57 } 58 59 if scriptName != "" { 60 // 开始运行助手数据库脚本 61 bootstrap.RunScript(scriptName) 62 return 63 } 64 65 api := routers.InitRouter() 66 api.TrustedPlatform = conf.SystemConfig.ProxyHeader 67 server := &http.Server{Handler: api} 68 69 // 收到信号后关闭服务器 70 sigChan := make(chan os.Signal, 1) 71 signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT) 72 go shutdown(sigChan, server) 73 74 defer func() { 75 <-sigChan 76 }() 77 78 // 如果启用了SSL 79 if conf.SSLConfig.CertPath != "" { 80 util.Log().Info("Listening to %q", conf.SSLConfig.Listen) 81 server.Addr = conf.SSLConfig.Listen 82 if err := server.ListenAndServeTLS(conf.SSLConfig.CertPath, conf.SSLConfig.KeyPath); err != nil { 83 util.Log().Error("Failed to listen to %q: %s", conf.SSLConfig.Listen, err) 84 return 85 } 86 } 87 88 // 如果启用了Unix 89 if conf.UnixConfig.Listen != "" { 90 // delete socket file before listening 91 if _, err := os.Stat(conf.UnixConfig.Listen); err == nil { 92 if err = os.Remove(conf.UnixConfig.Listen); err != nil { 93 util.Log().Error("Failed to delete socket file: %s", err) 94 return 95 } 96 } 97 98 util.Log().Info("Listening to %q", conf.UnixConfig.Listen) 99 if err := RunUnix(server); err != nil { 100 util.Log().Error("Failed to listen to %q: %s", conf.UnixConfig.Listen, err) 101 } 102 return 103 } 104 105 util.Log().Info("Listening to %q", conf.SystemConfig.Listen) 106 server.Addr = conf.SystemConfig.Listen 107 if err := server.ListenAndServe(); err != nil { 108 util.Log().Error("Failed to listen to %q: %s", conf.SystemConfig.Listen, err) 109 } 110 } 111 112 func RunUnix(server *http.Server) error { 113 listener, err := net.Listen("unix", conf.UnixConfig.Listen) 114 if err != nil { 115 return err 116 } 117 118 defer listener.Close() 119 defer os.Remove(conf.UnixConfig.Listen) 120 121 if conf.UnixConfig.Perm > 0 { 122 err = os.Chmod(conf.UnixConfig.Listen, os.FileMode(conf.UnixConfig.Perm)) 123 if err != nil { 124 util.Log().Warning( 125 "Failed to set permission to %q for socket file %q: %s", 126 conf.UnixConfig.Perm, 127 conf.UnixConfig.Listen, 128 err, 129 ) 130 } 131 } 132 133 return server.Serve(listener) 134 } 135 136 func shutdown(sigChan chan os.Signal, server *http.Server) { 137 sig := <-sigChan 138 util.Log().Info("Signal %s received, shutting down server...", sig) 139 ctx := context.Background() 140 if conf.SystemConfig.GracePeriod != 0 { 141 var cancel context.CancelFunc 142 ctx, cancel = context.WithTimeout(ctx, time.Duration(conf.SystemConfig.GracePeriod)*time.Second) 143 defer cancel() 144 } 145 146 // Shutdown http server 147 err := server.Shutdown(ctx) 148 if err != nil { 149 util.Log().Error("Failed to shutdown server: %s", err) 150 } 151 152 // Persist in-memory cache 153 if err := cache.Store.Persist(filepath.Join(model.GetSettingByName("temp_path"), cache.DefaultCacheFile)); err != nil { 154 util.Log().Warning("Failed to persist cache: %s", err) 155 } 156 157 close(sigChan) 158 }