Documentation
¶
Overview ¶
Package cmd implements command-line functionality for OpenList
Package cmd implements command-line functionality for OpenList ¶
Package cmd implements command-line functionality for OpenList ¶
Package cmd implements command-line functionality for OpenList ¶
Package cmd Copyright © 2022 Noah Hsu<i@nn.ci>
Package cmd implements command-line functionality for OpenList ¶
Package cmd implements command-line functionality for OpenList ¶
Package cmd implements command-line functionality for OpenList ¶
Package cmd implements command-line functionality for OpenList ¶
Package cmd implements command-line functionality for OpenList ¶
Package cmd implements command-line functionality for OpenList
Index ¶
Constants ¶
const ( // DefaultRandomPasswordLength defines the length of auto-generated passwords DefaultRandomPasswordLength = 12 // AdminInfoMessage is displayed when showing admin information AdminInfoMessage = `` /* 254-byte string literal not displayed */ )
Constants for admin-related functionality
const ( // DaemonDirName is the directory name for daemon-related files DaemonDirName = "daemon" // PIDFileName is the name of the file storing the process ID PIDFileName = "pid" // DaemonDirPerm is the permission for the daemon directory DaemonDirPerm = 0700 )
const ( // ShortDescription is the short description shown in help text ShortDescription = "A file list program that supports multiple storage." // LongDescription is the long description shown in help text LongDescription = `` /* 142-byte string literal not displayed */ )
Default CLI descriptions
const ( // DefaultLogFileMode defines the permission for log files DefaultLogFileMode = 0600 // DefaultPIDFileMode defines the permission for the PID file DefaultPIDFileMode = 0600 )
Variables ¶
var AdminCmd = &cobra.Command{ Use: "admin", Aliases: []string{"password"}, Short: "Show and manage admin user information", Long: "Display admin user information and perform operations related to the admin password", Run: func(cmd *cobra.Command, args []string) { Init() defer Release() admin, err := op.GetAdmin() if err != nil { utils.Log.Errorf("failed to get admin user: %+v", err) return } utils.Log.Infof("get admin user from CLI") fmt.Printf(AdminInfoMessage, admin.Username) }, }
AdminCmd represents the admin command for managing administrator accounts
var Cancel2FACmd = &cobra.Command{ Use: "cancel2fa", Short: "Disable two-factor authentication for admin user", Long: "Remove the two-factor authentication configuration from the admin user's account", Run: func(cmd *cobra.Command, args []string) { Init() defer Release() admin, err := op.GetAdmin() if err != nil { utils.Log.Errorf("Failed to get admin user: %+v", err) return } if err := op.Cancel2FAByUser(admin); err != nil { utils.Log.Errorf("Failed to disable two-factor authentication: %+v", err) return } utils.Log.Info("2FA authentication has been successfully disabled") delAdminCacheOnline() }, }
Cancel2FACmd represents the command to disable two-factor authentication for the admin user
var CryptCmd = &cobra.Command{ Use: "crypt", Short: "Encrypt or decrypt local file or dir", Example: `openlist crypt -s ./src/encrypt/ --op=de --pwd=123456 --salt=345678`, Run: func(cmd *cobra.Command, args []string) { opt.validate() opt.cryptFileDir() }, }
CryptCmd represents the crypt command
var KillCmd = &cobra.Command{ Use: "kill", Short: "Force kill OpenList server process", Long: "Forcefully terminate the running OpenList server process using the PID from the daemon/pid file", Run: func(cmd *cobra.Command, args []string) { kill() }, }
KillCmd represents the command to forcefully terminate the OpenList server process
var LangCmd = &cobra.Command{ Use: "lang", Short: "Generate language json file", Run: func(cmd *cobra.Command, args []string) { frontendPath, _ = cmd.Flags().GetString("frontend-path") initialize.InitConfig() err := os.MkdirAll("lang", 0777) if err != nil { utils.Log.Fatalf("failed create folder: %s", err.Error()) } generateDriversJson() generateSettingsJson() }, }
LangCmd represents the lang command
var RandomPasswordCmd = &cobra.Command{ Use: "random", Short: "Reset admin user's password to a random string", Long: "Generate a secure random password and set it for the admin user", Run: func(cmd *cobra.Command, args []string) { utils.Log.Infof("reset admin user's password to a random string from CLI") newPassword := random.String(DefaultRandomPasswordLength) setAdminPassword(newPassword) }, }
RandomPasswordCmd generates a random password for the admin user
var RestartCmd = &cobra.Command{ Use: "restart", Short: "Restart the OpenList server", Long: `Restart the OpenList server by gracefully stopping the running instance and then starting a new instance as a background process.`, Run: func(cmd *cobra.Command, args []string) { log.Info("Restarting OpenList server...") stop() time.Sleep(1 * time.Second) start() log.Info("Restart operation completed") }, }
RestartCmd represents the command to restart the OpenList server
var RootCmd = &cobra.Command{ Use: "openlist", Short: ShortDescription, Long: LongDescription, }
RootCmd represents the base command when called without any subcommands
var ServerCmd = &cobra.Command{ Use: "server", Short: "Start the OpenList server", Long: `Start the OpenList server with HTTP, HTTPS, Unix socket, FTP, SFTP, and S3-compatible APIs as configured in the configuration file.`, Run: func(cmd *cobra.Command, args []string) { initialize.InitApp(true) if conf.Conf.DelayedStart > 0 { delaySeconds := conf.Conf.DelayedStart utils.Log.Infof("Configured delayed start: waiting for %d seconds before startup", delaySeconds) time.Sleep(time.Duration(delaySeconds) * time.Second) } if !global.Debug && !global.Dev { gin.SetMode(gin.ReleaseMode) utils.Log.Info("Running in production mode") } else if global.Debug { utils.Log.Info("Running in debug mode") } else if global.Dev { utils.Log.Info("Running in development mode") } r := gin.New() if conf.Conf.Log.Filter.Enable { r.Use(middlewares.FilteredLogger()) } else { r.Use(gin.LoggerWithWriter(log.StandardLogger().Out)) } r.Use( middlewares.ErrorLogging(), gin.RecoveryWithWriter(log.StandardLogger().Out), ) server.Init(r) // Configure HTTP handler with H2C support if enabled var httpHandler http.Handler = r if conf.Conf.Scheme.EnableH2c { utils.Log.Debug("Enabling H2C (HTTP/2 over cleartext) support") httpHandler = h2c.NewHandler(r, &http2.Server{}) } // Initialize server variables var httpSrv, httpsSrv, unixSrv *http.Server if conf.Conf.Scheme.HttpPort != -1 { httpAddr := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpPort) utils.Log.Infof("Starting HTTP server on %s", httpAddr) fmt.Printf("start HTTP server @ %s\n", httpAddr) httpSrv = &http.Server{ Addr: httpAddr, Handler: httpHandler, ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, IdleTimeout: 120 * time.Second, } go func() { if err := httpSrv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { utils.Log.Fatalf("Failed to start HTTP server: %v", err) } }() } if conf.Conf.Scheme.HttpsPort != -1 { httpsAddr := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpsPort) utils.Log.Infof("Starting HTTPS server on %s", httpsAddr) fmt.Printf("start HTTPS server @ %s\n", httpsAddr) if !utils.Exists(conf.Conf.Scheme.CertFile) || !utils.Exists(conf.Conf.Scheme.KeyFile) { utils.Log.Errorf("Certificate file or key file not found: %s, %s", conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) utils.Log.Warn("HTTPS server will not start due to missing certificate files") } else { httpsSrv = &http.Server{ Addr: httpsAddr, Handler: r, ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, IdleTimeout: 120 * time.Second, } go func() { if err := httpsSrv.ListenAndServeTLS( conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile, ); err != nil && !errors.Is(err, http.ErrServerClosed) { utils.Log.Fatalf("Failed to start HTTPS server: %v", err) } }() } } if conf.Conf.Scheme.UnixFile != "" { unixSocketPath := conf.Conf.Scheme.UnixFile utils.Log.Infof("Starting Unix socket server on %s", unixSocketPath) fmt.Printf("start unix server @ %s\n", conf.Conf.Scheme.UnixFile) if utils.Exists(unixSocketPath) { if err := os.Remove(unixSocketPath); err != nil { utils.Log.Warnf("Failed to remove existing Unix socket file: %v", err) } } unixSrv = &http.Server{ Handler: httpHandler, ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, IdleTimeout: 120 * time.Second, } go func() { listener, err := net.Listen("unix", unixSocketPath) if err != nil { utils.Log.Fatalf("Failed to create Unix socket listener: %v", err) return } mode, err := strconv.ParseUint(conf.Conf.Scheme.UnixFilePerm, 8, 32) if err != nil { utils.Log.Errorf("Failed to parse Unix socket file permission '%s': %v", conf.Conf.Scheme.UnixFilePerm, err) } else { if err = os.Chmod(unixSocketPath, os.FileMode(mode)); err != nil { utils.Log.Errorf("Failed to set Unix socket file permissions: %v", err) } else { utils.Log.Debugf("Set Unix socket file permissions to %s", conf.Conf.Scheme.UnixFilePerm) } } if err = unixSrv.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) { utils.Log.Fatalf("Failed to start Unix socket server: %v", err) } }() } if conf.Conf.S3.Port != -1 && conf.Conf.S3.Enable { s3Router := gin.New() s3Router.Use( middlewares.ErrorLogging(), gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out), ) server.InitS3(s3Router) s3Addr := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.S3.Port) utils.Log.Infof("Starting S3-compatible API server on %s (SSL: %v)", s3Addr, conf.Conf.S3.SSL) fmt.Printf("Starting S3-compatible API server on %s (SSL: %v)", s3Addr, conf.Conf.S3.SSL) go func() { var err error var s3Server *http.Server s3Server = &http.Server{ Addr: s3Addr, Handler: s3Router, ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, IdleTimeout: 120 * time.Second, } if conf.Conf.S3.SSL { if !utils.Exists(conf.Conf.Scheme.CertFile) || !utils.Exists(conf.Conf.Scheme.KeyFile) { utils.Log.Errorf("Certificate file or key file not found for S3 SSL: %s, %s", conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) utils.Log.Warn("S3 server will start without SSL despite configuration") err = s3Server.ListenAndServe() } else { err = s3Server.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) } } else { err = s3Server.ListenAndServe() } if err != nil && !errors.Is(err, http.ErrServerClosed) { utils.Log.Fatalf("Failed to start S3-compatible API server: %v", err) } }() } // Initialize FTP server components var ftpDriver *server.FtpMainDriver var ftpServer *ftpserver.FtpServer if conf.Conf.FTP.Listen != "" && conf.Conf.FTP.Enable { utils.Log.Info("Initializing FTP server...") // Create FTP driver var err error ftpDriver, err = server.NewMainDriver() if err != nil { utils.Log.Fatalf("Failed to initialize FTP driver: %v", err) } else { utils.Log.Infof("Starting FTP server on %s", conf.Conf.FTP.Listen) go func() { ftpServer = ftpserver.NewFtpServer(ftpDriver) if err := ftpServer.ListenAndServe(); err != nil { utils.Log.Fatalf("FTP server error: %v", err) } }() } } // Initialize SFTP server components var sftpDriver *server.SftpDriver var sftpServer *sftpd.SftpServer if conf.Conf.SFTP.Listen != "" && conf.Conf.SFTP.Enable { utils.Log.Info("Initializing SFTP server...") // Create SFTP driver var err error sftpDriver, err = server.NewSftpDriver() if err != nil { utils.Log.Fatalf("Failed to initialize SFTP driver: %v", err) } else { utils.Log.Infof("Starting SFTP server on %s", conf.Conf.SFTP.Listen) go func() { sftpServer = sftpd.NewSftpServer(sftpDriver) if err := sftpServer.RunServer(); err != nil { utils.Log.Fatalf("SFTP server error: %v", err) } }() } } quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit utils.Log.Info("Shutdown signal received, gracefully shutting down servers...") fs.ArchiveContentUploadTaskManager.RemoveAll() Release() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // Use WaitGroup to wait for all servers to shutdown var wg sync.WaitGroup if conf.Conf.Scheme.HttpPort != -1 && httpSrv != nil { wg.Add(1) go func() { defer wg.Done() utils.Log.Debug("Shutting down HTTP server...") if err := httpSrv.Shutdown(ctx); err != nil { utils.Log.Errorf("HTTP server shutdown error: %v", err) } }() } if conf.Conf.Scheme.HttpsPort != -1 && httpsSrv != nil { wg.Add(1) go func() { defer wg.Done() utils.Log.Debug("Shutting down HTTPS server...") if err := httpsSrv.Shutdown(ctx); err != nil { utils.Log.Errorf("HTTPS server shutdown error: %v", err) } }() } if conf.Conf.Scheme.UnixFile != "" && unixSrv != nil { wg.Add(1) go func() { defer wg.Done() utils.Log.Debug("Shutting down Unix socket server...") if err := unixSrv.Shutdown(ctx); err != nil { utils.Log.Errorf("Unix server shutdown error: %v", err) } }() } if conf.Conf.FTP.Listen != "" && conf.Conf.FTP.Enable && ftpServer != nil && ftpDriver != nil { wg.Add(1) go func() { defer wg.Done() utils.Log.Debug("Shutting down FTP server...") ftpDriver.Stop() if err := ftpServer.Stop(); err != nil { utils.Log.Errorf("FTP server shutdown error: %v", err) } }() } if conf.Conf.SFTP.Listen != "" && conf.Conf.SFTP.Enable && sftpServer != nil && sftpDriver != nil { wg.Add(1) go func() { defer wg.Done() utils.Log.Debug("Shutting down SFTP server...") if err := sftpServer.Close(); err != nil { utils.Log.Errorf("SFTP server shutdown error: %v", err) } }() } <-global.CronConfig.Stop().Done() wg.Wait() utils.Log.Info("All servers successfully shut down") }, }
ServerCmd represents the server command that starts the OpenList server
var SetPasswordCmd = &cobra.Command{ Use: "set NEW_PASSWORD", Short: "Set admin user's password", Long: "Set a specific password for the admin user", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return errors.New("please enter the new password") } setAdminPassword(args[0]) return nil }, }
SetPasswordCmd sets a specific password for the admin user
var ShowTokenCmd = &cobra.Command{ Use: "token", Short: "Show admin token", Long: "Display the authentication token used for admin API access", Run: func(cmd *cobra.Command, args []string) { Init() defer Release() token := setting.GetStr(consts.Token) utils.Log.Infof("show admin token from CLI") fmt.Println("Admin token:", token) }, }
ShowTokenCmd displays the admin authentication token
var StartCmd = &cobra.Command{ Use: "start", Short: "Start OpenList server as a background process", Long: `Start the OpenList server as a background daemon process. This command automatically uses '--force-bin-dir' to ensure the server uses the binary's directory as the data directory.`, Run: func(cmd *cobra.Command, args []string) { start() }, }
StartCmd represents the command to start the OpenList server as a background process
var StopCmd = &cobra.Command{ Use: "stop", Short: "Stop openlist server by daemon/pid file", Run: func(cmd *cobra.Command, args []string) { stop() }, }
StopCmd represents the stop command
var VersionCmd = &cobra.Command{ Use: "version", Short: "Show current version of OpenList", Long: "Display detailed version information about the OpenList build", Run: func(cmd *cobra.Command, args []string) { goVersion := fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH) fmt.Printf(versionTemplate, conf.Version, conf.WebVersion, conf.BuiltAt, goVersion, conf.GitCommit, conf.GitAuthor, ) os.Exit(0) }, }
VersionCmd represents the version command
Functions ¶
func Execute ¶
func Execute()
Execute adds all child commands to the root command and sets flags appropriately. This is called by main.main(). It only needs to happen once to the rootCmd.
func OutOpenListInit ¶
func OutOpenListInit()
OutOpenListInit provides a public function to start the server from external code This can be used by other packages to initialize the OpenList server