forked from njones/socketio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.v1.go
157 lines (128 loc) · 4.49 KB
/
server.v1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package socketio
import (
"context"
"errors"
"net/http"
"strings"
"sync"
nmem "github.com/njones/socketio/adaptor/transport/memory"
eio "github.com/njones/socketio/engineio"
eiot "github.com/njones/socketio/engineio/transport"
siop "github.com/njones/socketio/protocol"
siot "github.com/njones/socketio/transport"
)
// The 3rd revision (included in [email protected]) can be found here: https://github.com/socketio/socket.io-protocol/tree/v3
// https://socket.io/blog/introducing-socket-io-1-0
// https://socket.io/blog/socket-io-1-4-0/
// https://socket.io/blog/socket-io-1-4-5/
// ServerV1 is the same as the javascript SocketIO v1.0 server.
type ServerV1 struct {
inSocketV1
run func(socketID SocketID, req *Request) error
doConnectPacket func(socketID SocketID, socket siot.Socket, req *Request) error
doDisconnectPacket func(socketID SocketID, socket siot.Socket, req *Request) error
doEventPacket func(socketID SocketID, socket siot.Socket) error
doAckPacket func(socketID SocketID, socket siot.Socket) error
path *string
ctx context.Context
eio eio.EIOServer
transport siot.Transporter
}
// NewServerV1 returns a new v1.0 SocketIO server
func NewServerV1(opts ...Option) *ServerV1 {
v1 := &ServerV1{inSocketV1: inSocketV1{ʟ: new(sync.RWMutex), x: new(sync.Mutex)}}
v1.new(opts...)
v1.eio = eio.NewServerV2(
eio.WithPath(*v1.path),
eio.WithInitialPackets(autoConnect(v1, siop.NewPacketV2)),
).(eio.EIOServer)
v1.eio.With(opts...)
v1.With(opts...)
return v1
}
// new returns a new ServerV1 with the different options. This should be called
// when setting up a new server, as it sets up the defaults. The defaults can
// be over written by the Options. Note that the Options can also include options
// that can be applied to the underlining engineIO server.
func (v1 *ServerV1) new(opts ...Option) Server {
v1.run = runV1(v1)
v1.doConnectPacket = doConnectPacket(v1)
v1.doDisconnectPacket = doDisconnectPacket(v1)
v1.doEventPacket = doEventPacket(v1)
v1.doAckPacket = doAckPacket(v1)
v1.ns = "/"
v1.path = ampersand("/socket.io/")
v1.events = make(map[Namespace]map[Event]map[SocketID]eventCallback)
v1.onConnect = make(map[Namespace]onConnectCallbackVersion1)
v1.protectedEventName = v1ProtectedEventName
v1.transport = nmem.NewInMemoryTransport(siop.NewPacketV2) // set the default transport
v1.inSocketV1.binary = true // for the v1 implementation this always is set to true
v1.inSocketV1.compress = true // for the v1 implementation this always is set to true
// v1.inSocketV1.tr = func() siot.Transporter { return v1.transport }
v1.inSocketV1.setTransporter(v1.transport)
return v1
}
func (v1 *ServerV1) With(opts ...Option) {
for _, opt := range opts {
opt(v1)
}
}
func (v1 *ServerV1) In(room Room) inToEmit {
rtn := v1.clone()
rtn.setIsServer(true)
return rtn.In(room)
}
func (v1 *ServerV1) Of(ns Namespace) inSocketV1 {
rtn := v1.clone()
v1.setIsServer(true)
return rtn.Of(ns)
}
func (v1 *ServerV1) To(room Room) inToEmit {
rtn := v1.clone()
rtn.setIsServer(true)
return rtn.To(room)
}
// ServeHTTP is the interface for applying a http request/response cycle. This handles
// errors that can be provided by the underlining serveHTTP method that uses errors.
func (v1 *ServerV1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if v1.path != nil && !strings.HasPrefix(r.URL.Path, *v1.path) { // lock to the default socketio path if present
return
}
ctx := r.Context()
if v1.ctx != nil {
ctx = v1.ctx
}
if err := v1.serveHTTP(w, r.WithContext(ctx)); err != nil {
switch {
case
errors.Is(err, eiot.ErrTimeoutSocket),
errors.Is(err, eiot.ErrCloseSocket),
errors.Is(err, eio.EOH):
return
case
errors.Is(err, eio.HTTPStatusError400),
errors.Is(err, eio.ErrNoSessionID),
errors.Is(err, eio.ErrNoEIOVersion),
errors.Is(err, eio.ErrNoTransport),
errors.Is(err, eio.ErrBadRequestMethod):
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// serveHTTP is the same as ServeHTTP but uses errors to break out of request cycles that
// have an error. The response is handled in the upper ServeHTTP method.
func (v1 *ServerV1) serveHTTP(w http.ResponseWriter, r *http.Request) (err error) {
eioTransport, err := v1.eio.ServeTransport(w, r)
if err != nil {
return err
}
sid, err := v1.transport.Add(eioTransport)
if err != nil {
return err
}
v1.setSocketID(sid)
return v1.run(sid, sioRequest(r))
}