aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authoralex <[email protected]>2026-07-10 20:46:30 +0200
committeralex <[email protected]>2026-07-10 20:46:30 +0200
commitc51e7f6d095153fa4d5358216271aeb4ad73ee0c (patch)
treea5de8cd1db65ed4049b0ed41e67c1fcbf3372e76 /pkg
parent0b064307a01e5eba65a22b2d3df7e51054beaff7 (diff)
downloadredis-clone-c51e7f6d095153fa4d5358216271aeb4ad73ee0c.tar.xz
redis-clone-c51e7f6d095153fa4d5358216271aeb4ad73ee0c.zip
turn pubsub into separate package
Diffstat (limited to 'pkg')
-rw-r--r--pkg/pubsub/pubsub.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/pkg/pubsub/pubsub.go b/pkg/pubsub/pubsub.go
new file mode 100644
index 0000000..690606c
--- /dev/null
+++ b/pkg/pubsub/pubsub.go
@@ -0,0 +1,106 @@
+package pubsub
+
+import (
+ "net"
+ "redisClone/pkg/core"
+ "sync"
+)
+
+type Hub struct {
+ mu sync.RWMutex
+ Channels map[string]map[net.Conn]struct{}
+}
+
+func NewHub() *Hub {
+ return &Hub{
+ Channels: make(map[string]map[net.Conn]struct{}),
+ }
+}
+
+func (h *Hub) Subscribe(conn net.Conn, channel string) int {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if _, exists := h.Channels[channel]; !exists {
+ h.Channels[channel] = make(map[net.Conn]struct{})
+ }
+ h.Channels[channel][conn] = struct{}{}
+
+ subCount := 0
+ for _, subscribers := range h.Channels {
+ if _, ok := subscribers[conn]; ok {
+ subCount++
+ }
+ }
+ return subCount
+}
+
+func (h *Hub) Unsubscribe(conn net.Conn, channels []string) map[string]int {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if len(channels) == 0 {
+ for channel, subscribers := range h.Channels {
+ if _, ok := subscribers[conn]; ok {
+ channels = append(channels, channel)
+ }
+ }
+ }
+
+ results := make(map[string]int)
+
+ for _, channel := range channels {
+ if subscribers, exists := h.Channels[channel]; exists {
+ delete(subscribers, conn)
+ if len(subscribers) == 0 {
+ delete(h.Channels, channel)
+ }
+ }
+
+ count := 0
+ for _, subs := range h.Channels {
+ if _, ok := subs[conn]; ok {
+ count++
+ }
+ }
+ results[channel] = count
+ }
+ return results
+}
+
+func (h *Hub) Publish(channel, message string) int {
+ h.mu.RLock()
+ subscribers, exists := h.Channels[channel]
+ if !exists || len(subscribers) == 0 {
+ h.mu.RUnlock()
+ return 0
+ }
+
+ conns := make([]net.Conn, 0, len(subscribers))
+ for conn := range subscribers {
+ conns = append(conns, conn)
+ }
+ h.mu.RUnlock()
+
+ payload := core.SerializeRESP([]string{"message", channel, message})
+ count := 0
+ for _, conn := range conns {
+ _, err := conn.Write(payload)
+ if err == nil {
+ count++
+ }
+ }
+ return count
+}
+
+func (h *Hub) HandleDisconnect(conn net.Conn) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ for channel, subscribers := range h.Channels {
+ delete(subscribers, conn)
+ if len(subscribers) == 0 {
+ delete(h.Channels, channel)
+ }
+ }
+} \ No newline at end of file