From cd709b332ac867a05725a6814f3247e79bf7d51f Mon Sep 17 00:00:00 2001 From: Vincent Vallaeys Date: Tue, 6 Aug 2024 23:18:16 +0200 Subject: [PATCH] feat: Chat colors * chore: optimization + bug fix * docs: added * chore: general utils file * feat: chat colors --- api/cammie.go | 10 ++++++---- api/main.go | 6 ++++++ go.mod | 2 +- main.go | 3 +++ screen/cammie.go | 47 ++++++++++++++++++++++++++++++----------------- screen/main.go | 11 +++++++---- utils/queue.go | 13 +++++++++++++ utils/utils.go | 16 ++++++++++++++++ 8 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 utils/utils.go diff --git a/api/cammie.go b/api/cammie.go index 7e73d24..be2f72a 100644 --- a/api/cammie.go +++ b/api/cammie.go @@ -9,19 +9,21 @@ import ( gin "github.com/gin-gonic/gin" ) +// message struct type message struct { Message string `form:"message" json:"message" xml:"message" binding:"required"` } +// header struct type header struct { Name string `header:"X-Username"` Ip string `header:"X-Real-IP"` } var messages uint64 = 0 -var blockedNames = []string{"Paul-Henri Spaak"} -var blockedIps = []string{} -var maxMessageLength = 200 +var blockedNames = []string{"Paul-Henri Spaak"} // Blocekd names +var blockedIps = []string{} // Blocked IPs +var maxMessageLength = 200 // Maximum message length func getMessage(app *screen.ScreenApp, c *gin.Context) { c.JSON(200, gin.H{"messages": messages}) @@ -57,7 +59,7 @@ func postMessage(app *screen.ScreenApp, c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "Message received"}) return } - newMessage = fmt.Sprintf("[%s] %s", header.Name, message.Message) + newMessage = fmt.Sprintf("[%s[] %s", header.Name, message.Message) } else if header.Ip != "" { if slices.Contains(blockedIps, header.Ip) { c.JSON(http.StatusOK, gin.H{"message": "Message received"}) diff --git a/api/main.go b/api/main.go index 2a5b833..81c019a 100644 --- a/api/main.go +++ b/api/main.go @@ -7,21 +7,27 @@ import ( "github.com/gin-gonic/gin" ) +// Wrapper for the handler functions to pass the screen application func handlerWrapper(app *screen.ScreenApp, callback func(*screen.ScreenApp, *gin.Context)) func(*gin.Context) { return func(ctx *gin.Context) { callback(app, ctx) } } +// Start the API func Start(screenApp *screen.ScreenApp) { gin.SetMode(gin.ReleaseMode) gin.DefaultWriter = io.Discard r := gin.Default() + // Routes + + // Cammie chat routes r.GET("/message", handlerWrapper(screenApp, getMessage)) r.POST("/message", handlerWrapper(screenApp, postMessage)) + // Spotify routes r.POST("/spotify", spotifyHandlerWrapper(screenApp)) r.Run() diff --git a/go.mod b/go.mod index 1235eac..26a2f7f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module scc go 1.22.0 require ( + github.com/gdamore/tcell/v2 v2.7.1 github.com/gin-gonic/gin v1.9.1 github.com/rivo/tview v0.0.0-20240225120200-5605142ca62e ) @@ -12,7 +13,6 @@ require ( github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gdamore/encoding v1.0.0 // indirect - github.com/gdamore/tcell/v2 v2.7.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect diff --git a/main.go b/main.go index 6649361..564f906 100644 --- a/main.go +++ b/main.go @@ -6,9 +6,12 @@ import ( ) func main() { + // Data holder for the screen screenApp := screen.NewScreenApp() + // Start the API go api.Start(screenApp) + // Start the screen screen.Start(screenApp) } diff --git a/screen/cammie.go b/screen/cammie.go index fd35e17..6d9bccf 100644 --- a/screen/cammie.go +++ b/screen/cammie.go @@ -1,7 +1,7 @@ package screen import ( - "scc/utils" + "fmt" "time" "github.com/gdamore/tcell/v2" @@ -11,49 +11,62 @@ import ( // Initial value, gets adjusted once it's known how much space is available var maxMessages = 20 +// Available colors +var COLORS = [...]tcell.Color{ + tcell.ColorViolet, + tcell.ColorRed, + tcell.ColorIndigo, + tcell.ColorYellow, + tcell.ColorBlue, + tcell.ColorGreen, + tcell.ColorOrange, + tcell.ColorLime, + tcell.ColorAqua, + tcell.ColorDarkSalmon, + tcell.ColorLightBlue, + tcell.ColorNavajoWhite, +} +var lastColorIndex = 0 + +// Component that displays messages received from the website aka cammie chat type Cammie struct { screenApp *ScreenApp view *tview.TextView - queue *utils.Queue[string] text string buffer string } +// Create a new cammie struct func NewCammie(screenApp *ScreenApp) *Cammie { cammie := Cammie{ screenApp: screenApp, - view: tview.NewTextView().SetWrap(true).SetWordWrap(true).SetText("pls"), - - queue: utils.NewQueue[string](maxMessages), + view: tview.NewTextView().SetWordWrap(true).SetScrollable(true).SetDynamicColors(true), } cammie.view.SetTitle(" Cammie ") cammie.view.SetBorder(true) - cammie.view.SetTextColor(tcell.ColorOrange) cammie.view.SetBorderColor(tcell.ColorOrange) cammie.view.SetTitleColor(tcell.ColorOrange) return &cammie } +// One-time setup func (cammie *Cammie) Run() { + // Wait for the view to be properly set up time.Sleep(5 * time.Second) - _, _, _, h := cammie.view.GetInnerRect() - cammie.queue.SetMaxSize(h) } +// Updates the cammie chat +// Gets called when a new message is received from the website func (cammie *Cammie) Update(message string) { - cammie.queue.Enqueue(message) + color := COLORS[lastColorIndex].String() + lastColorIndex = (lastColorIndex + 1) % len(COLORS) + + fmt.Fprintf(cammie.view, "\n[%s]%s", color, message) - cammie.screenApp.execute(func() { - cammie.screenApp.app.QueueUpdateDraw(func() { - cammie.view.Clear() + cammie.view.ScrollToEnd() - for _, message := range cammie.queue.Get() { - cammie.view.Write([]byte(message + "\n")) - } - }) - }) } diff --git a/screen/main.go b/screen/main.go index 1bf0336..1576501 100644 --- a/screen/main.go +++ b/screen/main.go @@ -6,6 +6,7 @@ import ( "github.com/rivo/tview" ) +// Main struct for the screen application type ScreenApp struct { mu sync.Mutex app *tview.Application @@ -16,16 +17,14 @@ type ScreenApp struct { Graph2 *Graph2 } -type s_cammie struct { - cammie *tview.TextView -} - +// Execute a function with a lock func (screenApp *ScreenApp) execute(f func()) { screenApp.mu.Lock() defer screenApp.mu.Unlock() f() } +// Create a new screen application func NewScreenApp() *ScreenApp { screen := ScreenApp{ app: tview.NewApplication(), @@ -36,6 +35,7 @@ func NewScreenApp() *ScreenApp { screen.Graph1 = NewGraph1(&screen) screen.Graph2 = NewGraph2(&screen) + // Build the screen layout screen.app.SetRoot(tview.NewFlex().SetDirection(tview.FlexRow). AddItem(screen.Spotify.view, 3, 2, false). AddItem(tview.NewFlex(). @@ -48,13 +48,16 @@ func NewScreenApp() *ScreenApp { return &screen } +// Start the screen application func Start(screen *ScreenApp) { + // Start each screen component go screen.Spotify.Run() go screen.Cammie.Run() go screen.Graph1.Run() go screen.Graph2.Run() + // Start the screen application if err := screen.app.Run(); err != nil { panic(err) } diff --git a/utils/queue.go b/utils/queue.go index 9a0ef81..a04ea58 100644 --- a/utils/queue.go +++ b/utils/queue.go @@ -1,10 +1,12 @@ package utils +// Simple Queue implementation type Queue[T any] struct { maxSize int Items []T } +// Create a new Queue with a maximum size func NewQueue[T any](maxSize int) *Queue[T] { return &Queue[T]{ maxSize: maxSize, @@ -12,6 +14,7 @@ func NewQueue[T any](maxSize int) *Queue[T] { } } +// Add an item to the Queue func (q *Queue[T]) Enqueue(item T) { if len(q.Items) >= q.maxSize { q.Items = q.Items[1:] @@ -19,6 +22,7 @@ func (q *Queue[T]) Enqueue(item T) { q.Items = append(q.Items, item) } +// Remove an item from the Queue func (q *Queue[T]) Dequeue() (T, bool) { if len(q.Items) == 0 { var zero T @@ -30,6 +34,7 @@ func (q *Queue[T]) Dequeue() (T, bool) { return item, true } +// Get the first item in the Queue wtihout removing it func (q *Queue[T]) Peek() (T, bool) { if len(q.Items) == 0 { var zero T @@ -39,10 +44,18 @@ func (q *Queue[T]) Peek() (T, bool) { return q.Items[0], true } +// Get all items in the Queue func (q *Queue[T]) Get() []T { return q.Items } +// Get the size of the Queue +func (q *Queue[T]) Size() int { + return len(q.Items) +} + +// Set the maximum size of the Queue +// If the new maximum size is smaller than the current size, the Queue will be truncated and items will potentially be lost func (q *Queue[T]) SetMaxSize(maxSize int) { q.maxSize = maxSize diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..db4314a --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,16 @@ +package utils + +import ( + "math/rand/v2" + "time" +) + +func RandRange(min, max int) int { + return rand.IntN(max-min) + min +} + +func TimeAndDateFormat() string { + currentTime := time.Now() + formattedTime := currentTime.Format("15:04 02/01") + return formattedTime +}