2023-12-13 21:07:40 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-12-19 21:26:11 +00:00
|
|
|
"errors"
|
2023-12-13 21:07:40 +00:00
|
|
|
"fmt"
|
2023-12-19 21:26:11 +00:00
|
|
|
"log"
|
|
|
|
"os"
|
2024-01-30 17:24:07 +00:00
|
|
|
"path/filepath"
|
2023-12-19 21:26:11 +00:00
|
|
|
"sync"
|
2023-12-21 20:20:43 +00:00
|
|
|
"time"
|
2023-12-13 21:07:40 +00:00
|
|
|
|
2023-12-21 20:20:43 +00:00
|
|
|
"github.com/tylertravisty/rum-goggles/internal/api"
|
2024-01-05 21:24:54 +00:00
|
|
|
"github.com/tylertravisty/rum-goggles/internal/chatbot"
|
2023-12-19 21:26:11 +00:00
|
|
|
"github.com/tylertravisty/rum-goggles/internal/config"
|
|
|
|
rumblelivestreamlib "github.com/tylertravisty/rumble-livestream-lib-go"
|
2024-01-30 17:24:07 +00:00
|
|
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
2023-12-19 21:26:11 +00:00
|
|
|
)
|
|
|
|
|
2023-12-24 21:18:42 +00:00
|
|
|
type chat struct {
|
|
|
|
username string
|
|
|
|
password string
|
|
|
|
url string
|
|
|
|
}
|
2023-12-13 21:07:40 +00:00
|
|
|
|
|
|
|
// App struct
|
|
|
|
type App struct {
|
2023-12-24 21:18:42 +00:00
|
|
|
ctx context.Context
|
|
|
|
cfg *config.App
|
|
|
|
cfgMu sync.Mutex
|
|
|
|
api *api.Api
|
|
|
|
apiMu sync.Mutex
|
2024-01-05 21:24:54 +00:00
|
|
|
cb *chatbot.ChatBot
|
|
|
|
cbMu sync.Mutex
|
2023-12-24 21:18:42 +00:00
|
|
|
logError *log.Logger
|
|
|
|
logInfo *log.Logger
|
2023-12-13 21:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewApp creates a new App application struct
|
|
|
|
func NewApp() *App {
|
2023-12-24 21:18:42 +00:00
|
|
|
app := &App{}
|
|
|
|
err := app.initLog()
|
|
|
|
if err != nil {
|
2023-12-24 21:22:49 +00:00
|
|
|
log.Fatal("error initializing log:", err)
|
2023-12-24 21:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
app.api = api.NewApi(app.logError, app.logInfo)
|
|
|
|
|
|
|
|
return app
|
2023-12-13 21:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// startup is called when the app starts. The context is saved
|
|
|
|
// so we can call the runtime methods
|
|
|
|
func (a *App) startup(ctx context.Context) {
|
|
|
|
a.ctx = ctx
|
2023-12-21 20:20:43 +00:00
|
|
|
a.api.Startup(ctx)
|
2023-12-24 21:18:42 +00:00
|
|
|
|
2023-12-19 21:26:11 +00:00
|
|
|
err := a.loadConfig()
|
|
|
|
if err != nil {
|
2023-12-24 21:18:42 +00:00
|
|
|
a.logError.Fatal("error loading config: ", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) initLog() error {
|
2023-12-26 16:30:29 +00:00
|
|
|
f, err := config.LogFile()
|
2023-12-24 21:18:42 +00:00
|
|
|
if err != nil {
|
2023-12-24 21:24:30 +00:00
|
|
|
return fmt.Errorf("error opening log file: %v", err)
|
2023-12-24 21:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
a.logInfo = log.New(f, "[info]", log.LstdFlags|log.Lshortfile)
|
|
|
|
a.logError = log.New(f, "[error]", log.LstdFlags|log.Lshortfile)
|
|
|
|
return nil
|
2023-12-19 21:26:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) loadConfig() error {
|
2023-12-24 21:18:42 +00:00
|
|
|
cfg, err := config.Load()
|
2023-12-19 21:26:11 +00:00
|
|
|
if err != nil {
|
|
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
|
|
return fmt.Errorf("error loading config: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return a.newConfig()
|
|
|
|
}
|
|
|
|
|
|
|
|
a.cfg = cfg
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) newConfig() error {
|
2023-12-21 20:20:43 +00:00
|
|
|
cfg := &config.App{Channels: map[string]config.Channel{}}
|
2023-12-24 21:18:42 +00:00
|
|
|
err := cfg.Save()
|
2023-12-19 21:26:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error saving new config: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
a.cfg = cfg
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) Config() *config.App {
|
|
|
|
return a.cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) AddChannel(url string) (*config.App, error) {
|
|
|
|
client := rumblelivestreamlib.Client{StreamKey: url}
|
|
|
|
resp, err := client.Request()
|
|
|
|
if err != nil {
|
2023-12-24 21:18:42 +00:00
|
|
|
a.logError.Println("error executing api request:", err)
|
|
|
|
return nil, fmt.Errorf("Error querying API. Verify key and try again.")
|
2023-12-19 21:26:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
name := resp.Username
|
|
|
|
if resp.ChannelName != "" {
|
|
|
|
name = resp.ChannelName
|
|
|
|
}
|
|
|
|
|
|
|
|
a.cfgMu.Lock()
|
|
|
|
defer a.cfgMu.Unlock()
|
2023-12-21 20:20:43 +00:00
|
|
|
_, err = a.cfg.NewChannel(url, name)
|
|
|
|
if err != nil {
|
2023-12-24 21:18:42 +00:00
|
|
|
a.logError.Println("error creating new channel:", err)
|
|
|
|
return nil, fmt.Errorf("Error creating new channel. Try again.")
|
2023-12-21 20:20:43 +00:00
|
|
|
}
|
|
|
|
|
2023-12-24 21:18:42 +00:00
|
|
|
err = a.cfg.Save()
|
2023-12-19 21:26:11 +00:00
|
|
|
if err != nil {
|
2023-12-24 21:18:42 +00:00
|
|
|
a.logError.Println("error saving config:", err)
|
|
|
|
return nil, fmt.Errorf("Error saving channel information. Try again.")
|
2023-12-19 21:26:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return a.cfg, nil
|
2023-12-13 21:07:40 +00:00
|
|
|
}
|
|
|
|
|
2024-01-05 21:24:54 +00:00
|
|
|
func (a *App) ChatBotMessages(cid string) (map[string]config.ChatMessage, error) {
|
|
|
|
a.cfgMu.Lock()
|
|
|
|
defer a.cfgMu.Unlock()
|
|
|
|
channel, exists := a.cfg.Channels[cid]
|
|
|
|
if !exists {
|
|
|
|
a.logError.Println("channel does not exist:", cid)
|
|
|
|
return nil, fmt.Errorf("Cannot find channel. Try reloading.")
|
|
|
|
}
|
|
|
|
|
|
|
|
return channel.ChatBot.Messages, nil
|
|
|
|
}
|
|
|
|
|
2024-02-06 19:57:56 +00:00
|
|
|
func (a *App) AddChatMessage(cid string, cm config.ChatMessage) (map[string]config.ChatMessage, error) {
|
2024-01-05 21:24:54 +00:00
|
|
|
var err error
|
|
|
|
a.cfgMu.Lock()
|
|
|
|
defer a.cfgMu.Unlock()
|
2024-02-06 19:57:56 +00:00
|
|
|
_, err = a.cfg.NewChatMessage(cid, cm)
|
2024-01-05 21:24:54 +00:00
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error creating new chat:", err)
|
|
|
|
return nil, fmt.Errorf("Error creating new chat message. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = a.cfg.Save()
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error saving config:", err)
|
|
|
|
return nil, fmt.Errorf("Error saving chat message information. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
a.updateChatBotConfig(a.cfg.Channels[cid].ChatBot)
|
|
|
|
|
|
|
|
return a.cfg.Channels[cid].ChatBot.Messages, nil
|
|
|
|
}
|
|
|
|
|
2024-02-06 19:57:56 +00:00
|
|
|
func (a *App) DeleteChatMessage(cid string, cm config.ChatMessage) (map[string]config.ChatMessage, error) {
|
2024-01-05 21:24:54 +00:00
|
|
|
a.cbMu.Lock()
|
|
|
|
if a.cb != nil {
|
2024-02-06 19:57:56 +00:00
|
|
|
err := a.cb.StopMessage(cm.ID)
|
2024-01-05 21:24:54 +00:00
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error stopping chat bot message:", err)
|
|
|
|
return nil, fmt.Errorf("Error stopping message. Try Again.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a.cbMu.Unlock()
|
|
|
|
|
|
|
|
a.cfgMu.Lock()
|
|
|
|
defer a.cfgMu.Unlock()
|
2024-02-06 19:57:56 +00:00
|
|
|
err := a.cfg.DeleteChatMessage(cid, cm)
|
2024-01-05 21:24:54 +00:00
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error deleting chat message:", err)
|
|
|
|
return nil, fmt.Errorf("Error deleting chat message. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = a.cfg.Save()
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error saving config:", err)
|
|
|
|
return nil, fmt.Errorf("Error saving chat message information. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
a.updateChatBotConfig(a.cfg.Channels[cid].ChatBot)
|
|
|
|
|
|
|
|
return a.cfg.Channels[cid].ChatBot.Messages, nil
|
|
|
|
}
|
|
|
|
|
2024-02-06 19:57:56 +00:00
|
|
|
func (a *App) UpdateChatMessage(cid string, cm config.ChatMessage) (map[string]config.ChatMessage, error) {
|
2024-01-05 21:24:54 +00:00
|
|
|
var err error
|
|
|
|
a.cfgMu.Lock()
|
|
|
|
defer a.cfgMu.Unlock()
|
2024-02-06 19:57:56 +00:00
|
|
|
_, err = a.cfg.UpdateChatMessage(cid, cm)
|
2024-01-05 21:24:54 +00:00
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error updating chat message:", err)
|
|
|
|
return nil, fmt.Errorf("Error updating chat message. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = a.cfg.Save()
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error saving config:", err)
|
|
|
|
return nil, fmt.Errorf("Error saving chat message information. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
a.updateChatBotConfig(a.cfg.Channels[cid].ChatBot)
|
|
|
|
|
|
|
|
return a.cfg.Channels[cid].ChatBot.Messages, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) NewChatBot(cid string, username string, password string, streamUrl string) error {
|
|
|
|
a.cbMu.Lock()
|
|
|
|
defer a.cbMu.Unlock()
|
|
|
|
|
|
|
|
if a.cb != nil {
|
|
|
|
err := a.resetChatBot()
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error resetting chat bot:", err)
|
|
|
|
return fmt.Errorf("Error creating chat bot. Try Again.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
channel, exists := a.cfg.Channels[cid]
|
|
|
|
if !exists {
|
|
|
|
a.logError.Println("channel does not exist:", cid)
|
|
|
|
return fmt.Errorf("Channel does not exist.")
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
a.cb, err = chatbot.NewChatBot(a.ctx, streamUrl, channel.ChatBot, a.logError)
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error creating new chat bot:", err)
|
2024-01-31 20:29:06 +00:00
|
|
|
return fmt.Errorf("Error creating new chat bot. Try again.")
|
2024-01-05 21:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = a.cb.Login(username, password)
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error logging into chat bot:", err)
|
2024-01-30 17:24:07 +00:00
|
|
|
return fmt.Errorf("Error logging in. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = a.cb.StartChatStream()
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error starting chat stream:", err)
|
|
|
|
return fmt.Errorf("Error connecting to chat. Try again.")
|
2024-01-05 21:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// a.cb = cb
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) ResetChatBot() error {
|
|
|
|
a.cbMu.Lock()
|
|
|
|
defer a.cbMu.Unlock()
|
|
|
|
|
|
|
|
err := a.resetChatBot()
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error resetting chat bot:", err)
|
|
|
|
return fmt.Errorf("Error resetting chat bot. Try Again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) resetChatBot() error {
|
|
|
|
if a.cb == nil {
|
|
|
|
// return fmt.Errorf("chat bot is nil")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err := a.cb.StopAllMessages()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error stopping all chat bot messages: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-01-30 17:24:07 +00:00
|
|
|
err = a.cb.StopChatStream()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error stopping chat stream: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-01-05 21:24:54 +00:00
|
|
|
err = a.cb.Logout()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error logging out of chat bot: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
a.cb = nil
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) StartChatBotMessage(mid string) error {
|
|
|
|
a.cbMu.Lock()
|
|
|
|
defer a.cbMu.Unlock()
|
|
|
|
|
|
|
|
if a.cb == nil {
|
|
|
|
return fmt.Errorf("Chat bot not initialized.")
|
|
|
|
}
|
|
|
|
|
|
|
|
err := a.cb.StartMessage(mid)
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error starting chat bot message:", err)
|
|
|
|
return fmt.Errorf("Error starting message. Try Again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) StopChatBotMessage(mid string) error {
|
|
|
|
a.cbMu.Lock()
|
|
|
|
defer a.cbMu.Unlock()
|
|
|
|
|
|
|
|
// If chat bot not initialized, then stop does nothing
|
|
|
|
if a.cb == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err := a.cb.StopMessage(mid)
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error stopping chat bot message:", err)
|
|
|
|
return fmt.Errorf("Error stopping message. Try Again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-12-21 20:20:43 +00:00
|
|
|
func (a *App) StartApi(cid string) error {
|
|
|
|
channel, found := a.cfg.Channels[cid]
|
|
|
|
if !found {
|
2023-12-24 21:18:42 +00:00
|
|
|
a.logError.Println("could not find channel CID:", cid)
|
2023-12-21 20:20:43 +00:00
|
|
|
return fmt.Errorf("channel CID not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
err := a.api.Start(channel.ApiUrl, channel.Interval*time.Second)
|
2023-12-13 21:07:40 +00:00
|
|
|
if err != nil {
|
2023-12-24 21:18:42 +00:00
|
|
|
a.logError.Println("error starting api:", err)
|
2023-12-21 20:20:43 +00:00
|
|
|
return fmt.Errorf("error starting API")
|
2023-12-13 21:07:40 +00:00
|
|
|
}
|
2023-12-21 20:20:43 +00:00
|
|
|
|
|
|
|
return nil
|
2023-12-13 21:07:40 +00:00
|
|
|
}
|
2023-12-14 21:18:36 +00:00
|
|
|
|
2023-12-21 20:20:43 +00:00
|
|
|
func (a *App) StopApi() {
|
|
|
|
a.api.Stop()
|
|
|
|
}
|
2024-01-05 21:24:54 +00:00
|
|
|
|
|
|
|
func (a *App) updateChatBotConfig(cfg config.ChatBot) {
|
|
|
|
a.cbMu.Lock()
|
|
|
|
defer a.cbMu.Unlock()
|
|
|
|
if a.cb != nil {
|
|
|
|
a.cb.Cfg = cfg
|
|
|
|
}
|
|
|
|
}
|
2024-01-30 17:24:07 +00:00
|
|
|
|
|
|
|
func (a *App) OpenFileDialog() (string, error) {
|
|
|
|
home, err := os.UserHomeDir()
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error getting home directory:", err)
|
|
|
|
return "", fmt.Errorf("Error opening file explorer. Try again.")
|
|
|
|
}
|
|
|
|
filepath, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{DefaultDirectory: home})
|
|
|
|
if err != nil {
|
|
|
|
a.logError.Println("error opening file dialog:", err)
|
|
|
|
return "", fmt.Errorf("Error opening file explorer. Try again.")
|
|
|
|
}
|
|
|
|
|
|
|
|
return filepath, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) FilepathBase(path string) string {
|
|
|
|
return filepath.Base(path)
|
|
|
|
}
|