Skip to content

Commit 1b5c301

Browse files
committed
project: the server part of the chat is implemented
1 parent 8bf5c9e commit 1b5c301

File tree

7 files changed

+190
-1
lines changed

7 files changed

+190
-1
lines changed

connection.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package main
2+
3+
import "github.com/gorilla/websocket"
4+
5+
type connection struct {
6+
ws *websocket.Conn
7+
send chan []byte
8+
hub *hub
9+
}
10+
11+
func newConnection(ws *websocket.Conn, hub *hub) connection {
12+
return connection{
13+
ws: ws,
14+
send: make(chan []byte, 256),
15+
hub: hub,
16+
}
17+
}
18+
19+
func (c *connection) read() {
20+
for {
21+
_, message, err := c.ws.ReadMessage()
22+
if err != nil {
23+
break
24+
}
25+
26+
c.hub.broadcast <- message
27+
}
28+
c.ws.Close()
29+
}
30+
31+
func (c *connection) write() {
32+
for message := range c.send {
33+
if err := c.ws.WriteMessage(websocket.TextMessage, message); err != nil {
34+
break
35+
}
36+
}
37+
c.ws.Close()
38+
}

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1-
module github.com/Lapp-coder/websocket-server
1+
module github.com/Lapp-coder/websocket-chat
22

33
go 1.16
4+
5+
require (
6+
github.com/gorilla/websocket v1.4.2
7+
github.com/sirupsen/logrus v1.8.1
8+
)

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
23
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
6+
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
7+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
8+
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
9+
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

handler.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"github.com/gorilla/websocket"
6+
"net/http"
7+
)
8+
9+
var upgrader = websocket.Upgrader{
10+
ReadBufferSize: 1024,
11+
WriteBufferSize: 1024,
12+
}
13+
14+
type handler struct {
15+
hub *hub
16+
}
17+
18+
func newHandler(hub *hub) *handler {
19+
return &handler{hub: hub}
20+
}
21+
22+
func (h *handler) initRoutes() {
23+
http.HandleFunc("/", h.index)
24+
http.HandleFunc("/chat", h.chat)
25+
}
26+
27+
func (h *handler) index(w http.ResponseWriter, r *http.Request) {
28+
fmt.Fprint(w, "<h1>Chat on websockets</h1>")
29+
}
30+
31+
func (h *handler) chat(w http.ResponseWriter, r *http.Request) {
32+
ws, err := upgrader.Upgrade(w, r, nil)
33+
if err != nil {
34+
return
35+
}
36+
37+
conn := newConnection(ws, h.hub)
38+
conn.hub.register <- &conn
39+
defer func() {
40+
conn.hub.unregister <- &conn
41+
}()
42+
43+
go conn.write()
44+
conn.read()
45+
}

hub.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
type hub struct {
4+
connections map[*connection]struct{}
5+
broadcast chan []byte
6+
register chan *connection
7+
unregister chan *connection
8+
}
9+
10+
func newHub() hub {
11+
return hub{
12+
connections: make(map[*connection]struct{}),
13+
broadcast: make(chan []byte),
14+
register: make(chan *connection),
15+
unregister: make(chan *connection),
16+
}
17+
}
18+
19+
func (h *hub) run() {
20+
for {
21+
select {
22+
case conn := <-h.register:
23+
h.connections[conn] = struct{}{}
24+
case conn := <-h.unregister:
25+
if _, ok := h.connections[conn]; ok {
26+
delete(h.connections, conn)
27+
close(conn.send)
28+
}
29+
case message := <-h.broadcast:
30+
for conn := range h.connections {
31+
conn.send <- message
32+
}
33+
}
34+
}
35+
}

main.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
11
package main
22

3+
import (
4+
"context"
5+
"github.com/sirupsen/logrus"
6+
"os"
7+
"os/signal"
8+
"syscall"
9+
)
10+
311
func main() {
12+
hub := newHub()
13+
handler := newHandler(&hub)
14+
handler.initRoutes()
15+
go hub.run()
16+
17+
host := os.Getenv("CHAT_HOST")
18+
port := os.Getenv("CHAT_PORT")
19+
srv := newServer(host, port)
20+
21+
go func() {
22+
if err := srv.start(); err != nil {
23+
logrus.Errorf("failed to start server: %s", err.Error())
24+
}
25+
}()
26+
27+
logrus.Info("server started")
28+
29+
shutdown := make(chan os.Signal)
30+
signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM)
31+
<-shutdown
32+
33+
logrus.Info("server shutdown")
434

35+
if err := srv.shutdown(context.Background()); err != nil {
36+
logrus.Errorf("failed to graceful shutdown server: %s", err.Error())
37+
}
538
}

server.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"net/http"
6+
)
7+
8+
type server struct {
9+
httpServer *http.Server
10+
}
11+
12+
func newServer(host, port string) *server {
13+
return &server{
14+
httpServer: &http.Server{
15+
Addr: host + ":" + port,
16+
},
17+
}
18+
}
19+
20+
func (s *server) start() error {
21+
return s.httpServer.ListenAndServe()
22+
}
23+
24+
func (s *server) shutdown(ctx context.Context) error {
25+
return s.httpServer.Shutdown(ctx)
26+
}

0 commit comments

Comments
 (0)