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  }