github.com/cnotch/ipchub@v1.1.0/network/websocket/websocket.go (about) 1 /********************************************************************************** 2 * Copyright (c) 2009-2017 Misakai Ltd. 3 * This program is free software: you can redistribute it and/or modify it under the 4 * terms of the GNU Affero General Public License as published by the Free Software 5 * Foundation, either version 3 of the License, or(at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 8 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 9 * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 10 * 11 * You should have received a copy of the GNU Affero General Public License along 12 * with this program. If not, see<http://www.gnu.org/licenses/>. 13 ************************************************************************************/ 14 // 15 // Copyright (c) 2019,CAOHONGJU All rights reserved. 16 // Use of this source code is governed by a MIT-style 17 // license that can be found in the LICENSE file. 18 19 package websocket 20 21 import ( 22 "io" 23 "net" 24 "net/http" 25 "sync" 26 "time" 27 28 "github.com/gorilla/websocket" 29 ) 30 31 // Conn websocket连接 32 type Conn interface { 33 net.Conn 34 Subprotocol() string // 获取子协议 35 TextTransport() Conn // 获取文本传输通道 36 Path() string // 接入时的ws后的路径 37 Username() string // 接入是http验证后的用户名称 38 } 39 40 type websocketConn interface { 41 NextReader() (messageType int, r io.Reader, err error) 42 NextWriter(messageType int) (io.WriteCloser, error) 43 Close() error 44 LocalAddr() net.Addr 45 RemoteAddr() net.Addr 46 SetReadDeadline(t time.Time) error 47 SetWriteDeadline(t time.Time) error 48 Subprotocol() string 49 } 50 51 // websocketConn represents a websocket connection. 52 type websocketTransport struct { 53 sync.Mutex 54 socket websocketConn 55 reader io.Reader 56 closing chan bool 57 path string 58 username string 59 } 60 61 const ( 62 writeWait = 10 * time.Second // Time allowed to write a message to the peer. 63 pongWait = 60 * time.Second // Time allowed to read the next pong message from the peer. 64 pingPeriod = (pongWait * 9) / 10 // Send pings to peer with this period. Must be less than pongWait. 65 closeGracePeriod = 10 * time.Second // Time to wait before force close on connection. 66 ) 67 68 // The default upgrader to use 69 var upgrader = &websocket.Upgrader{ 70 Subprotocols: []string{"rtsp"}, 71 CheckOrigin: func(r *http.Request) bool { return true }, 72 // ReadBufferSize: 64 * 1024, WriteBufferSize: 64 * 1024, 73 } 74 75 // TryUpgrade attempts to upgrade an HTTP request to rtsp/wsp over websocket. 76 func TryUpgrade(w http.ResponseWriter, r *http.Request, path, username string) (Conn, bool) { 77 if w == nil || r == nil { 78 return nil, false 79 } 80 81 if ws, err := upgrader.Upgrade(w, r, nil); err == nil { 82 return newConn(ws, path, username), true 83 } 84 85 return nil, false 86 } 87 88 // newConn creates a new transport from websocket. 89 func newConn(ws websocketConn, path, username string) Conn { 90 conn := &websocketTransport{ 91 socket: ws, 92 closing: make(chan bool), 93 path: path, 94 username: username, 95 } 96 97 /*ws.SetReadLimit(maxMessageSize) 98 ws.SetReadDeadline(time.Now().Add(pongWait)) 99 ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) 100 101 ws.SetCloseHandler(func(code int, text string) error { 102 return conn.Close() 103 }) 104 105 utils.Repeat(func() { 106 log.Println("ping") 107 if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil { 108 log.Println("ping:", err) 109 } 110 }, pingPeriod, conn.closing)*/ 111 112 return conn 113 } 114 115 // Read reads data from the connection. It is possible to allow reader to time 116 // out and return a Error with Timeout() == true after a fixed time limit by 117 // using SetDeadline and SetReadDeadline on the websocket. 118 func (c *websocketTransport) Read(b []byte) (n int, err error) { 119 var opCode int 120 if c.reader == nil { 121 // New message 122 var r io.Reader 123 for { 124 if opCode, r, err = c.socket.NextReader(); err != nil { 125 return 126 } 127 128 if opCode != websocket.BinaryMessage && opCode != websocket.TextMessage { 129 continue 130 } 131 132 c.reader = r 133 break 134 } 135 } 136 137 // Read from the reader 138 n, err = c.reader.Read(b) 139 if err != nil { 140 if err == io.EOF { 141 c.reader = nil 142 err = nil 143 } 144 } 145 return 146 } 147 148 // Write writes data to the connection. It is possible to allow writer to time 149 // out and return a Error with Timeout() == true after a fixed time limit by 150 // using SetDeadline and SetWriteDeadline on the websocket. 151 func (c *websocketTransport) Write(b []byte) (n int, err error) { 152 // Serialize write to avoid concurrent write 153 c.Lock() 154 defer c.Unlock() 155 156 var w io.WriteCloser 157 if w, err = c.socket.NextWriter(websocket.BinaryMessage); err == nil { 158 if n, err = w.Write(b); err == nil { 159 err = w.Close() 160 } 161 } 162 return 163 } 164 165 // Close terminates the connection. 166 func (c *websocketTransport) Close() error { 167 return c.socket.Close() 168 } 169 170 // LocalAddr returns the local network address. 171 func (c *websocketTransport) LocalAddr() net.Addr { 172 return c.socket.LocalAddr() 173 } 174 175 // RemoteAddr returns the remote network address. 176 func (c *websocketTransport) RemoteAddr() net.Addr { 177 return c.socket.RemoteAddr() 178 } 179 180 // SetDeadline sets the read and write deadlines associated 181 // with the connection. It is equivalent to calling both 182 // SetReadDeadline and SetWriteDeadline. 183 func (c *websocketTransport) SetDeadline(t time.Time) (err error) { 184 if err = c.socket.SetReadDeadline(t); err == nil { 185 err = c.socket.SetWriteDeadline(t) 186 } 187 return 188 } 189 190 // SetReadDeadline sets the deadline for future Read calls 191 // and any currently-blocked Read call. 192 func (c *websocketTransport) SetReadDeadline(t time.Time) error { 193 return c.socket.SetReadDeadline(t) 194 } 195 196 // SetWriteDeadline sets the deadline for future Write calls 197 // and any currently-blocked Write call. 198 func (c *websocketTransport) SetWriteDeadline(t time.Time) error { 199 return c.socket.SetWriteDeadline(t) 200 } 201 202 // Subprotocol 获取子协议名称 203 func (c *websocketTransport) Subprotocol() string { 204 return c.socket.Subprotocol() 205 } 206 207 // TextTransport 获取文本传输Conn 208 func (c *websocketTransport) TextTransport() Conn { 209 return &websocketTextTransport{c} 210 } 211 212 func (c *websocketTransport) Path() string { 213 return c.path 214 } 215 216 func (c *websocketTransport) Username() string { 217 return c.username 218 } 219 220 type websocketTextTransport struct { 221 *websocketTransport 222 } 223 224 // Write writes data to the connection. It is possible to allow writer to time 225 // out and return a Error with Timeout() == true after a fixed time limit by 226 // using SetDeadline and SetWriteDeadline on the websocket. 227 func (c *websocketTextTransport) Write(b []byte) (n int, err error) { 228 // Serialize write to avoid concurrent write 229 c.Lock() 230 defer c.Unlock() 231 232 var w io.WriteCloser 233 if w, err = c.socket.NextWriter(websocket.TextMessage); err == nil { 234 if n, err = w.Write(b); err == nil { 235 err = w.Close() 236 } 237 } 238 return 239 }