refactor MessageLink: clean up unused prop and optimize insert message
we don't actually need the child or to recurse over every previous message to insert a new message additionally, add load and dump message store to disk in JSON Signed-off-by: Sid Sun <sid@sidsun.com>
This commit is contained in:
parent
9d491d79b7
commit
fbeea444fc
|
@ -1,4 +1,4 @@
|
||||||
FROM golang as builder
|
FROM golang:1.21 as builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
@ -8,5 +8,6 @@ RUN make build
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
RUN apk --no-cache add ca-certificates
|
RUN apk --no-cache add ca-certificates
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
RUN mkdir /app/store
|
||||||
COPY --from=builder /app/bin/ /app/
|
COPY --from=builder /app/bin/ /app/
|
||||||
CMD ["/app/openwebui-telegram"]
|
CMD ["/app/openwebui-telegram"]
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package contract
|
package contract
|
||||||
|
|
||||||
type MessageLink struct {
|
type MessageLink struct {
|
||||||
Parent int
|
Parent int
|
||||||
Children []int
|
Text string
|
||||||
Text string
|
From string
|
||||||
From string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompletionUpdate struct {
|
type CompletionUpdate struct {
|
||||||
|
|
|
@ -71,6 +71,12 @@ func Handler(b *tele.Bot, isResend bool) tele.HandlerFunc {
|
||||||
var finalMessage *string
|
var finalMessage *string
|
||||||
debounced := debounce.New(20 * time.Millisecond)
|
debounced := debounce.New(20 * time.Millisecond)
|
||||||
for completion := range updatesChan {
|
for completion := range updatesChan {
|
||||||
|
if finalMessage != nil && *finalMessage == completion.Message {
|
||||||
|
if completion.IsLast {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
finalMessage = &completion.Message
|
finalMessage = &completion.Message
|
||||||
send := func() {
|
send := func() {
|
||||||
_, err := b.Edit(botMessage, completion.Message)
|
_, err := b.Edit(botMessage, completion.Message)
|
||||||
|
@ -111,25 +117,16 @@ func addMessageToChain(m *tele.Message) *contract.MessageLink {
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent int
|
var parent int
|
||||||
if m.ReplyTo != nil {
|
// If this is a reply message, set the parent ID if it exists in the store
|
||||||
|
if m.ReplyTo != nil && store.ChatStore[m.Chat.ID][m.ReplyTo.ID] != nil {
|
||||||
parent = m.ReplyTo.ID
|
parent = m.ReplyTo.ID
|
||||||
if store.ChatStore[m.Chat.ID][parent] == nil {
|
|
||||||
addMessageToChain(m.ReplyTo)
|
|
||||||
}
|
|
||||||
store.ChatStore[m.Chat.ID][parent].Children = append(store.ChatStore[m.Chat.ID][parent].Children, m.ID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fmt.Printf("Message: %+v\n", m)
|
// fmt.Printf("Message: %+v\n", m)
|
||||||
if m.Sender == nil {
|
|
||||||
m.Sender = &tele.User{
|
|
||||||
Username: "unknown",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
store.ChatStore[m.Chat.ID][m.ID] = &contract.MessageLink{
|
store.ChatStore[m.Chat.ID][m.ID] = &contract.MessageLink{
|
||||||
Parent: parent,
|
Parent: parent,
|
||||||
Children: []int{},
|
Text: m.Text,
|
||||||
Text: m.Text,
|
From: m.Sender.Username,
|
||||||
From: m.Sender.Username,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// x, err := json.MarshalIndent(store.ChatStore, "", " ")
|
// x, err := json.MarshalIndent(store.ChatStore, "", " ")
|
||||||
|
|
|
@ -11,12 +11,12 @@ import (
|
||||||
tele "gopkg.in/telebot.v3"
|
tele "gopkg.in/telebot.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bot struct {
|
type Bot struct {
|
||||||
bot *tele.Bot
|
bot *tele.Bot
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenAndServe starts listens on the update channel and handles routing the update to handlers
|
// ListenAndServe starts listens on the update channel and handles routing the update to handlers
|
||||||
func (b bot) Start() {
|
func (b Bot) Start() {
|
||||||
store.BotUsername = b.bot.Me.Username
|
store.BotUsername = b.bot.Me.Username
|
||||||
slog.Info("[StartBot] Started Bot", slog.String("bot_name", b.bot.Me.FirstName))
|
slog.Info("[StartBot] Started Bot", slog.String("bot_name", b.bot.Me.FirstName))
|
||||||
r := b.bot.Group()
|
r := b.bot.Group()
|
||||||
|
@ -27,8 +27,13 @@ func (b bot) Start() {
|
||||||
b.bot.Start()
|
b.bot.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b Bot) Stop() {
|
||||||
|
slog.Info("[StopBot] Stopping Bot")
|
||||||
|
b.bot.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
// New returns a new instance of the router
|
// New returns a new instance of the router
|
||||||
func New(cfg config.BotConfig) bot {
|
func New(cfg config.BotConfig) *Bot {
|
||||||
b, err := tele.NewBot(tele.Settings{
|
b, err := tele.NewBot(tele.Settings{
|
||||||
Token: cfg.Token(),
|
Token: cfg.Token(),
|
||||||
Poller: &tele.LongPoller{Timeout: 10 * time.Second},
|
Poller: &tele.LongPoller{Timeout: 10 * time.Second},
|
||||||
|
@ -36,7 +41,7 @@ func New(cfg config.BotConfig) bot {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return bot{
|
return &Bot{
|
||||||
bot: b,
|
bot: b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package bot
|
package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
"github.com/sid-sun/openwebui-bot/cmd/config"
|
"github.com/sid-sun/openwebui-bot/cmd/config"
|
||||||
"github.com/sid-sun/openwebui-bot/pkg/bot/router"
|
"github.com/sid-sun/openwebui-bot/pkg/bot/router"
|
||||||
|
@ -11,8 +14,47 @@ import (
|
||||||
// StartBot starts the bot, inits all the requited submodules and routine for shutdown
|
// StartBot starts the bot, inits all the requited submodules and routine for shutdown
|
||||||
func StartBot(cfg config.Config) {
|
func StartBot(cfg config.Config) {
|
||||||
store.NewStore()
|
store.NewStore()
|
||||||
|
loadStore()
|
||||||
ch := router.New(cfg.Bot)
|
ch := router.New(cfg.Bot)
|
||||||
|
|
||||||
slog.Info("[StartBot] Starting Bot")
|
slog.Info("[StartBot] Starting Bot")
|
||||||
|
go dumpStore(ch)
|
||||||
ch.Start()
|
ch.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dump store data to disk as JSON on interrupt
|
||||||
|
func dumpStore(ch *router.Bot) {
|
||||||
|
shutDown := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(shutDown, os.Interrupt)
|
||||||
|
<-shutDown
|
||||||
|
slog.Info("[DumpStore] Dumping store data to disk")
|
||||||
|
// Implement store dumping logic here
|
||||||
|
x, err := json.MarshalIndent(store.ChatStore, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("[DumpStore] Error dumping store data to disk", slog.Any("error", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = os.WriteFile("./store/chat_store.json", x, 0644)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("[DumpStore] Error writing store data to file", slog.Any("error", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
slog.Info("[LoadStore] Dumped store data to disk")
|
||||||
|
ch.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// load data from JSON file on startup
|
||||||
|
func loadStore() {
|
||||||
|
slog.Info("[LoadStore] Loading store data from disk")
|
||||||
|
data, err := os.ReadFile("./store/chat_store.json")
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("[LoadStore] Error reading store data from file", slog.Any("error", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &store.ChatStore)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("[LoadStore] Error unmarshaling store data from file", slog.Any("error", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
slog.Info("[LoadStore] Loaded store data from disk")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue