aboutsummaryrefslogtreecommitdiff
path: root/internal/chat/chan.go
blob: bc2b70f3d246aa52c5925c318253812078fb9c4a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package chat

import (
	"context"
	"log/slog"
	"sync"
	"time"
)

type Channel struct {
	Name   string
	Users  map[*User]struct{}
	Events chan any
	mu     sync.RWMutex
}

func (c *Channel) Listen(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		case ev := <-c.Events:
			c.processEvent(ev)
		}
	}
}

func (c *Channel) processEvent(ev any) {
	slog.Info("channel event", slog.String("channel", c.Name), slog.Any("event", ev))

	for u := range c.Users {
		if ev, ok := ev.(Message); ok {
			if ev.User == u {
				// Do not return user message to him
				continue
			}
		}
		select {
		case u.Events <- ev:
		default:
		}
	}
}

func (c *Channel) Join(u *User) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if _, ok := c.Users[u]; ok {
		return
	}
	c.Events <- UserJoined{
		User: u,
		Time: time.Now(),
		Chan: c,
	}

	c.Users[u] = struct{}{}
}

func (c *Channel) Leave(u *User) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if _, ok := c.Users[u]; !ok {
		return
	}
	c.Events <- UserLeft{
		User: u,
		Time: time.Now(),
		Chan: c,
	}

	delete(c.Users, u)
}