443 lines
14 KiB
Go
443 lines
14 KiB
Go
package configs
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"trbot/utils/yaml"
|
|
|
|
"github.com/joho/godotenv"
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/pkgerrors"
|
|
)
|
|
|
|
func InitBot() (context.Context, context.CancelFunc, zerolog.Logger) {
|
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
|
|
|
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack // set stack trace func
|
|
logger := zerolog.New(zerolog.ConsoleWriter{ Out: os.Stdout, TimeFormat: "15:04:05"}).With().Timestamp().Logger()
|
|
|
|
godotenv.Load()
|
|
|
|
var cfg config
|
|
|
|
/* read config file */ {
|
|
configPath := os.Getenv("CONFIG_PATH")
|
|
configDir := os.Getenv("CONFIG_DIR")
|
|
if configPath != "" {
|
|
// 检查配置文件是否存在
|
|
if _, err := os.Stat(configPath); err != nil {
|
|
if os.IsNotExist(err) {
|
|
// 如果配置文件不存在,就以默认配置的方式创建一份
|
|
logger.Warn().
|
|
Str("configPath", configPath).
|
|
Msg("The config file does not exist. creating a default config file...")
|
|
err = yaml.SaveYAML(configPath, BotConfig)
|
|
if err != nil {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Msg("Failed to create default config file")
|
|
} else {
|
|
logger.Warn().
|
|
Str("configPath", configPath).
|
|
Msg("The default config file is created, please fill the bot token and restart")
|
|
}
|
|
} else {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("configPath", configPath).
|
|
Msg("Failed to read config file info")
|
|
}
|
|
}
|
|
|
|
// 读取配置文件
|
|
ConfigPath = configPath
|
|
err := yaml.LoadYAML(configPath, &cfg)
|
|
if err != nil {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("configPath", configPath).
|
|
Msg("Failed to read config file")
|
|
} else {
|
|
logger.Info().Msg("Read config success from `CONFIG_PATH` environment")
|
|
}
|
|
} else if configDir != "" {
|
|
if _, err := os.Stat(configDir); err != nil {
|
|
if os.IsNotExist(err) {
|
|
logger.Warn().
|
|
Str("configDir", configDir).
|
|
Msg("The config directory does not exist, creating...")
|
|
err = os.MkdirAll(configDir, 0755)
|
|
if err != nil {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("configDir", configDir).
|
|
Msg("Failed to create config directory")
|
|
}
|
|
} else {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("configDir", configDir).
|
|
Msg("Failed to read config directory info")
|
|
}
|
|
}
|
|
|
|
// 使用默认的配置文件名,把目标配置文件路径补全
|
|
targetConfigPath := filepath.Join(configDir, "config.yaml")
|
|
|
|
// 检查目录配置文件是否存在
|
|
if _, err := os.Stat(targetConfigPath); err != nil {
|
|
if os.IsNotExist(err) {
|
|
// 用户指定目录的话,还是不创建配置文件了,提示用户想要自定义配置文件名的话,需要设定另外一个环境变量
|
|
logger.Fatal().
|
|
Str("configDir", configDir).
|
|
Msg("No config file named `config.yaml` was found in this directory, If you want to set a specific config file name, set the `CONFIG_PATH` environment variable")
|
|
} else {
|
|
// 读取目标配置文件路径时的其他错误
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("targetConfigPath", targetConfigPath).
|
|
Msg("Failed to read target config file info")
|
|
}
|
|
}
|
|
|
|
// 读取配置文件
|
|
ConfigPath = configPath
|
|
err := yaml.LoadYAML(targetConfigPath, &cfg)
|
|
if err != nil {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("targetConfigPath", targetConfigPath).
|
|
Msg("Failed to read config file")
|
|
} else {
|
|
logger.Info().Msg("Read config file success from `CONFIG_DIR` environment")
|
|
}
|
|
} else {
|
|
// 没有指定任何环境变量,就读取默认的路径
|
|
if _, err := os.Stat(ConfigPath); err != nil {
|
|
if os.IsNotExist(err) {
|
|
// 如果配置文件不存在,就以默认配置的方式创建一份
|
|
logger.Warn().
|
|
Str("defaultConfigPath", ConfigPath).
|
|
Msg("The default config file does not exist. creating a default config file...")
|
|
err = yaml.SaveYAML(ConfigPath, BotConfig)
|
|
if err != nil {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("defaultConfigPath", ConfigPath).
|
|
Msg("Failed to create default config file")
|
|
} else {
|
|
logger.Warn().
|
|
Str("defaultConfigPath", ConfigPath).
|
|
Msg("The default config file is created, please fill the bot token and restart")
|
|
}
|
|
} else {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("defaultConfigPath", ConfigPath).
|
|
Msg("Failed to read default config file")
|
|
}
|
|
}
|
|
|
|
err := yaml.LoadYAML(ConfigPath, &cfg)
|
|
if err != nil {
|
|
logger.Fatal().
|
|
Err(err).
|
|
Str("defaultConfigPath", ConfigPath).
|
|
Msg("Failed to read default config file")
|
|
} else {
|
|
logger.Info().Msg("Read config file success")
|
|
}
|
|
}
|
|
}
|
|
|
|
/* logger */ {
|
|
if os.Getenv("DEBUG") != "" {
|
|
BotConfig.LogLevel = "debug"
|
|
logger.Warn().
|
|
Msg("Get `DEBUG` flag from environment, set log level to `debug`")
|
|
} else {
|
|
logLevel := os.Getenv("LOG_LEVEL")
|
|
if logLevel != "" {
|
|
BotConfig.LogLevel = logLevel
|
|
logger.Info().
|
|
Str("LogLevel", BotConfig.LogLevel).
|
|
Msg("Get log level from environment")
|
|
} else if cfg.LogLevel != "" {
|
|
BotConfig.LogLevel = cfg.LogLevel
|
|
logger.Info().
|
|
Str("LogLevel", BotConfig.LogLevel).
|
|
Msg("Get log level from config file")
|
|
} else {
|
|
logger.Info().
|
|
Str("LogLevel", BotConfig.LogLevel).
|
|
Msg("No log level config, use default level")
|
|
}
|
|
}
|
|
|
|
logFilePath := os.Getenv("LOG_FILE_PATH")
|
|
if logFilePath != "" {
|
|
BotConfig.LogFilePath = logFilePath
|
|
logger.Warn().
|
|
Str("LogFilePath", BotConfig.LogFilePath).
|
|
Msg("Get log file path from environment")
|
|
} else if cfg.LogFilePath != "" {
|
|
BotConfig.LogFilePath = cfg.LogFilePath
|
|
logger.Info().
|
|
Str("LogFilePath", BotConfig.LogFilePath).
|
|
Msg("Get log file path from config file")
|
|
} else {
|
|
logger.Info().
|
|
Str("LogFilePath", BotConfig.LogFilePath).
|
|
Msg("No log file path config, use default path")
|
|
}
|
|
|
|
if BotConfig.LogFilePath != "disable" {
|
|
logFileLevel := os.Getenv("LOG_FILE_LEVEL")
|
|
if logFileLevel != "" {
|
|
BotConfig.LogFileLevel = logFileLevel
|
|
logger.Info().
|
|
Str("LogFileLevel", BotConfig.LogFileLevel).
|
|
Msg("Get log file level from environment")
|
|
} else if cfg.LogFileLevel != "" {
|
|
BotConfig.LogFileLevel = cfg.LogFileLevel
|
|
logger.Info().
|
|
Str("LogFileLevel", BotConfig.LogFileLevel).
|
|
Msg("Get log file level from config file")
|
|
} else {
|
|
logger.Info().
|
|
Str("LogFileLevel", BotConfig.LogFileLevel).
|
|
Msg("No log file level config, use default level")
|
|
}
|
|
|
|
file, err := os.OpenFile(BotConfig.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
logger.Error().
|
|
Err(err).
|
|
Str("LogFilePath", BotConfig.LogFilePath).
|
|
Msg("Failed to open log file, use console log writer only")
|
|
} else {
|
|
logger = zerolog.New(zerolog.MultiLevelWriter(
|
|
&zerolog.ConsoleWriter{
|
|
Out: os.Stdout,
|
|
TimeFormat: "15:04:05",
|
|
},
|
|
&zerolog.FilteredLevelWriter{
|
|
Writer: zerolog.MultiLevelWriter(file),
|
|
Level: BotConfig.LevelForZeroLog(true),
|
|
},
|
|
)).With().Timestamp().Logger()
|
|
|
|
logger.Info().
|
|
Str("LogFilePath", BotConfig.LogFilePath).
|
|
Str("LogFileLevel", BotConfig.LogFileLevel).
|
|
Msg("Use mult log writer")
|
|
}
|
|
} else {
|
|
logger.Warn().Msg("LogFilePath is set to `disable`, use console log writer only")
|
|
}
|
|
|
|
logChatID := os.Getenv("LOG_CHAT_ID")
|
|
if logChatID != "" {
|
|
logChatID_int64, err := strconv.ParseInt(logChatID, 10, 64)
|
|
if err != nil {
|
|
logger.Error().
|
|
Err(err).
|
|
Str("LogChatID", logChatID).
|
|
Msg("Failed to parse log chat ID from environment")
|
|
} else {
|
|
BotConfig.LogChatID = logChatID_int64
|
|
}
|
|
logger.Warn().
|
|
Int64("LogChatID", BotConfig.LogChatID).
|
|
Msg("Get log chat ID from environment")
|
|
} else if cfg.LogChatID != 0 {
|
|
BotConfig.LogChatID = cfg.LogChatID
|
|
logger.Info().
|
|
Int64("LogChatID", BotConfig.LogChatID).
|
|
Msg("Get log chat id from config")
|
|
}
|
|
}
|
|
|
|
/* bot token and mode */ {
|
|
botToken := os.Getenv("BOT_TOKEN")
|
|
if botToken != "" {
|
|
BotConfig.BotToken = botToken
|
|
logger.Info().
|
|
Str("botTokenID", strings.Split(BotConfig.BotToken, ":")[0]).
|
|
Msg("Get token from environment")
|
|
} else if cfg.BotToken != "" {
|
|
BotConfig.BotToken = cfg.BotToken
|
|
logger.Info().
|
|
Str("botTokenID", strings.Split(BotConfig.BotToken, ":")[0]).
|
|
Msg("Get token from config file")
|
|
} else {
|
|
logger.Fatal().Msg("No bot token in environment, `.env` file and YAML config file, try create a bot from https://t.me/@botfather https://core.telegram.org/bots/tutorial#obtain-your-bot-token and fill it")
|
|
}
|
|
|
|
webhookURL := os.Getenv("WEBHOOK_URL")
|
|
if webhookURL != "" {
|
|
BotConfig.WebhookURL = webhookURL
|
|
logger.Warn().
|
|
Str("WebhookURL", BotConfig.WebhookURL).
|
|
Msg("Get Webhook URL from environment")
|
|
} else if cfg.WebhookURL != "" {
|
|
BotConfig.WebhookURL = cfg.WebhookURL
|
|
logger.Info().
|
|
Str("WebhookURL", BotConfig.WebhookURL).
|
|
Msg("Get Webhook URL from config file")
|
|
} else {
|
|
logger.Info().Msg("No Webhook URL in environment `.env` file and YAML config file, using getUpdate mode")
|
|
}
|
|
|
|
if BotConfig.WebhookURL != "" {
|
|
webhookAddress := os.Getenv("WEBHOOK_ADDR")
|
|
if webhookAddress != "" {
|
|
BotConfig.WebhookListenAddress = webhookAddress
|
|
logger.Warn().
|
|
Str("WebhookListenAddress", BotConfig.WebhookListenAddress).
|
|
Msg("Get Webhook Listen Address from environment")
|
|
} else if cfg.WebhookListenAddress != "" {
|
|
BotConfig.WebhookListenAddress = cfg.WebhookListenAddress
|
|
logger.Warn().
|
|
Str("WebhookListenAddress", BotConfig.WebhookListenAddress).
|
|
Msg("Get Webhook Listen Address from config file")
|
|
} else {
|
|
logger.Info().
|
|
Str("WebhookListenAddress", BotConfig.WebhookListenAddress).
|
|
Msg("Webhook listen address is not set, use default address")
|
|
}
|
|
}
|
|
|
|
if len(cfg.AllowedUpdates) != 0 {
|
|
BotConfig.AllowedUpdates = cfg.AllowedUpdates
|
|
logger.Warn().
|
|
Strs("AllowedUpdates", BotConfig.AllowedUpdates).
|
|
Msg("Allowed updates list is set")
|
|
} else {
|
|
logger.Info().Msg("Allowed updates list is empty, you will receive all updates except `chat_member`, `message_reaction` and `message_reaction_count`. See `allowed_updates` in https://core.telegram.org/bots/api#getting-updates for details")
|
|
}
|
|
|
|
if len(cfg.AdminIDs) != 0 {
|
|
BotConfig.AdminIDs = cfg.AdminIDs
|
|
logger.Info().
|
|
Ints64("AdminIDs", BotConfig.AdminIDs).
|
|
Msg("Admin ID list is set")
|
|
} else {
|
|
logger.Warn().
|
|
Msg("Admin ID list is not set, fill it in config file to use admin only features")
|
|
}
|
|
|
|
if cfg.InlineDefaultHandler != "" {
|
|
BotConfig.InlineDefaultHandler = cfg.InlineDefaultHandler
|
|
} else {
|
|
logger.Info().Msg("Inline default handler is not set, default show all commands")
|
|
}
|
|
|
|
if cfg.InlineSubCommandSymbol != "" {
|
|
BotConfig.InlineSubCommandSymbol = cfg.InlineSubCommandSymbol
|
|
} else {
|
|
logger.Info().
|
|
Str("SubCommandSymbol", BotConfig.InlineSubCommandSymbol).
|
|
Msg("Inline sub command symbol is not set, use default symbol")
|
|
}
|
|
|
|
if cfg.InlinePaginationSymbol != "" {
|
|
BotConfig.InlinePaginationSymbol = cfg.InlinePaginationSymbol
|
|
} else {
|
|
logger.Info().
|
|
Str("PaginationSymbol", BotConfig.InlinePaginationSymbol).
|
|
Msg("Inline pagination symbol is not set, use default symbol")
|
|
}
|
|
|
|
if cfg.InlineCategorySymbol != "" {
|
|
BotConfig.InlineCategorySymbol = cfg.InlineCategorySymbol
|
|
} else {
|
|
logger.Info().
|
|
Str("CategorySymbol", BotConfig.InlineCategorySymbol).
|
|
Msg("Inline category symbol is not set, use default symbol")
|
|
}
|
|
|
|
if cfg.InlineResultsPerPage != 0 {
|
|
if cfg.InlineResultsPerPage < 1 || cfg.InlineResultsPerPage > 50 {
|
|
logger.Warn().
|
|
Int("invalidNumber", BotConfig.InlineResultsPerPage).
|
|
Int("ResultsPerPage", cfg.InlineResultsPerPage).
|
|
Msg("Inline results per page number is invalid, use default number")
|
|
} else {
|
|
BotConfig.InlineResultsPerPage = cfg.InlineResultsPerPage
|
|
}
|
|
} else {
|
|
logger.Info().
|
|
Int("ResultsPerPage", BotConfig.InlineResultsPerPage).
|
|
Msg("Inline results per page number is not set, use default number")
|
|
}
|
|
|
|
logger.Info().
|
|
Str("DefaultHandler", BotConfig.InlineDefaultHandler).
|
|
Str("SubCommandSymbol", BotConfig.InlineSubCommandSymbol).
|
|
Str("CategorySymbol", BotConfig.InlineCategorySymbol).
|
|
Str("PaginationSymbol", BotConfig.InlinePaginationSymbol).
|
|
Int("ResultsPerPage", BotConfig.InlineResultsPerPage).
|
|
Msg("Inline mode config")
|
|
}
|
|
|
|
/* build info */ {
|
|
if BuildAt == "" {
|
|
logger.Warn().
|
|
Str("error", "Remind: You are using a version without build info").
|
|
Str("runtime", runtime.Version()).
|
|
Str("logLevel", BotConfig.LogLevel).
|
|
Msg("trbot")
|
|
} else {
|
|
logger.Info().
|
|
Str("commit", Commit).
|
|
Str("branch", Branch).
|
|
Str("version", Version).
|
|
Str("buildAt", BuildAt).
|
|
Str("buildOn", BuildOn).
|
|
Str("changes", Changes).
|
|
Str("runtime", runtime.Version()).
|
|
Str("logLevel", BotConfig.LogLevel).
|
|
Msg("trbot")
|
|
}
|
|
}
|
|
|
|
/* other */ {
|
|
if cfg.RedisURL != "" {
|
|
BotConfig.RedisURL = cfg.RedisURL
|
|
BotConfig.RedisPassword = cfg.RedisPassword
|
|
BotConfig.RedisDatabaseID = cfg.RedisDatabaseID
|
|
logger.Info().
|
|
Str("RedisURL", BotConfig.RedisURL).
|
|
Int("RedisDatabaseID", BotConfig.RedisDatabaseID).
|
|
Msg("Get Redis URL and Database ID from config")
|
|
}
|
|
|
|
FFmpegPath := os.Getenv("FFMPEG_PATH")
|
|
if FFmpegPath != "" {
|
|
BotConfig.FFmpegPath = FFmpegPath
|
|
logger.Info().
|
|
Str("FFmpegPath", BotConfig.FFmpegPath).
|
|
Msg("Get FFmpeg path from environment")
|
|
} else if cfg.FFmpegPath != "" {
|
|
BotConfig.FFmpegPath = cfg.FFmpegPath
|
|
logger.Info().
|
|
Str("FFmpegPath", BotConfig.FFmpegPath).
|
|
Msg("Get FFmpeg path from config")
|
|
} else {
|
|
logger.Warn().
|
|
Msg("No FFmpeg path in environment `.env` file and YAML config file, you will not be able to use some features that depend on it")
|
|
}
|
|
}
|
|
|
|
// attach logger into ctx
|
|
ctx = logger.WithContext(ctx)
|
|
|
|
return ctx, cancel, logger
|
|
}
|