130 lines
2.4 KiB
Go
130 lines
2.4 KiB
Go
|
package engineio
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"net"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"github.com/googollee/go-socket.io/engineio/frame"
|
||
|
"github.com/googollee/go-socket.io/engineio/packet"
|
||
|
"github.com/googollee/go-socket.io/engineio/session"
|
||
|
"github.com/googollee/go-socket.io/engineio/transport"
|
||
|
)
|
||
|
|
||
|
// Pauser is connection which can be paused and resumes.
|
||
|
type Pauser interface {
|
||
|
Pause()
|
||
|
Resume()
|
||
|
}
|
||
|
|
||
|
// Opener is client connection which need receive open message first.
|
||
|
type Opener interface {
|
||
|
Open() (transport.ConnParameters, error)
|
||
|
}
|
||
|
|
||
|
type client struct {
|
||
|
conn transport.Conn
|
||
|
params transport.ConnParameters
|
||
|
transport string
|
||
|
context interface{}
|
||
|
close chan struct{}
|
||
|
closeOnce sync.Once
|
||
|
}
|
||
|
|
||
|
func (c *client) SetContext(v interface{}) {
|
||
|
c.context = v
|
||
|
}
|
||
|
|
||
|
func (c *client) Context() interface{} {
|
||
|
return c.context
|
||
|
}
|
||
|
|
||
|
func (c *client) ID() string {
|
||
|
return c.params.SID
|
||
|
}
|
||
|
|
||
|
func (c *client) Transport() string {
|
||
|
return c.transport
|
||
|
}
|
||
|
|
||
|
func (c *client) Close() error {
|
||
|
c.closeOnce.Do(func() {
|
||
|
close(c.close)
|
||
|
})
|
||
|
return c.conn.Close()
|
||
|
}
|
||
|
|
||
|
func (c *client) NextReader() (session.FrameType, io.ReadCloser, error) {
|
||
|
for {
|
||
|
ft, pt, r, err := c.conn.NextReader()
|
||
|
if err != nil {
|
||
|
return 0, nil, err
|
||
|
}
|
||
|
|
||
|
switch pt {
|
||
|
case packet.PONG:
|
||
|
if err = c.conn.SetReadDeadline(time.Now().Add(c.params.PingInterval + c.params.PingTimeout)); err != nil {
|
||
|
return 0, nil, err
|
||
|
}
|
||
|
|
||
|
case packet.CLOSE:
|
||
|
c.Close()
|
||
|
return 0, nil, io.EOF
|
||
|
|
||
|
case packet.MESSAGE:
|
||
|
return session.FrameType(ft), r, nil
|
||
|
}
|
||
|
|
||
|
r.Close()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *client) NextWriter(typ session.FrameType) (io.WriteCloser, error) {
|
||
|
return c.conn.NextWriter(frame.Type(typ), packet.MESSAGE)
|
||
|
}
|
||
|
|
||
|
func (c *client) URL() url.URL {
|
||
|
return c.conn.URL()
|
||
|
}
|
||
|
|
||
|
func (c *client) LocalAddr() net.Addr {
|
||
|
return c.conn.LocalAddr()
|
||
|
}
|
||
|
|
||
|
func (c *client) RemoteAddr() net.Addr {
|
||
|
return c.conn.RemoteAddr()
|
||
|
}
|
||
|
|
||
|
func (c *client) RemoteHeader() http.Header {
|
||
|
return c.conn.RemoteHeader()
|
||
|
}
|
||
|
|
||
|
func (c *client) serve() {
|
||
|
defer c.conn.Close()
|
||
|
|
||
|
for {
|
||
|
select {
|
||
|
case <-c.close:
|
||
|
return
|
||
|
case <-time.After(c.params.PingInterval):
|
||
|
}
|
||
|
|
||
|
w, err := c.conn.NextWriter(frame.String, packet.PING)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if err := w.Close(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if err = c.conn.SetWriteDeadline(time.Now().Add(c.params.PingInterval + c.params.PingTimeout)); err != nil {
|
||
|
fmt.Printf("set writer's deadline error,msg:%s\n", err.Error())
|
||
|
}
|
||
|
}
|
||
|
}
|