mostly working
This commit is contained in:
		
							
								
								
									
										105
									
								
								glist/glist.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								glist/glist.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
package glist
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Entry struct {
 | 
			
		||||
	Text    string `json:"text"`
 | 
			
		||||
	Checked bool   `json:"checked"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GList struct {
 | 
			
		||||
	AllMsgCounter int        `json:"-"`
 | 
			
		||||
	Mutex         sync.Mutex `json:"-"`
 | 
			
		||||
	ChatID        int        `json:"chat_id"`
 | 
			
		||||
	MessageID     *int       `json:"message_id"`
 | 
			
		||||
	Items         []Entry    `json:"items"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewGList(chatID int, items ...string) *GList {
 | 
			
		||||
	g := GList{ChatID: chatID}
 | 
			
		||||
	for _, text := range items {
 | 
			
		||||
		g.Items = append(g.Items, Entry{text, false})
 | 
			
		||||
	}
 | 
			
		||||
	return &g
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GList) Add(text string) error {
 | 
			
		||||
	for _, item := range g.Items {
 | 
			
		||||
		if item.Text == text {
 | 
			
		||||
			return fmt.Errorf("dupe:%s", text)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	g.Items = append(g.Items, Entry{text, false})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GList) Toggle(text string) error {
 | 
			
		||||
	for i, item := range g.Items {
 | 
			
		||||
		if item.Text == text {
 | 
			
		||||
			g.Items[i].Checked = !g.Items[i].Checked
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Errorf("not found:%s", text)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GList) ClearChecked() {
 | 
			
		||||
	var remaining []Entry
 | 
			
		||||
	for _, item := range g.Items {
 | 
			
		||||
		if !item.Checked {
 | 
			
		||||
			remaining = append(remaining, item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	g.Items = remaining
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type button struct {
 | 
			
		||||
	Text         string `json:"text"`
 | 
			
		||||
	CallbackData string `json:"callback_data"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type newListReq struct {
 | 
			
		||||
	ChatID      int    `json:"chat_id"`
 | 
			
		||||
	MessageID   *int   `json:"message_id,omitempty"`
 | 
			
		||||
	Text        string `json:"text"`
 | 
			
		||||
	ReplyMarkup struct {
 | 
			
		||||
		InlineKeyboard [][]button `json:"inline_keyboard"`
 | 
			
		||||
	} `json:"reply_markup"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeButton(e Entry) button {
 | 
			
		||||
	b := button{Text: e.Text, CallbackData: e.Text}
 | 
			
		||||
	if e.Checked {
 | 
			
		||||
		b.Text = fmt.Sprintf("✓ %s", e.Text)
 | 
			
		||||
	}
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeButtons(items []Entry) [][]button {
 | 
			
		||||
	var buttons [][]button
 | 
			
		||||
	var current []button
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		current = append(current, makeButton(item))
 | 
			
		||||
		if len(current) == 2 {
 | 
			
		||||
			buttons = append(buttons, current)
 | 
			
		||||
			current = []button{}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(current) != 0 {
 | 
			
		||||
		buttons = append(buttons, current)
 | 
			
		||||
	}
 | 
			
		||||
	return buttons
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GList) GenSendListReq() ([]byte, error) {
 | 
			
		||||
	req := newListReq{ChatID: g.ChatID, MessageID: g.MessageID, Text: "ok"}
 | 
			
		||||
	itemButtons := makeButtons(g.Items)
 | 
			
		||||
	controlButtons := []button{{"clear checked", "clear"}}
 | 
			
		||||
	req.ReplyMarkup.InlineKeyboard = append(itemButtons, controlButtons)
 | 
			
		||||
	data, err := json.Marshal(req)
 | 
			
		||||
	return data, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								glist/glist_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								glist/glist_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
package glist
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sync"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestGList(t *testing.T) {
 | 
			
		||||
	var ti int
 | 
			
		||||
	var m sync.Mutex
 | 
			
		||||
	g := GList{ti, m, 4342, nil, []Entry{{"foo", true}}}
 | 
			
		||||
	data, err := g.GenSendListReq()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	expected := `{"chat_id":4342,"text":"ok","reply_markup":{"inline_keyboard":[[{"text":"✓ foo","callback_data":"foo"}]]}}`
 | 
			
		||||
	if expected != string(data) {
 | 
			
		||||
		t.Fatalf("expected: %s\n got:%s\n", expected, string(data))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										123
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								main.go
									
									
									
									
									
								
							@@ -1,21 +1,23 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gitea.balki.me/telegram-msgchkbox/glist"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var apiToken = "421791796:AAE4wPbcqfLP1GNeGR3RTBiyX16fCj3HPAM"
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var chats sync.Map
 | 
			
		||||
	fmt.Println("vim-go")
 | 
			
		||||
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		w.WriteHeader(http.StatusNotFound)
 | 
			
		||||
	})
 | 
			
		||||
	http.HandleFunc("/zeexkfcsdjpmncirkyelwzotjmmefcqtcogrfwnafidionxiacwnslwuhbwfuppjgwzbmazd", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		w.Write([]byte("ok"))
 | 
			
		||||
		body, err := io.ReadAll(r.Body)
 | 
			
		||||
@@ -50,39 +52,70 @@ func main() {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if update.Message != nil {
 | 
			
		||||
			go sendButton(update.Message.Chat.ID, update.Message.ID, update.Message.Text)
 | 
			
		||||
			go DeleteMessage(update.Message.Chat.ID, update.Message.ID)
 | 
			
		||||
 | 
			
		||||
			chatID := update.Message.Chat.ID
 | 
			
		||||
			g, _ := chats.LoadOrStore(chatID, glist.NewGList(chatID))
 | 
			
		||||
			gl := g.(*glist.GList)
 | 
			
		||||
			go handleTextAdded(gl, update.Message.Text)
 | 
			
		||||
		} else if update.CallbackQuery != nil {
 | 
			
		||||
			go markButtonChecked(update.CallbackQuery.Message.Chat.ID, update.CallbackQuery.Message.ID, update.CallbackQuery.Data)
 | 
			
		||||
			go answerCallbackQuery(update.CallbackQuery.ID)
 | 
			
		||||
			defer func() { go answerCallbackQuery(update.CallbackQuery.ID) }()
 | 
			
		||||
 | 
			
		||||
			chatID := update.CallbackQuery.Message.Chat.ID
 | 
			
		||||
			g, ok := chats.Load(chatID)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				log.Println("Chat not found: %s", chatID)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			gl := g.(*glist.GList)
 | 
			
		||||
			go handleButtonClick(gl, update.CallbackQuery.Message.ID, update.CallbackQuery.Data)
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	port := 28923
 | 
			
		||||
	log.Panic(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func markButtonChecked(chatID int, messageID int, text string) {
 | 
			
		||||
	url := fmt.Sprintf("https://api.telegram.org/bot%s/editMessageText", apiToken)
 | 
			
		||||
	text = fmt.Sprintf("✓ %s", text)
 | 
			
		||||
	sendMsgFmt := `
 | 
			
		||||
				{
 | 
			
		||||
				  "chat_id": "%d",
 | 
			
		||||
				  "message_id": "%d",
 | 
			
		||||
				  "text": "ok",
 | 
			
		||||
				  "reply_markup": {
 | 
			
		||||
					"inline_keyboard": [
 | 
			
		||||
					  [
 | 
			
		||||
						{
 | 
			
		||||
						  "text": "%s",
 | 
			
		||||
						  "callback_data": "%s"
 | 
			
		||||
						}
 | 
			
		||||
					  ]
 | 
			
		||||
					]
 | 
			
		||||
				  }
 | 
			
		||||
				}
 | 
			
		||||
			`
 | 
			
		||||
	sendMsgReq := fmt.Sprintf(sendMsgFmt, chatID, messageID, text, text)
 | 
			
		||||
	resp, err := http.Post(url, "application/json", strings.NewReader(sendMsgReq))
 | 
			
		||||
func handleTextAdded(gl *glist.GList, text string) {
 | 
			
		||||
	gl.Mutex.Lock()
 | 
			
		||||
	defer gl.Mutex.Unlock()
 | 
			
		||||
	gl.Add(text)
 | 
			
		||||
	count := gl.AllMsgCounter + 1
 | 
			
		||||
	gl.AllMsgCounter = count
 | 
			
		||||
	time.AfterFunc(30*time.Second, func() {
 | 
			
		||||
		gl.Mutex.Lock()
 | 
			
		||||
		defer gl.Mutex.Unlock()
 | 
			
		||||
		if count == gl.AllMsgCounter {
 | 
			
		||||
			sendList(gl, "sendMessage")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleButtonClick(gl *glist.GList, messageID int, text string) {
 | 
			
		||||
	gl.Mutex.Lock()
 | 
			
		||||
	defer gl.Mutex.Unlock()
 | 
			
		||||
	if gl.MessageID != nil {
 | 
			
		||||
		if messageID != *gl.MessageID {
 | 
			
		||||
			go deleteMessage(gl.ChatID, *gl.MessageID)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	gl.MessageID = &messageID
 | 
			
		||||
	if text == "clear" {
 | 
			
		||||
		gl.ClearChecked()
 | 
			
		||||
	} else {
 | 
			
		||||
		gl.Toggle(text)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sendList(gl, "editMessageText")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sendList(gl *glist.GList, method string) {
 | 
			
		||||
	url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", apiToken, method)
 | 
			
		||||
	sendMsgReq, err := gl.GenSendListReq()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	resp, err := http.Post(url, "application/json", bytes.NewReader(sendMsgReq))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println(err)
 | 
			
		||||
		return
 | 
			
		||||
@@ -100,33 +133,7 @@ func answerCallbackQuery(callbackQueryID string) {
 | 
			
		||||
	logBody(resp.Body)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sendButton(chatID int, messageID int, text string) {
 | 
			
		||||
	url := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", apiToken)
 | 
			
		||||
	sendMsgFmt := `
 | 
			
		||||
			{
 | 
			
		||||
			  "chat_id": "%d",
 | 
			
		||||
			  "text": "ok",
 | 
			
		||||
			  "reply_markup": {
 | 
			
		||||
				"inline_keyboard": [
 | 
			
		||||
				  [
 | 
			
		||||
					{
 | 
			
		||||
					  "text": "%s",
 | 
			
		||||
					  "callback_data": "%s"
 | 
			
		||||
					}
 | 
			
		||||
				  ]
 | 
			
		||||
				]
 | 
			
		||||
			  }
 | 
			
		||||
			}
 | 
			
		||||
			`
 | 
			
		||||
	sendMsgReq := fmt.Sprintf(sendMsgFmt, chatID, text, text)
 | 
			
		||||
	resp, err := http.Post(url, "application/json", strings.NewReader(sendMsgReq))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	logBody(resp.Body)
 | 
			
		||||
}
 | 
			
		||||
func DeleteMessage(chatID int, messageID int) {
 | 
			
		||||
func deleteMessage(chatID int, messageID int) {
 | 
			
		||||
	deleteUrl := fmt.Sprintf("https://api.telegram.org/bot%s/deleteMessage?chat_id=%d&message_id=%d", apiToken, chatID, messageID)
 | 
			
		||||
	resp, err := http.Get(deleteUrl)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -151,7 +158,7 @@ func logBody(respBody io.ReadCloser) {
 | 
			
		||||
	log.Println(string(body))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
/* Example data
 | 
			
		||||
update_id: 547400623
 | 
			
		||||
message:
 | 
			
		||||
  message_id: 869
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user