implement persistence
This commit is contained in:
parent
ea082ccc89
commit
8711ec1245
@ -3,9 +3,15 @@ package glist
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var DataPath string
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
Checked bool `json:"checked"`
|
Checked bool `json:"checked"`
|
||||||
@ -27,6 +33,42 @@ func NewGList(chatID int, items ...string) *GList {
|
|||||||
return &g
|
return &g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reqs chan *GList
|
||||||
|
|
||||||
|
func DoPersist() {
|
||||||
|
reqs = make(chan *GList, 50)
|
||||||
|
go func() {
|
||||||
|
for range time.Tick(5 * time.Second) {
|
||||||
|
lists := map[*GList]struct{}{}
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case g := <-reqs:
|
||||||
|
lists[g] = struct{}{}
|
||||||
|
default:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for g := range lists {
|
||||||
|
g.persist()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GList) persist() {
|
||||||
|
g.Mutex.Lock()
|
||||||
|
defer g.Mutex.Unlock()
|
||||||
|
data, err := json.Marshal(g)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicln("failed to marshal")
|
||||||
|
}
|
||||||
|
filename := path.Join(DataPath, fmt.Sprintf("chkchat%d", g.ChatID))
|
||||||
|
if err := os.WriteFile(filename, data, 0644); err != nil {
|
||||||
|
log.Panicln("failed to write to file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GList) Add(text string) error {
|
func (g *GList) Add(text string) error {
|
||||||
for _, item := range g.Items {
|
for _, item := range g.Items {
|
||||||
if item.Text == text {
|
if item.Text == text {
|
||||||
@ -34,6 +76,7 @@ func (g *GList) Add(text string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.Items = append(g.Items, Entry{text, false})
|
g.Items = append(g.Items, Entry{text, false})
|
||||||
|
reqs <- g
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +84,7 @@ func (g *GList) Toggle(text string) error {
|
|||||||
for i, item := range g.Items {
|
for i, item := range g.Items {
|
||||||
if item.Text == text {
|
if item.Text == text {
|
||||||
g.Items[i].Checked = !g.Items[i].Checked
|
g.Items[i].Checked = !g.Items[i].Checked
|
||||||
|
reqs <- g
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,6 +99,7 @@ func (g *GList) ClearChecked() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.Items = remaining
|
g.Items = remaining
|
||||||
|
reqs <- g
|
||||||
}
|
}
|
||||||
|
|
||||||
type button struct {
|
type button struct {
|
||||||
|
85
main.go
85
main.go
@ -1,3 +1,4 @@
|
|||||||
|
// This is the main package
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -7,18 +8,58 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.balki.me/telegram-msgchkbox/glist"
|
"gitea.balki.me/telegram-msgchkbox/glist"
|
||||||
)
|
)
|
||||||
|
|
||||||
var apiToken = "421791796:AAE4wPbcqfLP1GNeGR3RTBiyX16fCj3HPAM"
|
var apiToken string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
apiToken = os.Getenv("CHKBOT_API_TOKEN")
|
||||||
|
|
||||||
|
if apiToken == "" {
|
||||||
|
log.Panicln("CHKBOT_API_TOKEN is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
port := func() int {
|
||||||
|
portStr := os.Getenv("CHKBOT_PORT")
|
||||||
|
port, err := strconv.Atoi(portStr)
|
||||||
|
if err == nil {
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
return 28923
|
||||||
|
}()
|
||||||
|
|
||||||
|
dataPath := func() string {
|
||||||
|
dataPath := os.Getenv("CHKBOT_DATA_PATH")
|
||||||
|
if dataPath == "" {
|
||||||
|
dataPath = "."
|
||||||
|
}
|
||||||
|
err := os.MkdirAll(dataPath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("Failed to create datapath, path: %s, err: %s", dataPath, err)
|
||||||
|
}
|
||||||
|
return dataPath
|
||||||
|
}()
|
||||||
|
|
||||||
|
glist.DataPath = dataPath
|
||||||
|
glist.DoPersist()
|
||||||
|
|
||||||
|
log.Printf("List path starting with datapath:%s, port:%d\n", dataPath, port)
|
||||||
|
|
||||||
var chats sync.Map
|
var chats sync.Map
|
||||||
fmt.Println("vim-go")
|
if err := loadData(dataPath, &chats); err != nil {
|
||||||
http.HandleFunc("/zeexkfcsdjpmncirkyelwzotjmmefcqtcogrfwnafidionxiacwnslwuhbwfuppjgwzbmazd", func(w http.ResponseWriter, r *http.Request) {
|
log.Panicf("failed to load data, err: %s", err)
|
||||||
|
}
|
||||||
|
botPath := fmt.Sprintf("/bot%s", apiToken)
|
||||||
|
http.HandleFunc(botPath, func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte("ok"))
|
w.Write([]byte("ok"))
|
||||||
body, err := io.ReadAll(r.Body)
|
body, err := io.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -57,7 +98,9 @@ func main() {
|
|||||||
g, _ := chats.LoadOrStore(chatID, glist.NewGList(chatID))
|
g, _ := chats.LoadOrStore(chatID, glist.NewGList(chatID))
|
||||||
gl := g.(*glist.GList)
|
gl := g.(*glist.GList)
|
||||||
go handleTextAdded(gl, update.Message.Text)
|
go handleTextAdded(gl, update.Message.Text)
|
||||||
|
|
||||||
} else if update.CallbackQuery != nil {
|
} else if update.CallbackQuery != nil {
|
||||||
|
|
||||||
defer func() { go answerCallbackQuery(update.CallbackQuery.ID) }()
|
defer func() { go answerCallbackQuery(update.CallbackQuery.ID) }()
|
||||||
|
|
||||||
chatID := update.CallbackQuery.Message.Chat.ID
|
chatID := update.CallbackQuery.Message.Chat.ID
|
||||||
@ -71,7 +114,6 @@ func main() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
port := 28923
|
|
||||||
log.Panic(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
|
log.Panic(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +171,8 @@ func sendList(gl *glist.GList, method string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func answerCallbackQuery(callbackQueryID string) {
|
func answerCallbackQuery(callbackQueryID string) {
|
||||||
answerUrl := fmt.Sprintf("https://api.telegram.org/bot%s/answerCallbackQuery?callback_query_id=%stext=ok", apiToken, callbackQueryID)
|
answerURL := fmt.Sprintf("https://api.telegram.org/bot%s/answerCallbackQuery?callback_query_id=%stext=ok", apiToken, callbackQueryID)
|
||||||
resp, err := http.Get(answerUrl)
|
resp, err := http.Get(answerURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
@ -139,8 +181,8 @@ func answerCallbackQuery(callbackQueryID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
deleteURL := fmt.Sprintf("https://api.telegram.org/bot%s/deleteMessage?chat_id=%d&message_id=%d", apiToken, chatID, messageID)
|
||||||
resp, err := http.Get(deleteUrl)
|
resp, err := http.Get(deleteURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
@ -163,6 +205,33 @@ func logBody(respBody io.ReadCloser) {
|
|||||||
log.Println(string(body))
|
log.Println(string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadData(dataPath string, chats *sync.Map) error {
|
||||||
|
items, err := os.ReadDir(dataPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, de := range items {
|
||||||
|
if de.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := de.Name()
|
||||||
|
if !strings.HasPrefix(name, "chkchat") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var gl glist.GList
|
||||||
|
data, err := os.ReadFile(path.Join(dataPath, name))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed read file, name: %s, err:%w", name, err)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &gl)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse data, data:%s, err:%w", data, err)
|
||||||
|
}
|
||||||
|
chats.Store(gl.ChatID, &gl)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
/* Example data
|
/* Example data
|
||||||
update_id: 547400623
|
update_id: 547400623
|
||||||
message:
|
message:
|
||||||
|
Loading…
Reference in New Issue
Block a user