Skip to content

Commit

Permalink
feat(example): performance optimization and add concurrent lock suppo…
Browse files Browse the repository at this point in the history
…rt (#13)
  • Loading branch information
StellarisW committed Feb 4, 2023
1 parent b7b0e0f commit 9a7e600
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 16 deletions.
12 changes: 5 additions & 7 deletions examples/chat/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ var (

// Client is a middleman between the websocket connection and the hub.
type Client struct {
hub *Hub

// The websocket connection.
conn *websocket.Conn

Expand All @@ -53,7 +51,7 @@ type Client struct {
// reads from this goroutine.
func (c *Client) readPump() {
defer func() {
c.hub.unregister <- c
hub.unregister <- c
c.conn.Close()
}()
c.conn.SetReadLimit(maxMessageSize)
Expand All @@ -68,7 +66,7 @@ func (c *Client) readPump() {
break
}
message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
c.hub.broadcast <- message
hub.broadcast <- message
}
}

Expand Down Expand Up @@ -119,10 +117,10 @@ func (c *Client) writePump() {
}

// serveWs handles websocket requests from the peer.
func serveWs(ctx *app.RequestContext, hub *Hub) {
func serveWs(ctx *app.RequestContext) {
err := upgrader.Upgrade(ctx, func(conn *websocket.Conn) {
client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)}
client.hub.register <- client
client := &Client{conn: conn, send: make(chan []byte, 256)}
hub.register <- client

go client.writePump()
client.readPump()
Expand Down
41 changes: 34 additions & 7 deletions examples/chat/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@

package main

import (
"sync"
)

// Hub maintains the set of active clients and broadcasts messages to the
// clients.
type Hub struct {
// Registered clients.
clients map[*Client]bool
clients map[*Client]struct{}
clientsLock sync.RWMutex

// Inbound messages from the clients.
broadcast chan []byte
Expand All @@ -23,25 +28,24 @@ type Hub struct {
unregister chan *Client
}

var hub = newHub()

func newHub() *Hub {
return &Hub{
broadcast: make(chan []byte),
register: make(chan *Client),
unregister: make(chan *Client),
clients: make(map[*Client]bool),
clients: make(map[*Client]struct{}),
}
}

func (h *Hub) run() {
for {
select {
case client := <-h.register:
h.clients[client] = true
h.Register(client)
case client := <-h.unregister:
if _, ok := h.clients[client]; ok {
delete(h.clients, client)
close(client.send)
}
h.Unregister(client)
case message := <-h.broadcast:
for client := range h.clients {
select {
Expand All @@ -54,3 +58,26 @@ func (h *Hub) run() {
}
}
}

func (h *Hub) Register(client *Client) {
h.AddClient(client)
}

func (h *Hub) AddClient(client *Client) {
h.clientsLock.Lock()
defer h.clientsLock.Unlock()
h.clients[client] = struct{}{}
}

func (h *Hub) Unregister(client *Client) {
h.DelClient(client)
}

func (h *Hub) DelClient(client *Client) {
h.clientsLock.Lock()
defer h.clientsLock.Unlock()
if _, ok := h.clients[client]; ok {
delete(h.clients, client)
close(client.send)
}
}
3 changes: 1 addition & 2 deletions examples/chat/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ func serveHome(_ context.Context, c *app.RequestContext) {
}

func main() {
hub := newHub()
go hub.run()
// server.Default() creates a Hertz with recovery middleware.
// If you need a pure hertz, you can use server.New()
Expand All @@ -49,7 +48,7 @@ func main() {

h.GET("/", serveHome)
h.GET("/ws", func(c context.Context, ctx *app.RequestContext) {
serveWs(ctx, hub)
serveWs(ctx)
})

h.Spin()
Expand Down

0 comments on commit 9a7e600

Please sign in to comment.