Template
1
0
Fork 0

Added coloured logs and fixed a concurrency bug in the localpubsub adapter

This commit is contained in:
Atridad Lahiji 2024-02-06 18:44:45 -07:00
parent e44c858ab3
commit 53e2254795
No known key found for this signature in database
10 changed files with 61 additions and 25 deletions

View file

@ -7,9 +7,10 @@ import (
"github.com/labstack/echo/v4"
"goth.stack/lib"
"goth.stack/lib/pubsub"
)
func SSE(c echo.Context, pubSub lib.PubSub) error {
func SSE(c echo.Context, pubSub pubsub.PubSub) error {
if pubSub == nil {
return errors.New("pubSub is nil")
}

View file

@ -5,9 +5,10 @@ import (
"github.com/labstack/echo/v4"
"goth.stack/lib"
"goth.stack/lib/pubsub"
)
func SSEDemoSend(c echo.Context, pubSub lib.PubSub) error {
func SSEDemoSend(c echo.Context, pubSub pubsub.PubSub) error {
channel := c.QueryParam("channel")
if channel == "" {
channel = "default"

1
go.mod
View file

@ -28,6 +28,7 @@ require (
require (
github.com/alecthomas/assert/v2 v2.4.1
github.com/fatih/color v1.16.0
github.com/go-redis/redismock/v9 v9.2.0
github.com/joho/godotenv v1.5.1
github.com/labstack/echo/v4 v4.11.4

2
go.sum
View file

@ -21,6 +21,8 @@ github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-redis/redismock/v9 v9.2.0 h1:ZrMYQeKPECZPjOj5u9eyOjg8Nnb0BS9lkVIZ6IpsKLw=

View file

@ -2,53 +2,54 @@ package lib
import (
"context"
"log"
"sync"
"time"
"goth.stack/lib/pubsub"
)
type LocalPubSub struct {
subscribers map[string][]chan Message
subscribers map[string][]chan pubsub.Message
lock sync.RWMutex
}
type LocalPubSubMessage struct {
messages <-chan Message
messages <-chan pubsub.Message
}
func (ps *LocalPubSub) SubscribeToChannel(channel string) (PubSubMessage, error) {
func (ps *LocalPubSub) SubscribeToChannel(channel string) (pubsub.PubSubMessage, error) {
ps.lock.Lock()
defer ps.lock.Unlock()
if ps.subscribers == nil {
ps.subscribers = make(map[string][]chan Message)
ps.subscribers = make(map[string][]chan pubsub.Message)
}
ch := make(chan Message, 100)
ch := make(chan pubsub.Message, 100)
ps.subscribers[channel] = append(ps.subscribers[channel], ch)
log.Printf("Subscribed to channel %s", channel)
LogInfo.Printf("[PUBSUB/LOCAL] Subscribed to channel %s", channel)
return &LocalPubSubMessage{messages: ch}, nil
}
func (ps *LocalPubSub) PublishToChannel(channel string, message string) error {
ps.lock.RLock()
defer ps.lock.RUnlock()
ps.lock.Lock() // Changed from RLock to Lock
defer ps.lock.Unlock() // Changed from RUnlock to Unlock
if subscribers, ok := ps.subscribers[channel]; ok {
log.Printf("Publishing message to channel %s: %s", channel, message)
LogInfo.Printf("[PUBSUB/LOCAL] Publishing message to channel %s: %s", channel, message)
for _, ch := range subscribers {
ch <- Message{Payload: message}
ch <- pubsub.Message{Payload: message}
}
} else {
log.Printf("No subscribers for channel %s", channel)
LogWarning.Printf("[PUBSUB/LOCAL] No subscribers for channel %s", channel)
}
return nil
}
func (m *LocalPubSubMessage) ReceiveMessage(ctx context.Context) (*Message, error) {
func (m *LocalPubSubMessage) ReceiveMessage(ctx context.Context) (*pubsub.Message, error) {
for {
select {
case <-ctx.Done():
@ -56,16 +57,16 @@ func (m *LocalPubSubMessage) ReceiveMessage(ctx context.Context) (*Message, erro
return nil, ctx.Err()
case msg := <-m.messages:
// A message has been received. Send it to the client.
log.Printf("Received message: %s", msg.Payload)
LogInfo.Printf("[PUBSUB/LOCAL] Received message: %s", msg.Payload)
return &msg, nil
case <-time.After(30 * time.Second):
// No message has been received for 30 seconds. Send a keep-alive message.
return &Message{Payload: "keep-alive"}, nil
return &pubsub.Message{Payload: "keep-alive"}, nil
}
}
}
func (ps *LocalPubSub) UnsubscribeFromChannel(channel string, ch <-chan Message) {
func (ps *LocalPubSub) UnsubscribeFromChannel(channel string, ch <-chan pubsub.Message) {
ps.lock.Lock()
defer ps.lock.Unlock()

27
lib/logging.go Normal file
View file

@ -0,0 +1,27 @@
package lib
import "github.com/fatih/color"
// Error logging
var red = color.New(color.FgRed)
var LogError = red.Add(color.Bold)
// Info logging
var cyan = color.New(color.FgCyan)
var LogInfo = cyan.Add(color.Bold)
// Success logging
var green = color.New(color.FgGreen)
var LogSuccess = green.Add(color.Bold)
// Warning logging
var yellow = color.New(color.FgYellow)
var LogWarning = yellow.Add(color.Bold)
// Debug logging
var magenta = color.New(color.FgMagenta)
var LogDebug = magenta.Add(color.Bold)
// Custom logging
var white = color.New(color.FgWhite)
var LogCustom = white.Add(color.Bold)

View file

@ -1,4 +1,4 @@
package lib
package pubsub
import "context"

View file

@ -7,6 +7,7 @@ import (
"github.com/joho/godotenv"
"github.com/redis/go-redis/v9"
"goth.stack/lib/pubsub"
)
var RedisClient *redis.Client
@ -39,16 +40,16 @@ func NewRedisClient() *redis.Client {
return RedisClient
}
func (m *RedisPubSubMessage) ReceiveMessage(ctx context.Context) (*Message, error) {
func (m *RedisPubSubMessage) ReceiveMessage(ctx context.Context) (*pubsub.Message, error) {
msg, err := m.pubsub.ReceiveMessage(ctx)
if err != nil {
return nil, err
}
return &Message{Payload: msg.Payload}, nil
return &pubsub.Message{Payload: msg.Payload}, nil
}
func (ps *RedisPubSub) SubscribeToChannel(channel string) (PubSubMessage, error) {
func (ps *RedisPubSub) SubscribeToChannel(channel string) (pubsub.PubSubMessage, error) {
pubsub := ps.Client.Subscribe(context.Background(), channel)
_, err := pubsub.Receive(context.Background())
if err != nil {

View file

@ -9,6 +9,7 @@ import (
"time"
"github.com/labstack/echo/v4"
"goth.stack/lib/pubsub"
)
type SSEServerType struct {
@ -58,7 +59,7 @@ func (s *SSEServerType) ClientCount(channel string) int {
return len(s.clients[channel])
}
func SendSSE(ctx context.Context, messageBroker PubSub, channel string, message string) error {
func SendSSE(ctx context.Context, messageBroker pubsub.PubSub, channel string, message string) error {
// Create a channel to receive an error from the goroutine
errCh := make(chan error, 1)
@ -102,7 +103,7 @@ func CreateTickerAndKeepAlive(c echo.Context, duration time.Duration) *time.Tick
return ticker
}
func HandleIncomingMessages(c echo.Context, pubsub PubSubMessage, client chan string) {
func HandleIncomingMessages(c echo.Context, pubsub pubsub.PubSubMessage, client chan string) {
for {
select {
case <-c.Request().Context().Done():

View file

@ -13,6 +13,7 @@ import (
"goth.stack/api"
"goth.stack/lib"
"goth.stack/lib/pubsub"
"goth.stack/pages"
)
@ -27,7 +28,7 @@ func main() {
_, err := lib.RedisClient.Ping(context.Background()).Result()
// Initialize pubsub
var pubSub lib.PubSub
var pubSub pubsub.PubSub
if err != nil {
log.Printf("Failed to connect to Redis: %v", err)
log.Println("Falling back to LocalPubSub")