From 5c3fa663a1524b901e8587330c532243b39b887a Mon Sep 17 00:00:00 2001 From: tyler Date: Fri, 9 Feb 2024 15:35:18 -0500 Subject: [PATCH] Login sessions persist; start/stop all chat bot messages --- NOTES.md | 2 + app.go | 198 +++++++++++++++++- frontend/src/assets/icons/index.jsx | 4 + frontend/src/assets/icons/play-fill-green.png | Bin 0 -> 3203 bytes frontend/src/assets/icons/stop-fill.png | Bin 0 -> 2302 bytes frontend/src/components/ChatBot.css | 17 ++ frontend/src/components/ChatBot.jsx | 108 ++++++---- frontend/src/components/StreamChatBot.jsx | 16 +- frontend/src/screens/Dashboard.jsx | 82 +++++++- go.mod | 2 +- go.sum | 4 +- internal/chatbot/chatbot.go | 48 ++++- internal/config/config.go | 9 +- 13 files changed, 429 insertions(+), 61 deletions(-) create mode 100644 frontend/src/assets/icons/play-fill-green.png create mode 100644 frontend/src/assets/icons/stop-fill.png diff --git a/NOTES.md b/NOTES.md index ea5a2c9..47245ff 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,5 +1,7 @@ # Doing +Reset session information in config on logout + Show error when choosing file "chooseFile" Show filename in chat bot list Add styling to choose file button diff --git a/app.go b/app.go index 36b3c64..a594854 100644 --- a/app.go +++ b/app.go @@ -215,10 +215,77 @@ func (a *App) UpdateChatMessage(cid string, cm config.ChatMessage) (map[string]c return a.cfg.Channels[cid].ChatBot.Messages, nil } -func (a *App) NewChatBot(cid string, username string, password string, streamUrl string) error { +type NewChatBotResponse struct { + LoggedIn bool `json:"logged_in"` + StreamUrl string `json:"stream_url"` + Username string `json:"username"` +} + +func (a *App) GetChatBot(cid string) (NewChatBotResponse, error) { + if a.cb == nil { + return NewChatBotResponse{}, fmt.Errorf("Chat bot not initalized.") + } + + loggedIn, err := a.cb.LoggedIn() + if err != nil { + a.logError.Println("error checking if chat bot is logged in:", err) + return NewChatBotResponse{}, fmt.Errorf("Error checking if chat bot is logged in. Try again.") + } + + return NewChatBotResponse{loggedIn, a.cb.Cfg.Session.Client.StreamUrl, a.cb.Cfg.Session.Username}, nil +} + +func (a *App) NewChatBot(cid string) (NewChatBotResponse, 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 NewChatBotResponse{}, 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 NewChatBotResponse{}, fmt.Errorf("Channel does not exist.") + } + + if channel.ChatBot.Session.Client.StreamUrl == "" { + return NewChatBotResponse{}, nil + } + + var err error + a.cb, err = chatbot.NewChatBot(a.ctx, channel.ChatBot, a.logError) + if err != nil { + a.logError.Println("error creating new chat bot:", err) + return NewChatBotResponse{}, fmt.Errorf("Error creating new chat bot. Try again.") + } + + loggedIn, err := a.cb.LoggedIn() + if err != nil { + a.logError.Println("error checking if chat bot is logged in:", err) + return NewChatBotResponse{}, fmt.Errorf("Error checking if chat bot is logged in. Try again.") + } + + if loggedIn { + err = a.cb.StartChatStream() + if err != nil { + a.logError.Println("error starting chat stream:", err) + return NewChatBotResponse{}, fmt.Errorf("Error connecting to chat. Try again.") + } + } + + return NewChatBotResponse{loggedIn, channel.ChatBot.Session.Client.StreamUrl, channel.ChatBot.Session.Username}, nil +} + +func (a *App) LoginChatBot(cid string, username string, password string, streamUrl string) error { + a.cbMu.Lock() + defer a.cbMu.Unlock() + a.cfgMu.Lock() + defer a.cfgMu.Unlock() + if a.cb != nil { err := a.resetChatBot() if err != nil { @@ -231,35 +298,151 @@ func (a *App) NewChatBot(cid string, username string, password string, streamUrl a.logError.Println("channel does not exist:", cid) return fmt.Errorf("Channel does not exist.") } + channel.ChatBot.Session.Client.StreamUrl = streamUrl var err error - a.cb, err = chatbot.NewChatBot(a.ctx, streamUrl, channel.ChatBot, a.logError) + a.cb, err = chatbot.NewChatBot(a.ctx, channel.ChatBot, a.logError) if err != nil { a.logError.Println("error creating new chat bot:", err) return fmt.Errorf("Error creating new chat bot. Try again.") } - err = a.cb.Login(username, password) + cookies, err := a.cb.Login(username, password) if err != nil { a.logError.Println("error logging into chat bot:", err) return fmt.Errorf("Error logging in. Try again.") } + channel.ChatBot.Session = config.ChatBotSession{ + Client: rumblelivestreamlib.NewClientOptions{ + Cookies: cookies, + StreamUrl: streamUrl, + }, + Username: username, + } + a.cfg.Channels[cid] = channel + err = a.cfg.Save() + if err != nil { + a.logError.Println("error saving config:", err) + return fmt.Errorf("Error saving session information. Try again.") + } + + a.cb.Cfg.Session = channel.ChatBot.Session + err = a.cb.StartChatStream() if err != nil { a.logError.Println("error starting chat stream:", err) return fmt.Errorf("Error connecting to chat. Try again.") } - // a.cb = cb return nil } -func (a *App) ResetChatBot() error { +func (a *App) StopAllChatBot(cid string) error { + err := a.cb.StopAllMessages() + if err != nil { + a.logError.Println("error stopping all chat bot messages:", err) + return fmt.Errorf("Error stopping messages.") + } + + return nil +} + +func (a *App) StartAllChatBot(cid string) error { + err := a.cb.StartAllMessages() + if err != nil { + a.logError.Println("error starting all chat bot messages:", err) + return fmt.Errorf("Error starting messages.") + } + + return nil +} + +func (a *App) UpdateChatBotUrl(cid string, streamUrl string) error { a.cbMu.Lock() defer a.cbMu.Unlock() + a.cfgMu.Lock() + defer a.cfgMu.Unlock() + + if a.cb == nil { + return fmt.Errorf("Chat bot not initalized.") + } 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.") + } + channel.ChatBot.Session.Client.StreamUrl = streamUrl + + a.cb, err = chatbot.NewChatBot(a.ctx, channel.ChatBot, a.logError) + if err != nil { + a.logError.Println("error creating new chat bot:", err) + return fmt.Errorf("Error creating new chat bot. Try again.") + } + + a.cfg.Channels[cid] = channel + err = a.cfg.Save() + if err != nil { + a.logError.Println("error saving config:", err) + return fmt.Errorf("Error saving session information. Try again.") + } + + a.cb.Cfg.Session.Client.StreamUrl = streamUrl + + err = a.cb.StartChatStream() + if err != nil { + a.logError.Println("error starting chat stream:", err) + return fmt.Errorf("Error connecting to chat. Try again.") + } + + return nil +} + +func (a *App) ResetChatBot(cid string, logout bool) error { + a.cbMu.Lock() + defer a.cbMu.Unlock() + a.cfgMu.Lock() + defer a.cfgMu.Unlock() + + if a.cb == nil { + return nil + } + + err := a.cb.StopAllMessages() + if err != nil { + return fmt.Errorf("error stopping all chat bot messages: %v", err) + } + + if logout { + err := a.cb.Logout() + if err != nil { + return fmt.Errorf("error logging out of chat bot: %v", err) + } + + //TODO: reset session in config + channel, exists := a.cfg.Channels[cid] + if !exists { + a.logError.Println("channel does not exist:", cid) + return fmt.Errorf("Channel does not exist.") + } + + channel.ChatBot.Session = config.ChatBotSession{} + a.cfg.Channels[cid] = channel + err = a.cfg.Save() + if err != nil { + a.logError.Println("error saving config:", err) + return fmt.Errorf("Error saving session information. Try again.") + } + } + + err = a.resetChatBot() if err != nil { a.logError.Println("error resetting chat bot:", err) return fmt.Errorf("Error resetting chat bot. Try Again.") @@ -284,11 +467,6 @@ func (a *App) resetChatBot() error { return fmt.Errorf("error stopping chat stream: %v", err) } - err = a.cb.Logout() - if err != nil { - return fmt.Errorf("error logging out of chat bot: %v", err) - } - a.cb = nil return nil diff --git a/frontend/src/assets/icons/index.jsx b/frontend/src/assets/icons/index.jsx index 2c394db..b814454 100644 --- a/frontend/src/assets/icons/index.jsx +++ b/frontend/src/assets/icons/index.jsx @@ -6,8 +6,10 @@ import heart from './heart-fill.png'; import house from './house.png'; import pause from './pause-fill.png'; import play from './play-fill.png'; +import play_green from './play-fill-green.png'; import plus_circle from './plus-circle-fill.png'; import star from './star-fill.png'; +import stop from './stop-fill.png'; import thumbs_down from './hand-thumbs-down.png'; import thumbs_up from './hand-thumbs-up.png'; import x_lg from './x-lg.png'; @@ -20,8 +22,10 @@ export const Heart = heart; export const House = house; export const Pause = pause; export const Play = play; +export const PlayGreen = play_green; export const PlusCircle = plus_circle; export const Star = star; +export const Stop = stop; export const ThumbsDown = thumbs_down; export const ThumbsUp = thumbs_up; export const XLg = x_lg; diff --git a/frontend/src/assets/icons/play-fill-green.png b/frontend/src/assets/icons/play-fill-green.png new file mode 100644 index 0000000000000000000000000000000000000000..6b7294a2cae72062266861ccd5b1e6ed3b36b3c5 GIT binary patch literal 3203 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 UG%f6A{%rxq`WAWwluOM20p&3KssI20 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/icons/stop-fill.png b/frontend/src/assets/icons/stop-fill.png new file mode 100644 index 0000000000000000000000000000000000000000..6dccccf3778424063be818250758d8a235a00658 GIT binary patch literal 2302 zcmeH|`9BkmAIE1V+k`nfND&`LcZRt`&N0Un(Q@C!9Fz%qqxFRC1h<(q+xh-B@9`flc@y4dQWv|=-3Sre>ZveRRS`W z+U9FqK}OEK$sSOYH#wiBNifa@JiPkmQk`jzxDF-cePxsX@~0L!;wtGd@Wa_vPEsQWlB-+9l_l`VTDsB2P5B{^Q(Q{GL~TsOX7x1xvY{-3VX1NdfHDo;#gOibkd? zMFrPV!LlH} zi{%WnQcdtB5}GzQQ8>gL#Jo&wm&#{-uL~hZ5eah<>ncCKzV6WVoZqdES?k?zn`1v{ z>B}(D5bn@ETcHDM8Exh6lmFBs^I}sc>fWQ^Q!TNrgTEGwtoV;=Eor+h3$&(Bg-OgU zYmc!tT)#9ms5~0i=N`e@`uP60sA^QU%peO!D|8Fl#s5)l-5%^ zXpbw^4xk*j-th>9Hf6?YTuPQaF^A(HWJi?xnSvh+y^Z1hiC=34AcBQlHp$PPBv+*- z$V2vbM)Cx7zK;i#v$WI2BhYE^s~lk$WL?qp@qA{p{df-Or1Rna`vp{_^cvf_X< zn&k5jgbr#c>>#Nzi`FleB`<}c-e*J#egp!pS(SnYo-xFm5g~Mu5lquxi7h{Lpdc-i zVsl95Iseg00j0wJ^R`7RI?l*83%hLmob=`F6Mg^sTi0lVW>0eNETLM!xegT#-bdL@ ze6?CFzrw=SoENde#X8)j(VXTY|%ZSmnoV}8JcAccaO*iwnbO<>HL?n+lB zdPD8uraBPSJGNN6z0ChylL)oF%sZbFnNtsr z)U_wPjbyZGag=^9=mU`OOr(^We!Vujw<-W~^j}Y&^H8Y3>)%&E-w1f+0 za)>3Iir-tFFIT5)(iOaTd9QtwjrwA_`7v$`i`XoBH5D6Nf-S4ye!4RNQz8yf49}<1 zRTcgq>SsSo?YeThkoo<_b0ANfdvblq3v-xYa@$76;r;mEA3S_Vebwy^3iHI2?((Q+ z(y0}TDMrvVe|ZvBBvs`i3aRZgl&k%DBwlu&@#L?DAm;XzjbrY8#;@t=>|QP&+~?~O z&fM^ET(=>?>4FySmGnccZ;g>&0;NH-7hRYKU#(Fk6?2}uep%x{(=(Or*f*6n=&WYz+o%&eQa!>||Xh1!sB<4k@tM*F8w>LJ!_7vI9 WV6`b5zShTY6<};&s$Z?=68#^V=?Gl_ literal 0 HcmV?d00001 diff --git a/frontend/src/components/ChatBot.css b/frontend/src/components/ChatBot.css index 332cb42..6b879db 100644 --- a/frontend/src/components/ChatBot.css +++ b/frontend/src/components/ChatBot.css @@ -44,4 +44,21 @@ padding: 10px; resize: none; width: 100%; +} + +.chat-bot-description { + align-items: center; + display: flex; + flex-direction: row; + justify-content: start; + padding-top: 10px; + width: 100%; +} + +.chat-bot-description-label { + color: white; + font-family: sans-serif; + font-size: 20px; + padding-bottom: 5px; + padding-right: 5px; } \ No newline at end of file diff --git a/frontend/src/components/ChatBot.jsx b/frontend/src/components/ChatBot.jsx index 8e1354e..d7b2174 100644 --- a/frontend/src/components/ChatBot.jsx +++ b/frontend/src/components/ChatBot.jsx @@ -2,18 +2,19 @@ import { useEffect, useState } from 'react'; import { Modal, SmallModal } from './Modal'; -import { NewChatBot } from '../../wailsjs/go/main/App'; +import { LoginChatBot, UpdateChatBotUrl } from '../../wailsjs/go/main/App'; import './ChatBot.css'; export function ChatBotModal(props) { const [error, setError] = useState(''); + const [loggedIn, setLoggedIn] = useState(props.loggedIn); const [password, setPassword] = useState(''); const [saving, setSaving] = useState(false); const updatePassword = (event) => setPassword(event.target.value); - const [url, setUrl] = useState(''); + const [url, setUrl] = useState(props.streamUrl); const updateUrl = (event) => setUrl(event.target.value); - const [username, setUsername] = useState(''); + const [username, setUsername] = useState(props.username); const updateUsername = (event) => setUsername(event.target.value); useEffect(() => { @@ -22,21 +23,36 @@ export function ChatBotModal(props) { // let p = password; // let u = url; // props.onSubmit(user, p, u); - NewChatBot(props.cid, username, password, url) - .then(() => { - reset(); - props.onClose(); - }) - .catch((error) => { - setSaving(false); - setError(error); - console.log('Error creating new chat bot:', error); - }); + // NewChatBot(props.cid, username, password, url) + if (loggedIn) { + UpdateChatBotUrl(props.cid, url) + .then(() => { + reset(); + props.onUpdate(url); + }) + .catch((error) => { + setSaving(false); + setError(error); + console.log('Error updating chat bot:', error); + }); + } else { + LoginChatBot(props.cid, username, password, url) + .then(() => { + reset(); + props.onLogin(); + }) + .catch((error) => { + setSaving(false); + setError(error); + console.log('Error creating new chat bot:', error); + }); + } } }, [saving]); const reset = () => { setError(''); + setLoggedIn(false); setPassword(''); setSaving(false); setUrl(''); @@ -48,13 +64,18 @@ export function ChatBotModal(props) { props.onClose(); }; + const logout = () => { + reset(); + props.onLogout(); + }; + const submit = () => { if (username === '') { setError('Add username'); return; } - if (password === '') { + if (password === '' && !loggedIn) { setError('Add password'); return; } @@ -78,8 +99,10 @@ export function ChatBotModal(props) { onClose={close} show={props.show} style={{ minWidth: '300px', maxWidth: '400px' }} - cancelButton={'Cancel'} + cancelButton={loggedIn ? '' : 'Cancel'} onCancel={close} + deleteButton={loggedIn ? 'Logout' : ''} + onDelete={logout} submitButton={saving ? 'Saving' : 'Save'} onSubmit={ saving @@ -91,27 +114,40 @@ export function ChatBotModal(props) { title={'Chat Bot'} >
- {/* {error && {error}} */} -
- Username - -
-
- Password - -
+ {loggedIn ? ( +
+ Logged in: + + {username} + +
+ ) : ( +
+ Username + +
+ )} + {!loggedIn && ( +
+ Password + +
+ )}
Stream URL
{props.title} +
+ + +