cmd

package
v4.1.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2025 License: AGPL-3.0 Imports: 48 Imported by: 0

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

Copyright © 2023 NAME HERE <EMAIL ADDRESS>

Package cmd implements command-line functionality for OpenList

Index

Constants

View Source
const (
	// DefaultRandomPasswordLength defines the length of auto-generated passwords
	DefaultRandomPasswordLength = 12

	// AdminInfoMessage is displayed when showing admin information
	AdminInfoMessage = `` /* 196-byte string literal not displayed */

)

Constants for admin-related functionality

View Source
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
)
View Source
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 = `` /* 146-byte string literal not displayed */

)

Default CLI descriptions

View Source
const (
	// DefaultLogFileMode defines the permission for log files
	DefaultLogFileMode = 0600

	// DefaultPIDFileMode defines the permission for the PID file
	DefaultPIDFileMode = 0600
)

Variables

View Source
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(AdminInfoMessage, admin.Username)
	},
}

AdminCmd represents the admin command for managing administrator accounts

View Source
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("Two-factor authentication has been successfully disabled")
		DelAdminCacheOnline()
	},
}

Cancel2FACmd represents the command to disable two-factor authentication for the admin user

View Source
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

View Source
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

View Source
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

View Source
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) {

		newPassword := random.String(DefaultRandomPasswordLength)
		setAdminPassword(newPassword)
	},
}

RandomPasswordCmd generates a random password for the admin user

View Source
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

View Source
var RootCmd = &cobra.Command{
	Use:   "openlist",
	Short: ShortDescription,
	Long:  LongDescription,
}

RootCmd represents the base command when called without any subcommands

View Source
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()

		r.Use(middlewares.ErrorLogging())
		r.Use(
			gin.LoggerWithWriter(log.StandardLogger().Out),
			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)

			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)

			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)

			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(
				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)

			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)
				}
			}()
		}

		wg.Wait()
		utils.Log.Info("All servers successfully shut down")
	},
}

ServerCmd represents the server command that starts the OpenList server

View Source
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),
	Run: func(cmd *cobra.Command, args []string) {
		setAdminPassword(args[0])
	},
}

SetPasswordCmd sets a specific password for the admin user

View Source
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("Admin token: %s", token)
	},
}

ShowTokenCmd displays the admin authentication token

View Source
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

View Source
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

View Source
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 DelAdminCacheOnline

func DelAdminCacheOnline()

func DelUserCacheOnline

func DelUserCacheOnline(username string)

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 Init

func Init()

Init initializes the application

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

func Release

func Release()

Release performs cleanup operations before application shutdown

Types

type Drivers

type Drivers KV[KV[any]]

type KV

type KV[V any] map[string]V

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL