-
Notifications
You must be signed in to change notification settings - Fork 1
/
constructor.go
118 lines (105 loc) · 2 KB
/
constructor.go
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package constructor
import (
"fmt"
"log"
"net"
"net/http"
"github.com/gorilla/websocket"
"github.com/s4y/reserve"
)
type Client struct {
Id uint `json:"id"`
State interface{} `json:"state"`
queue chan func(*websocket.Conn)
}
func (c *Client) Close() {
close(c.queue)
}
type Clients struct {
nextId uint
clients map[uint]*Client
queue chan func()
}
func NewClients() Clients {
queue := make(chan func())
go func() {
for f := range queue {
f()
}
}()
return Clients{
nextId: 0,
clients: make(map[uint]*Client),
queue: queue,
}
}
func (cs *Clients) Create(conn *websocket.Conn) *Client {
c := &Client{
Id: cs.nextId,
State: make(map[string]interface{}),
queue: make(chan func(*websocket.Conn)),
}
cs.nextId += 1
go func() {
for f := range c.queue {
f(conn)
}
cs.queue <- func() {
delete(cs.clients, c.Id)
}
}()
cs.queue <- func() {
c.queue <- func(conn *websocket.Conn) {
for _, client := range cs.clients {
conn.WriteJSON(Message{
Name: "update",
Value: client,
})
}
}
for _, client := range cs.clients {
client.queue <- func(conn *websocket.Conn) {
conn.WriteJSON(Message{
Name: "update",
Value: c,
})
}
}
cs.clients[c.Id] = c
}
return c
}
type Server struct {
StaticDir string
HTTPAddr string
}
type Message struct {
Name string `json:"name"`
Value interface{} `json:"value"`
}
func (s *Server) Serve() error {
ln, err := net.Listen("tcp", s.HTTPAddr)
if err != nil {
log.Fatal(err)
}
upgrader := websocket.Upgrader{}
clients := NewClients()
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer conn.Close()
client := clients.Create(conn)
defer client.Close()
for {
var msg Message
if err := conn.ReadJSON(&msg); err != nil {
break
}
fmt.Println("got", msg)
}
})
http.Handle("/", reserve.FileServer(http.Dir(s.StaticDir)))
return http.Serve(ln, nil)
}