Spaces:
Runtime error
Runtime error
package cmd | |
import ( | |
"context" | |
"errors" | |
"fmt" | |
"net" | |
"net/http" | |
"os" | |
"os/signal" | |
"strconv" | |
"sync" | |
"syscall" | |
"time" | |
"github.com/alist-org/alist/v3/cmd/flags" | |
"github.com/alist-org/alist/v3/internal/bootstrap" | |
"github.com/alist-org/alist/v3/internal/conf" | |
"github.com/alist-org/alist/v3/pkg/utils" | |
"github.com/alist-org/alist/v3/server" | |
"github.com/gin-gonic/gin" | |
log "github.com/sirupsen/logrus" | |
"github.com/spf13/cobra" | |
) | |
// ServerCmd represents the server command | |
var ServerCmd = &cobra.Command{ | |
Use: "server", | |
Short: "Start the server at the specified address", | |
Long: `Start the server at the specified address | |
the address is defined in config file`, | |
Run: func(cmd *cobra.Command, args []string) { | |
Init() | |
if conf.Conf.DelayedStart != 0 { | |
utils.Log.Infof("delayed start for %d seconds", conf.Conf.DelayedStart) | |
time.Sleep(time.Duration(conf.Conf.DelayedStart) * time.Second) | |
} | |
bootstrap.InitOfflineDownloadTools() | |
bootstrap.LoadStorages() | |
bootstrap.InitTaskManager() | |
if !flags.Debug && !flags.Dev { | |
gin.SetMode(gin.ReleaseMode) | |
} | |
r := gin.New() | |
r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out)) | |
server.Init(r) | |
var httpSrv, httpsSrv, unixSrv *http.Server | |
if conf.Conf.Scheme.HttpPort != -1 { | |
httpBase := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpPort) | |
utils.Log.Infof("start HTTP server @ %s", httpBase) | |
httpSrv = &http.Server{Addr: httpBase, Handler: r} | |
go func() { | |
err := httpSrv.ListenAndServe() | |
if err != nil && !errors.Is(err, http.ErrServerClosed) { | |
utils.Log.Fatalf("failed to start http: %s", err.Error()) | |
} | |
}() | |
} | |
if conf.Conf.Scheme.HttpsPort != -1 { | |
httpsBase := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpsPort) | |
utils.Log.Infof("start HTTPS server @ %s", httpsBase) | |
httpsSrv = &http.Server{Addr: httpsBase, Handler: r} | |
go func() { | |
err := httpsSrv.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) | |
if err != nil && !errors.Is(err, http.ErrServerClosed) { | |
utils.Log.Fatalf("failed to start https: %s", err.Error()) | |
} | |
}() | |
} | |
if conf.Conf.Scheme.UnixFile != "" { | |
utils.Log.Infof("start unix server @ %s", conf.Conf.Scheme.UnixFile) | |
unixSrv = &http.Server{Handler: r} | |
go func() { | |
listener, err := net.Listen("unix", conf.Conf.Scheme.UnixFile) | |
if err != nil { | |
utils.Log.Fatalf("failed to listen unix: %+v", err) | |
} | |
// set socket file permission | |
mode, err := strconv.ParseUint(conf.Conf.Scheme.UnixFilePerm, 8, 32) | |
if err != nil { | |
utils.Log.Errorf("failed to parse socket file permission: %+v", err) | |
} else { | |
err = os.Chmod(conf.Conf.Scheme.UnixFile, os.FileMode(mode)) | |
if err != nil { | |
utils.Log.Errorf("failed to chmod socket file: %+v", err) | |
} | |
} | |
err = unixSrv.Serve(listener) | |
if err != nil && !errors.Is(err, http.ErrServerClosed) { | |
utils.Log.Fatalf("failed to start unix: %s", err.Error()) | |
} | |
}() | |
} | |
if conf.Conf.S3.Port != -1 && conf.Conf.S3.Enable { | |
s3r := gin.New() | |
s3r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out)) | |
server.InitS3(s3r) | |
s3Base := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.S3.Port) | |
utils.Log.Infof("start S3 server @ %s", s3Base) | |
go func() { | |
var err error | |
if conf.Conf.S3.SSL { | |
httpsSrv = &http.Server{Addr: s3Base, Handler: s3r} | |
err = httpsSrv.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) | |
} | |
if !conf.Conf.S3.SSL { | |
httpSrv = &http.Server{Addr: s3Base, Handler: s3r} | |
err = httpSrv.ListenAndServe() | |
} | |
if err != nil && !errors.Is(err, http.ErrServerClosed) { | |
utils.Log.Fatalf("failed to start s3 server: %s", err.Error()) | |
} | |
}() | |
} | |
// Wait for interrupt signal to gracefully shutdown the server with | |
// a timeout of 1 second. | |
quit := make(chan os.Signal, 1) | |
// kill (no param) default send syscanll.SIGTERM | |
// kill -2 is syscall.SIGINT | |
// kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it | |
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) | |
<-quit | |
utils.Log.Println("Shutdown server...") | |
Release() | |
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | |
defer cancel() | |
var wg sync.WaitGroup | |
if conf.Conf.Scheme.HttpPort != -1 { | |
wg.Add(1) | |
go func() { | |
defer wg.Done() | |
if err := httpSrv.Shutdown(ctx); err != nil { | |
utils.Log.Fatal("HTTP server shutdown err: ", err) | |
} | |
}() | |
} | |
if conf.Conf.Scheme.HttpsPort != -1 { | |
wg.Add(1) | |
go func() { | |
defer wg.Done() | |
if err := httpsSrv.Shutdown(ctx); err != nil { | |
utils.Log.Fatal("HTTPS server shutdown err: ", err) | |
} | |
}() | |
} | |
if conf.Conf.Scheme.UnixFile != "" { | |
wg.Add(1) | |
go func() { | |
defer wg.Done() | |
if err := unixSrv.Shutdown(ctx); err != nil { | |
utils.Log.Fatal("Unix server shutdown err: ", err) | |
} | |
}() | |
} | |
wg.Wait() | |
utils.Log.Println("Server exit") | |
}, | |
} | |
func init() { | |
RootCmd.AddCommand(ServerCmd) | |
// Here you will define your flags and configuration settings. | |
// Cobra supports Persistent Flags which will work for this command | |
// and all subcommands, e.g.: | |
// serverCmd.PersistentFlags().String("foo", "", "A help for foo") | |
// Cobra supports local flags which will only run when this command | |
// is called directly, e.g.: | |
// serverCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | |
} | |
// OutAlistInit 暴露用于外部启动server的函数 | |
func OutAlistInit() { | |
var ( | |
cmd *cobra.Command | |
args []string | |
) | |
ServerCmd.Run(cmd, args) | |
} | |