diff --git a/Dockerfile b/Dockerfile index 889d8a92..5d768a79 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,4 +7,4 @@ RUN CGO_ENABLED=0 go build -o /app/fsb -ldflags="-w -s" ./cmd/fsb FROM scratch COPY --from=builder /app/fsb /app/fsb EXPOSE ${PORT} -ENTRYPOINT ["/app/fsb"] \ No newline at end of file +ENTRYPOINT ["/app/fsb", "run"] \ No newline at end of file diff --git a/README.md b/README.md index 99693f4d..47978798 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ - Extract the zip file to a folder. - Create an a file named `fsb.env` and add all the variables there (see `fsb.sample.env` file for reference). - Give the executable file permission to execute using the command `chmod +x fsb` (Not required for windows). -- Run the bot using `./fsb` command. ( `./fsb.exe` for windows) +- Run the bot using `./fsb run` command. ( `./fsb.exe run` for windows)
@@ -124,7 +124,7 @@ chmod +x fsb mv fsb.sample.env fsb.env nano fsb.env # (add your environment variables, see the next section for more info) -./fsb +./fsb run ``` and to stop the program, @@ -142,7 +142,7 @@ go build ./cmd/fsb/ Rename-Item -LiteralPath ".\fsb.sample.env" -NewName ".\fsb.env" notepad fsb.env # (add your environment variables, see the next section for more info) -.\fsb +.\fsb run ``` and to stop the program, diff --git a/cmd/fsb/main.go b/cmd/fsb/main.go index dff81a40..2e9eaf4e 100644 --- a/cmd/fsb/main.go +++ b/cmd/fsb/main.go @@ -2,64 +2,35 @@ package main import ( "EverythingSuckz/fsb/config" - "EverythingSuckz/fsb/internal/bot" - "EverythingSuckz/fsb/internal/cache" - "EverythingSuckz/fsb/internal/routes" - "EverythingSuckz/fsb/internal/types" - "EverythingSuckz/fsb/internal/utils" "fmt" - "net/http" - "time" + "os" - "github.com/gin-gonic/gin" - "go.uber.org/zap" + "github.com/spf13/cobra" ) const versionString = "3.0.0-alpha1" -var startTime time.Time = time.Now() - -func main() { - utils.InitLogger() - log := utils.Logger - mainLogger := log.Named("Main") - mainLogger.Info("Starting server") - config.Load(log) - router := getRouter(log) - - _, err := bot.StartClient(log) - if err != nil { - log.Info(err.Error()) - return - } - cache.InitCache(log) - bot.StartWorkers(log) - bot.StartUserBot(log) - mainLogger.Info("Server started", zap.Int("port", config.ValueOf.Port)) - mainLogger.Info("File Stream Bot", zap.String("version", versionString)) - err = router.Run(fmt.Sprintf(":%d", config.ValueOf.Port)) - if err != nil { - mainLogger.Sugar().Fatalln(err) - } +var rootCmd = &cobra.Command{ + Use: "fsb [command]", + Short: "Telegram File Stream Bot", + Long: "Telegram Bot to generate direct streamable links for telegram media.", + Example: "fsb run --port 8080", + Version: versionString, + CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true}, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} +func init() { + config.SetFlagsFromConfig(runCmd) + rootCmd.AddCommand(runCmd) + rootCmd.SetVersionTemplate(fmt.Sprintf(`Telegram File Stream Bot version %s`, versionString)) } -func getRouter(log *zap.Logger) *gin.Engine { - if config.ValueOf.Dev { - gin.SetMode(gin.DebugMode) - } else { - gin.SetMode(gin.ReleaseMode) +func main() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) } - router := gin.Default() - router.Use(gin.ErrorLogger()) - router.GET("/", func(ctx *gin.Context) { - ctx.JSON(http.StatusOK, types.RootResponse{ - Message: "Server is running.", - Ok: true, - Uptime: utils.TimeFormat(uint64(time.Since(startTime).Seconds())), - Version: versionString, - }) - }) - routes.Load(log, router) - return router } diff --git a/cmd/fsb/run.go b/cmd/fsb/run.go new file mode 100644 index 00000000..b5655b5e --- /dev/null +++ b/cmd/fsb/run.go @@ -0,0 +1,72 @@ +package main + +import ( + "EverythingSuckz/fsb/config" + "EverythingSuckz/fsb/internal/bot" + "EverythingSuckz/fsb/internal/cache" + "EverythingSuckz/fsb/internal/routes" + "EverythingSuckz/fsb/internal/types" + "EverythingSuckz/fsb/internal/utils" + "fmt" + "net/http" + "time" + + "github.com/spf13/cobra" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +var runCmd = &cobra.Command{ + Use: "run", + Short: "Run the bot with the given configuration.", + DisableSuggestions: false, + Run: runApp, +} + +var startTime time.Time = time.Now() + +func runApp(cmd *cobra.Command, args []string) { + utils.InitLogger() + log := utils.Logger + mainLogger := log.Named("Main") + mainLogger.Info("Starting server") + config.Load(log, cmd) + router := getRouter(log) + + _, err := bot.StartClient(log) + if err != nil { + log.Info(err.Error()) + return + } + cache.InitCache(log) + bot.StartWorkers(log) + bot.StartUserBot(log) + mainLogger.Info("Server started", zap.Int("port", config.ValueOf.Port)) + mainLogger.Info("File Stream Bot", zap.String("version", versionString)) + err = router.Run(fmt.Sprintf(":%d", config.ValueOf.Port)) + if err != nil { + mainLogger.Sugar().Fatalln(err) + } + +} + +func getRouter(log *zap.Logger) *gin.Engine { + if config.ValueOf.Dev { + gin.SetMode(gin.DebugMode) + } else { + gin.SetMode(gin.ReleaseMode) + } + router := gin.Default() + router.Use(gin.ErrorLogger()) + router.GET("/", func(ctx *gin.Context) { + ctx.JSON(http.StatusOK, types.RootResponse{ + Message: "Server is running.", + Ok: true, + Uptime: utils.TimeFormat(uint64(time.Since(startTime).Seconds())), + Version: versionString, + }) + }) + routes.Load(log, router) + return router +} diff --git a/config/config.go b/config/config.go index 51845eb8..13688c25 100644 --- a/config/config.go +++ b/config/config.go @@ -10,6 +10,7 @@ import ( "github.com/joho/godotenv" "github.com/kelseyhightower/envconfig" + "github.com/spf13/cobra" "go.uber.org/zap" ) @@ -31,7 +32,7 @@ type config struct { var botTokenRegex = regexp.MustCompile(`MULTI\_TOKEN\d+=(.*)`) -func (c *config) setupEnvVars(log *zap.Logger) { +func (c *config) loadFromEnvFile(log *zap.Logger) { envPath := filepath.Clean("fsb.env") log.Sugar().Infof("Trying to load ENV vars from %s", envPath) err := godotenv.Load(envPath) @@ -45,7 +46,74 @@ func (c *config) setupEnvVars(log *zap.Logger) { log.Fatal("Unknown error while parsing env file.", zap.Error(err)) } } - err = envconfig.Process("", c) +} + +func SetFlagsFromConfig(cmd *cobra.Command) { + cmd.Flags().Int32("api-id", ValueOf.ApiID, "Telegram API ID") + cmd.Flags().String("api-hash", ValueOf.ApiHash, "Telegram API Hash") + cmd.Flags().String("bot-token", ValueOf.BotToken, "Telegram Bot Token") + cmd.Flags().Int64("log-channel", ValueOf.LogChannelID, "Telegram Log Channel ID") + cmd.Flags().Bool("dev", ValueOf.Dev, "Enable development mode") + cmd.Flags().IntP("port", "p", ValueOf.Port, "Server port") + cmd.Flags().String("host", ValueOf.Host, "Server host that will be included in links") + cmd.Flags().Int("hash-length", ValueOf.HashLength, "Hash length in links") + cmd.Flags().Bool("use-session-file", ValueOf.UseSessionFile, "Use session files") + cmd.Flags().String("user-session", ValueOf.UserSession, "Pyrogram user session") + cmd.Flags().String("multi-token-txt-file", "", "Multi token txt file (Not implemented)") +} + +func (c *config) loadConfigFromArgs(log *zap.Logger, cmd *cobra.Command) { + apiID, _ := cmd.Flags().GetInt32("api-id") + if apiID != 0 { + os.Setenv("API_ID", strconv.Itoa(int(apiID))) + } + apiHash, _ := cmd.Flags().GetString("api-hash") + if apiHash != "" { + os.Setenv("API_HASH", apiHash) + } + botToken, _ := cmd.Flags().GetString("bot-token") + if botToken != "" { + os.Setenv("BOT_TOKEN", botToken) + } + logChannelID, _ := cmd.Flags().GetString("log-channel") + if logChannelID != "" { + os.Setenv("LOG_CHANNEL", logChannelID) + } + dev, _ := cmd.Flags().GetBool("dev") + if dev { + os.Setenv("DEV", strconv.FormatBool(dev)) + } + port, _ := cmd.Flags().GetInt("port") + if port != 0 { + os.Setenv("PORT", strconv.Itoa(port)) + } + host, _ := cmd.Flags().GetString("host") + if host != "" { + os.Setenv("HOST", host) + } + hashLength, _ := cmd.Flags().GetInt("hash-length") + if hashLength != 0 { + os.Setenv("HASH_LENGTH", strconv.Itoa(hashLength)) + } + useSessionFile, _ := cmd.Flags().GetBool("use-session-file") + if useSessionFile { + os.Setenv("USE_SESSION_FILE", strconv.FormatBool(useSessionFile)) + } + userSession, _ := cmd.Flags().GetString("user-session") + if userSession != "" { + os.Setenv("USER_SESSION", userSession) + } + multiTokens, _ := cmd.Flags().GetString("multi-token-txt-file") + if multiTokens != "" { + os.Setenv("MULTI_TOKEN_TXT_FILE", multiTokens) + // TODO: Add support for importing tokens from a separate file + } +} + +func (c *config) setupEnvVars(log *zap.Logger, cmd *cobra.Command) { + c.loadFromEnvFile(log) + c.loadConfigFromArgs(log, cmd) + err := envconfig.Process("", c) if err != nil { log.Fatal("Error while parsing env variables", zap.Error(err)) } @@ -58,10 +126,10 @@ func (c *config) setupEnvVars(log *zap.Logger) { val.FieldByName("MultiTokens").Set(reflect.ValueOf(c.MultiTokens)) } -func Load(log *zap.Logger) { +func Load(log *zap.Logger, cmd *cobra.Command) { log = log.Named("Config") defer log.Info("Loaded config") - ValueOf.setupEnvVars(log) + ValueOf.setupEnvVars(log, cmd) ValueOf.LogChannelID = int64(stripInt(log, int(ValueOf.LogChannelID))) if ValueOf.HashLength == 0 { log.Sugar().Info("HASH_LENGTH can't be 0, defaulting to 6") diff --git a/go.mod b/go.mod index aaaa3fc5..77bf5869 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/joho/godotenv v1.5.1 github.com/kelseyhightower/envconfig v1.4.0 github.com/quantumsheep/range-parser v1.1.0 + github.com/spf13/cobra v1.8.0 ) require ( @@ -24,12 +25,14 @@ require ( github.com/google/uuid v1.4.0 // indirect github.com/gotd/ige v0.2.2 // indirect github.com/gotd/neo v0.1.5 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/segmentio/asm v1.2.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect go.uber.org/atomic v1.11.0 // indirect diff --git a/go.sum b/go.sum index 65bdce58..cf0fb2a8 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,7 @@ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhD github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/coocood/freecache v1.2.4 h1:UdR6Yz/X1HW4fZOuH0Z94KwG851GWOSknua5VUbb/5M= github.com/coocood/freecache v1.2.4/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -61,6 +62,8 @@ github.com/gotd/neo v0.1.5 h1:oj0iQfMbGClP8xI59x7fE/uHoTJD7NZH9oV1WNuPukQ= github.com/gotd/neo v0.1.5/go.mod h1:9A2a4bn9zL6FADufBdt7tZt+WMhvZoc5gWXihOPoiBQ= github.com/gotd/td v0.89.0 h1:qRWbTmPYk5y/u4gNAj9qIkLJlQgdMGr4HzW2ix1Q2hA= github.com/gotd/td v0.89.0/go.mod h1:NgvwaHPW8rAHPGjaKSKzwSe+N2cUWTmfaDs8P6HPp/U= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -99,8 +102,13 @@ github.com/quantumsheep/range-parser v1.1.0 h1:k4f1F58f8FF54FBYc9dYBRM+8JkAxFo11 github.com/quantumsheep/range-parser v1.1.0/go.mod h1:acv4Vt2PvpGvRsvGju7Gk2ahKluZJsIUNR69W53J22I= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=