package main import ( "errors" "fmt" tgbot "github.com/go-telegram-bot-api/telegram-bot-api" "github.com/umputun/go-flags" "io/ioutil" "log" "net/http" "os" "strconv" "strings" "valera/commands" "valera/db" ) var ( workoutTypes = []string{ "Отжимания", "Пресс", } ) const ( version = "v1.4.0" ) type Opts struct { Token string `short:"t" long:"token" description:"Telegram api token"` Name string `short:"n" long:"name" description:"Telegram bot name" default:"@body_weight_loss_bot"` } var opts Opts func readFile(filename string) (string, error) { b, err := ioutil.ReadFile(filename) if err != nil { return "", err } str := string(b) return str, nil } func main() { run() } func run() { p := flags.NewParser(&opts, flags.PrintErrors|flags.PassDoubleDash|flags.HelpFlag) p.SubcommandsOptional = true if _, err := p.Parse(); err != nil { if err.(*flags.Error).Type != flags.ErrHelp { log.Println(errors.New("[ERROR] cli error: " + err.Error())) } os.Exit(2) } if opts.Token == "" { token, err := readFile("token.txt") if err != nil { panic(err) } opts.Token = strings.ReplaceAll(token, "\n", "") } fmt.Println(opts.Token) bot, err := tgbot.NewBotAPI(opts.Token) if err != nil { panic(err) } mongoURL, err := readFile("mongo_url.txt") if err != nil { panic(err) } mongoURL = strings.ReplaceAll(mongoURL, "\n", "") fmt.Println(mongoURL) dbName, err := readFile("db_name.txt") if err != nil { panic(err) } dbName = strings.ReplaceAll(dbName, "\n", "") fmt.Println(dbName) dataBase := db.NewDB( mongoURL, dbName, ) u := tgbot.NewUpdate(0) u.Timeout = 60 updates, err := bot.GetUpdatesChan(u) if err != nil { panic(err) } go func() { http.HandleFunc("/go", func(w http.ResponseWriter, r *http.Request) { chats, err := dataBase.GetAllChats() if err != nil { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _, _ = fmt.Fprintf(w, `{"result":"error"}`) return } for _, chatID := range chats { sendGoToChat(bot, dataBase, chatID) } w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = fmt.Fprintf(w, `{"result":"ok"}`) }) http.HandleFunc("/stat", func(w http.ResponseWriter, r *http.Request) { chats, err := dataBase.GetAllChats() if err != nil { fmt.Println(err) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _, _ = fmt.Fprintf(w, `{"result":"error"}`) return } for _, chatID := range chats { if err := sendStatToChat(bot, dataBase, chatID, "Напоминаю:\n- Cегодня больше не жрем!\n\n"); err != nil { fmt.Println(err) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _, _ = fmt.Fprintf(w, `{"result":"error"}`) return } } w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = fmt.Fprintf(w, `{"result":"ok"}`) }) port := ":10002" log.Println("Server is start up! port", port) log.Fatal(http.ListenAndServe(port, nil)) }() log.Println("Run", opts.Name) for update := range updates { if update.Message == nil { continue } text := update.Message.Text chatID := update.Message.Chat.ID username := update.Message.From.UserName userInfoDTO, err := dataBase.GetChatInfo(chatID) if err != nil { log.Println(err) continue } isWorkout := false for _, workoutType := range workoutTypes { if userInfoDTO.GetStatus() == db.UserState(workoutType) { count, err := strconv.Atoi(text) if err != nil { log.Println(err) continue } if err := dataBase.AddWorkout(chatID, db.NewWorkout(workoutType, count, username)); err != nil { log.Println(err) continue } msgText := fmt.Sprintf("Отлично, %s, записал.", text) if count <= 0 { msgText = "Плохо, хочешь быть толстым и не красивым?" } _, _ = bot.Send(tgbot.NewMessage(chatID, msgText)) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } isWorkout = true break } } if isWorkout { continue } switch userInfoDTO.GetStatus() { case db.UserStateGo: if err := dataBase.SetStatusToChat(chatID, db.UserState(text)); err != nil { log.Println(err) } msg := tgbot.NewMessage(chatID, fmt.Sprintf("%s, отпишись сколько раз ты выполнил упражнение", text)) msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false) _, _ = bot.Send(msg) continue case db.UserStateEat: count, err := strconv.Atoi(text) if err != nil { log.Println(err) continue } if err := dataBase.AddCalories(chatID, db.NewCalories(count, username)); err != nil { log.Println(err) continue } if count <= 0 { _, _ = bot.Send(tgbot.NewMessage(chatID, "Все фигня, давай по новой")) continue } _, _ = bot.Send(tgbot.NewMessage(chatID, fmt.Sprintf("Калории, фу, %s, записал.", text))) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } continue } command := commands.Command(strings.Replace(text, opts.Name, "", 1)) switch command { case commands.Start: _, _ = bot.Send(tgbot.NewMessage(chatID, fmt.Sprintf("Здорова, я Валера (%s), твой тренер (%d).", version, chatID))) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } case commands.Help: _, _ = bot.Send(tgbot.NewMessage(chatID, "Вот что я умею:\n\n1) Предлагать размяться\n2) Показывать статистику\n3) Считать калории")) case commands.Ping: _, _ = bot.Send(tgbot.NewMessage(chatID, "pong")) case commands.Go: sendGoToChat(bot, dataBase, chatID) case commands.Stat: if err := sendStatToChat(bot, dataBase, chatID, ""); err != nil { fmt.Println(err) continue } case commands.Eat: if _, err := bot.Send(tgbot.NewMessage(chatID, "Вижу ты поел, отпишись сколько калорий было")); err == nil { if err := dataBase.SetStatusToChat(chatID, db.UserStateEat); err != nil { log.Println(err) } } } } } func sendGoToChat(bot *tgbot.BotAPI, dataBase *db.DB, chatID int64) { msg := tgbot.NewMessage(chatID, "Давай немного разомнемся, выбирай:") row := tgbot.NewKeyboardButtonRow() for _, workoutType := range workoutTypes { row = append(row, tgbot.NewKeyboardButton(workoutType)) } msg.ReplyMarkup = tgbot.NewReplyKeyboard(row) if _, err := bot.Send(msg); err == nil { if err := dataBase.SetStatusToChat(chatID, db.UserStateGo); err != nil { log.Println(err) } } } func sendStatToChat(bot *tgbot.BotAPI, dataBase *db.DB, chatID int64, prefix string) error { stat, err := dataBase.GetStat(chatID) if err != nil { return err } msgText := prefix + "Результаты за сегодня:\n" for k, v := range stat { msgText += fmt.Sprintf("- %s: %d\n", k, v) } _, _ = bot.Send(tgbot.NewMessage(chatID, msgText)) return nil }