@@ -34,8 +34,9 @@ type Client struct {
3434}
3535
3636type ClientMessage struct {
37- Info ClientInfo
38- Incoming Event
37+ Info ClientInfo
38+ SkipConnectedCheck bool
39+ Incoming Event
3940}
4041
4142type ClientInfo struct {
@@ -44,7 +45,6 @@ type ClientInfo struct {
4445 Authenticated bool
4546 AuthenticatedUser string
4647 Write chan outgoing.Message
47- Close chan string
4848 Addr net.IP
4949}
5050
@@ -63,36 +63,46 @@ func newClient(conn *websocket.Conn, req *http.Request, read chan ClientMessage,
6363 RoomID : "" ,
6464 Addr : ip ,
6565 Write : make (chan outgoing.Message , 1 ),
66- Close : make (chan string , 1 ),
6766 },
6867 read : read ,
6968 }
7069 client .debug ().Msg ("WebSocket New Connection" )
71- conn .SetCloseHandler (func (code int , text string ) error {
72- message := websocket .FormatCloseMessage (code , text )
73- client .debug ().Str ("reason" , text ).Int ("code" , code ).Msg ("WebSocket Close" )
74- return conn .WriteControl (websocket .CloseMessage , message , time .Now ().Add (writeWait ))
75- })
7670 return client
7771}
7872
79- // Close closes the connection.
80- func (c * Client ) Close ( ) {
73+ // CloseOnError closes the connection.
74+ func (c * Client ) CloseOnError ( code int , reason string ) {
8175 c .once .Do (func () {
82- c .conn .Close ()
8376 go func () {
8477 c .read <- ClientMessage {
85- Info : c .info ,
86- Incoming : & Disconnected {},
78+ Info : c .info ,
79+ Incoming : & Disconnected {
80+ Code : code ,
81+ Reason : reason ,
82+ },
8783 }
8884 }()
85+ c .writeCloseMessage (code , reason )
8986 })
9087}
9188
89+ func (c * Client ) CloseOnDone (code int , reason string ) {
90+ c .once .Do (func () {
91+ c .writeCloseMessage (code , reason )
92+ })
93+ }
94+
95+ func (c * Client ) writeCloseMessage (code int , reason string ) {
96+ message := websocket .FormatCloseMessage (code , reason )
97+ c .conn .WriteControl (websocket .CloseMessage , message , time .Now ().Add (writeWait ))
98+ c .conn .Close ()
99+ }
100+
92101// startWriteHandler starts listening on the client connection. As we do not need anything from the client,
93102// we ignore incoming messages. Leaves the loop on errors.
94103func (c * Client ) startReading (pongWait time.Duration ) {
95- defer c .Close ()
104+ defer c .CloseOnError (websocket .CloseNormalClosure , "Reader Routine Closed" )
105+
96106 _ = c .conn .SetReadDeadline (time .Now ().Add (pongWait ))
97107 c .conn .SetPongHandler (func (appData string ) error {
98108 _ = c .conn .SetReadDeadline (time .Now ().Add (pongWait ))
@@ -101,17 +111,17 @@ func (c *Client) startReading(pongWait time.Duration) {
101111 for {
102112 t , m , err := c .conn .NextReader ()
103113 if err != nil {
104- c .printWebSocketError ( "read" , err )
114+ c .CloseOnError ( websocket . CloseNormalClosure , "read error: " + err . Error () )
105115 return
106116 }
107117 if t == websocket .BinaryMessage {
108- _ = c . conn . CloseHandler ()( websocket .CloseUnsupportedData , fmt . Sprintf ( "unsupported binary message type: %s" , err ) )
118+ c . CloseOnError ( websocket .CloseUnsupportedData , "unsupported binary message type" )
109119 return
110120 }
111121
112122 incoming , err := ReadTypedIncoming (m )
113123 if err != nil {
114- _ = c . conn . CloseHandler ()( websocket .CloseNormalClosure , fmt .Sprintf ("malformed message: %s" , err ))
124+ c . CloseOnError ( websocket .CloseUnsupportedData , fmt .Sprintf ("malformed message: %s" , err ))
115125 return
116126 }
117127 c .debug ().Interface ("event" , fmt .Sprintf ("%T" , incoming )).Interface ("payload" , incoming ).Msg ("WebSocket Receive" )
@@ -125,38 +135,26 @@ func (c *Client) startReading(pongWait time.Duration) {
125135// * on errors exit the loop.
126136func (c * Client ) startWriteHandler (pingPeriod time.Duration ) {
127137 pingTicker := time .NewTicker (pingPeriod )
128-
129- dead := false
130- conClosed := func () {
131- dead = true
132- c .Close ()
133- pingTicker .Stop ()
134- }
135- defer conClosed ()
138+ defer pingTicker .Stop ()
136139 defer func () {
137140 c .debug ().Msg ("WebSocket Done" )
138141 }()
142+ defer c .conn .Close ()
139143 for {
140144 select {
141- case reason := <- c .info .Close :
142- if reason == CloseDone {
143- return
144- } else {
145- _ = c .conn .CloseHandler ()(websocket .CloseNormalClosure , reason )
146- conClosed ()
147- }
148145 case message := <- c .info .Write :
149- if dead {
150- c .debug ().Msg ("WebSocket write on dead connection" )
151- continue
146+ if msg , ok := message .(outgoing.CloseWriter ); ok {
147+ c .debug ().Str ("reason" , msg .Reason ).Int ("code" , msg .Code ).Msg ("WebSocket Close" )
148+ c .CloseOnDone (msg .Code , msg .Reason )
149+ return
152150 }
153151
154152 _ = c .conn .SetWriteDeadline (time .Now ().Add (writeWait ))
155153 typed , err := ToTypedOutgoing (message )
156154 c .debug ().Interface ("event" , typed .Type ).Interface ("payload" , typed .Payload ).Msg ("WebSocket Send" )
157155 if err != nil {
158156 c .debug ().Err (err ).Msg ("could not get typed message, exiting connection." )
159- conClosed ( )
157+ c . CloseOnError ( websocket . CloseNormalClosure , "malformed outgoing " + err . Error () )
160158 continue
161159 }
162160
@@ -165,14 +163,14 @@ func (c *Client) startWriteHandler(pingPeriod time.Duration) {
165163 }
166164
167165 if err := writeJSON (c .conn , typed ); err != nil {
168- conClosed ()
169166 c .printWebSocketError ("write" , err )
167+ c .CloseOnError (websocket .CloseNormalClosure , "write error" + err .Error ())
170168 }
171169 case <- pingTicker .C :
172170 _ = c .conn .SetWriteDeadline (time .Now ().Add (writeWait ))
173171 if err := ping (c .conn ); err != nil {
174- conClosed ()
175172 c .printWebSocketError ("ping" , err )
173+ c .CloseOnError (websocket .CloseNormalClosure , "ping timeout" )
176174 }
177175 }
178176 }
0 commit comments