github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/igm/sockjs-go.v2/sockjs/httpreceiver.go (about) 1 package sockjs 2 3 import ( 4 "fmt" 5 "io" 6 "net/http" 7 "strings" 8 "sync" 9 ) 10 11 type frameWriter interface { 12 write(writer io.Writer, frame string) (int, error) 13 } 14 15 type httpReceiverState int 16 17 const ( 18 stateHTTPReceiverActive httpReceiverState = iota 19 stateHTTPReceiverClosed 20 ) 21 22 type httpReceiver struct { 23 sync.Mutex 24 state httpReceiverState 25 26 frameWriter frameWriter 27 rw http.ResponseWriter 28 maxResponseSize uint32 29 currentResponseSize uint32 30 doneCh chan struct{} 31 interruptCh chan struct{} 32 } 33 34 func newHTTPReceiver(rw http.ResponseWriter, maxResponse uint32, frameWriter frameWriter) *httpReceiver { 35 recv := &httpReceiver{ 36 rw: rw, 37 frameWriter: frameWriter, 38 maxResponseSize: maxResponse, 39 doneCh: make(chan struct{}), 40 interruptCh: make(chan struct{}), 41 } 42 if closeNotifier, ok := rw.(http.CloseNotifier); ok { 43 // if supported check for close notifications from http.RW 44 closeNotifyCh := closeNotifier.CloseNotify() 45 go func() { 46 select { 47 case <-closeNotifyCh: 48 recv.Lock() 49 defer recv.Unlock() 50 if recv.state < stateHTTPReceiverClosed { 51 recv.state = stateHTTPReceiverClosed 52 close(recv.interruptCh) 53 } 54 case <-recv.doneCh: 55 // ok, no action needed here, receiver closed in correct way 56 // just finish the routine 57 } 58 }() 59 } 60 return recv 61 } 62 63 func (recv *httpReceiver) sendBulk(messages ...string) { 64 if len(messages) > 0 { 65 recv.sendFrame(fmt.Sprintf("a[%s]", 66 strings.Join( 67 transform(messages, quote), 68 ",", 69 ), 70 )) 71 } 72 } 73 74 func (recv *httpReceiver) sendFrame(value string) { 75 recv.Lock() 76 defer recv.Unlock() 77 78 if recv.state == stateHTTPReceiverActive { 79 // TODO(igm) check err, possibly act as if interrupted 80 n, _ := recv.frameWriter.write(recv.rw, value) 81 recv.currentResponseSize += uint32(n) 82 if recv.currentResponseSize >= recv.maxResponseSize { 83 recv.state = stateHTTPReceiverClosed 84 close(recv.doneCh) 85 } else { 86 recv.rw.(http.Flusher).Flush() 87 } 88 } 89 } 90 91 func (recv *httpReceiver) doneNotify() <-chan struct{} { return recv.doneCh } 92 func (recv *httpReceiver) interruptedNotify() <-chan struct{} { return recv.interruptCh } 93 func (recv *httpReceiver) close() { 94 recv.Lock() 95 defer recv.Unlock() 96 if recv.state < stateHTTPReceiverClosed { 97 recv.state = stateHTTPReceiverClosed 98 close(recv.doneCh) 99 } 100 } 101 func (recv *httpReceiver) canSend() bool { 102 recv.Lock() 103 defer recv.Unlock() 104 return recv.state != stateHTTPReceiverClosed 105 }