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  }