-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathws.go
131 lines (109 loc) · 3.08 KB
/
ws.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
119
120
121
122
123
124
125
126
127
128
129
130
131
// package ws_for_micro provides building simple websocket server with message push.
package ws_for_micro
import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/gorilla/websocket"
)
const (
serverDefaultWSPath = "/ws"
serverDefaultPushPath = "/push"
)
var defaultUpgrader = &websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(*http.Request) bool {
return true
},
}
// Server defines parameters for running websocket server.
type Server struct {
// Address for server to listen on
Addr string
// Path for websocket request, default "/ws".
WSPath string
// Path for push message, default "/push".
PushPath string
// Upgrader is for upgrade connection to websocket connection using
// "github.com/gorilla/websocket".
//
// If Upgrader is nil, default upgrader will be used. Default upgrader is
// set ReadBufferSize and WriteBufferSize to 1024, and CheckOrigin always
// returns true.
Upgrader *websocket.Upgrader
// Check token if it's valid and return userID. If token is valid, userID
// must be returned and ok should be true. Otherwise ok should be false.
AuthToken func(token string) (userID string, ok bool)
// Authorize push request. Message will be sent if it returns true,
// otherwise the request will be discarded. Default nil and push request
// will always be accepted.
PushAuth func(r *http.Request) bool
WH *websocketHandler
PH *pushHandler
}
// ListenAndServe listens on the TCP network address and handle websocket
// request.
// Push filters connections by userID and event, then write message
func (s *Server) Push(userID, event, message string) (int, error) {
return s.PH.push(userID, event, message)
}
func (s *Server) Broadcast(event, message string) (int, error) {
cnt := 0
userIds, _ := s.PH.binder.FindUsers(event)
for _, uid := range userIds {
c, err := s.Push(uid, event, message)
if err != nil {
return cnt, err
}
cnt += c
}
return cnt, nil
}
// Drop find connections by userID and event, then close them. The userID can't
// be empty. The event is ignored if it's empty.
func (s *Server) Drop(userID, event string) (int, error) {
return s.WH.closeConns(userID, event)
}
// Check parameters of Server, returns error if fail.
func (s Server) check() error {
if !checkPath(s.WSPath) {
return fmt.Errorf("WSPath: %s not illegal", s.WSPath)
}
if !checkPath(s.PushPath) {
return fmt.Errorf("PushPath: %s not illegal", s.PushPath)
}
if s.WSPath == s.PushPath {
return errors.New("WSPath is equal to PushPath")
}
return nil
}
// NewServer creates a new Server.
func NewWs() *Server {
b := &binder{
userID2EventConnMap: make(map[string]*[]eventConn),
connID2UserIDMap: make(map[string]string),
}
// websocket request handler
wh := &websocketHandler{
upgrader: defaultUpgrader,
binder: b,
}
// push request handler
ph := &pushHandler{
binder: b,
}
return &Server{
WSPath: serverDefaultWSPath,
PushPath: serverDefaultPushPath,
WH: wh,
PH: ph,
}
}
func checkPath(path string) bool {
if path != "" && !strings.HasPrefix(path, "/") {
return false
}
return true
}