~mendelmaleh/tg_mcstatusbot

0b71049222aa3d338676f764376c4e6e80913bee — Mendel E 5 months ago
Initial commit
2 files changed, 216 insertions(+), 0 deletions(-)

A .gitignore
A main.go
A  => .gitignore +3 -0
@@ 1,3 @@
config.toml
notes.md
db/

A  => main.go +213 -0
@@ 1,213 @@
package main

import (
	"encoding/binary"
	"fmt"
	"html"
	"io/ioutil"
	"log"
	"strings"

	"git.sr.ht/~mendelmaleh/mcstatus"

	"github.com/bobesa/go-domain-util/domainutil"
	"github.com/go-telegram-bot-api/telegram-bot-api"
	"github.com/pelletier/go-toml"
	"github.com/prologic/bitcask"
)

type Config struct {
	Bot struct {
		Token string
		DB    string
	}
}

func mcStatusString(q string, s mcstatus.Status) string {
	var b strings.Builder

	// query, hostname, isonline
	b.WriteString(fmt.Sprintf("<a href=\"%s\">%s</a> is %s\n", s.Hostname, html.EscapeString(q), mcStatusOnlineString(s)))

	if !s.IsOnline {
		return b.String()
	}

	b.WriteString(fmt.Sprintf("- players: %d/%d\n", s.PlayersOnline, s.PlayersMax)) // players
	b.WriteString(fmt.Sprintf("- version: %s (%s)\n", s.Version, s.Software))       // version, software
	b.WriteString(fmt.Sprintf("- ip: <code>%s:%d</code>\n", s.IP, s.Port))          // ip, port

	return b.String()
}

func mcStatusOnlineString(s mcstatus.Status) string {
	if s.IsOnline {
		return "online"
	}

	return "not online"
}

func int64toBytes(i int64) []byte {
	b := make([]byte, 8)
	binary.LittleEndian.PutUint64(b, uint64(i))

	return b
}

func main() {
	// get and parse config
	doc, err := ioutil.ReadFile("config.toml")
	if err != nil {
		log.Panic(err)
	}

	var config Config
	if err := toml.Unmarshal(doc, &config); err != nil {
		log.Panic(err)
	}

	// setup db
	db, err := bitcask.Open(config.Bot.DB)
	if err != nil {
		log.Panic(err)
	}
	defer db.Close()

	// setup mc
	mc := mcstatus.New()

	// setup bot
	bot, err := tgbotapi.NewBotAPI(config.Bot.Token)
	if err != nil {
		log.Panic(err)
	}

	log.Printf("Authorized on account %s", bot.Self.UserName)
	// bot.Debug = true

	updates, err := bot.GetUpdatesChan(tgbotapi.UpdateConfig{Timeout: 60})
	if err != nil {
		log.Panic(err)
	}

	for u := range updates {
		if q := u.InlineQuery; q != nil {
			if dmn := domainutil.Domain(q.Query); dmn == "" {
				continue
			}

			status, err := mc.GetStatus(q.Query)
			if err != nil {
				log.Println(err)
				continue
			}

			r := tgbotapi.InlineQueryResultArticle{
				Type:        "article", // must be
				ID:          q.ID,
				Title:       q.Query,
				Description: fmt.Sprintf("%s is %s", q.Query, mcStatusOnlineString(status)),
				ThumbURL:    mcstatus.IconURL(q.Query),
				InputMessageContent: tgbotapi.InputTextMessageContent{
					DisableWebPagePreview: true,
					ParseMode:             "html",
					Text:                  mcStatusString(q.Query, status),
				},
			}

			results := make([]interface{}, 1)
			results[0] = r

			api, err := bot.AnswerInlineQuery(tgbotapi.InlineConfig{
				InlineQueryID: q.ID,
				Results:       results,
			})

			if err != nil {
				log.Println(api, err)
			}

			continue
		}

		if m := u.Message; m != nil {
			if m.Command() == "status" {
				chatid := int64toBytes(m.Chat.ID)
				q := m.CommandArguments()
				if q == "" && !db.Has(chatid) {
					continue // TODO
				}

				if q == "" {
					val, err := db.Get(chatid)
					if err != nil {
						log.Println(err)
						continue // TODO
					}

					q = string(val)
				} else {
					q = strings.Fields(q)[0]

					if m.Chat.IsPrivate() {
						err := db.Put(chatid, []byte(q))
						if err != nil {
							log.Println(err)
							continue // TODO
						}
					}
				}

				status, err := mc.GetStatus(q)
				if err != nil {
					log.Println(err)
					continue // TODO
				}

				msg := tgbotapi.NewMessage(m.Chat.ID, mcStatusString(q, status))
				msg.ParseMode = "html"
				msg.DisableWebPagePreview = true

				if api, err := bot.Send(msg); err != nil {
					log.Println(api, err)
				}
			} else if m.Command() == "default" {
				if m.Chat.IsPrivate() {
					continue
				}

				chatmember, err := bot.GetChatMember(tgbotapi.ChatConfigWithUser{
					ChatID: m.Chat.ID,
					UserID: m.From.ID,
				})
				if err != nil {
					log.Println(err)
					continue
				}

				if !chatmember.IsAdministrator() && !chatmember.IsCreator() {
					continue // TODO
				}

				args := strings.Fields(m.CommandArguments())
				if len(args) < 1 || len(args[0]) < 1 {
					continue // TODO
				}

				q := args[0]
				if q == "clear" {
					if err := db.Delete(int64toBytes(m.Chat.ID)); err != nil {
						log.Println(err)
					}

					continue
				}

				if err := db.Put(int64toBytes(m.Chat.ID), []byte(q)); err != nil {
					log.Println(err)
				}
			}
		}
	}
}