1package socketio
2
3import (
4	"net/http"
5
6	engineio "github.com/googollee/go-socket.io/engineio"
7)
8
9// Server is a go-socket.io server.
10type Server struct {
11	handlers map[string]*namespaceHandler
12	eio      *engineio.Server
13}
14
15// NewServer returns a server.
16func NewServer(c *engineio.Options) (*Server, error) {
17	eio, err := engineio.NewServer(c)
18	if err != nil {
19		return nil, err
20	}
21	return &Server{
22		handlers: make(map[string]*namespaceHandler),
23		eio:      eio,
24	}, nil
25}
26
27// Close closes server.
28func (s *Server) Close() error {
29	return s.eio.Close()
30}
31
32func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
33	s.eio.ServeHTTP(w, r)
34}
35
36// OnConnect set a handler function f to handle open event for
37// namespace nsp.
38func (s *Server) OnConnect(nsp string, f func(Conn) error) {
39	h := s.getNamespace(nsp, true)
40	h.OnConnect(f)
41}
42
43// OnDisconnect set a handler function f to handle disconnect event for
44// namespace nsp.
45func (s *Server) OnDisconnect(nsp string, f func(Conn, string)) {
46	h := s.getNamespace(nsp, true)
47	h.OnDisconnect(f)
48}
49
50// OnError set a handler function f to handle error for namespace nsp.
51func (s *Server) OnError(nsp string, f func(Conn, error)) {
52	h := s.getNamespace(nsp, true)
53	h.OnError(f)
54}
55
56// OnEvent set a handler function f to handle event for namespace nsp.
57func (s *Server) OnEvent(nsp, event string, f interface{}) {
58	h := s.getNamespace(nsp, true)
59	h.OnEvent(event, f)
60}
61
62// Serve serves go-socket.io server
63func (s *Server) Serve() error {
64	for {
65		conn, err := s.eio.Accept()
66		if err != nil {
67			return err
68		}
69		go s.serveConn(conn)
70	}
71}
72
73// JoinRoom joins given connection to the room
74func (s *Server) JoinRoom(namespace string, room string, connection Conn) bool {
75	nspHandler := s.getNamespace(namespace, false)
76	if nspHandler != nil {
77		nspHandler.broadcast.Join(room, connection)
78		return true
79	}
80	return false
81}
82
83// LeaveRoom leaves given connection from the room
84func (s *Server) LeaveRoom(namespace string, room string, connection Conn) bool {
85	nspHandler := s.getNamespace(namespace, false)
86	if nspHandler != nil {
87		nspHandler.broadcast.Leave(room, connection)
88		return true
89	}
90	return false
91}
92
93// LeaveAllRooms leaves the given connection from all rooms
94func (s *Server) LeaveAllRooms(namespace string, connection Conn) bool {
95	nspHandler := s.getNamespace(namespace, false)
96	if nspHandler != nil {
97		nspHandler.broadcast.LeaveAll(connection)
98		return true
99	}
100	return false
101}
102
103// ClearRoom clears the room
104func (s *Server) ClearRoom(namespace string, room string) bool {
105	nspHandler := s.getNamespace(namespace, false)
106	if nspHandler != nil {
107		nspHandler.broadcast.Clear(room)
108		return true
109	}
110	return false
111}
112
113// BroadcastToRoom broadcasts given event & args to all the connections in the room
114func (s *Server) BroadcastToRoom(namespace string, room, event string, args ...interface{}) bool {
115	nspHandler := s.getNamespace(namespace, false)
116	if nspHandler != nil {
117		nspHandler.broadcast.Send(room, event, args...)
118		return true
119	}
120	return false
121}
122
123// RoomLen gives number of connections in the room
124func (s *Server) RoomLen(namespace string, room string) int {
125	nspHandler := s.getNamespace(namespace, false)
126	if nspHandler != nil {
127		return nspHandler.broadcast.Len(room)
128	}
129	return -1
130}
131
132// Rooms gives list of all the rooms
133func (s *Server) Rooms(namespace string) []string {
134	nspHandler := s.getNamespace(namespace, false)
135	if nspHandler != nil {
136		return nspHandler.broadcast.Rooms(nil)
137	}
138	return nil
139}
140
141// Count number of connections
142func (s *Server) Count() int {
143	return s.eio.Count()
144}
145
146func (s *Server) ForEach(namespace string, room string, f EachFunc) bool {
147	nspHandler := s.getNamespace(namespace, false)
148	if nspHandler != nil {
149		nspHandler.broadcast.ForEach(room, f)
150		return true
151	}
152	return false
153}
154
155func (s *Server) serveConn(c engineio.Conn) {
156	_, err := newConn(c, s.handlers)
157	if err != nil {
158		root := s.handlers[""]
159		if root != nil && root.onError != nil {
160			root.onError(nil, err)
161		}
162		return
163	}
164}
165
166func (s *Server) getNamespace(nsp string, create bool) *namespaceHandler {
167	if nsp == "/" {
168		nsp = ""
169	}
170	ret, ok := s.handlers[nsp]
171	if ok {
172		return ret
173	}
174	if create {
175		handler := newHandler()
176		s.handlers[nsp] = handler
177		return handler
178	} else {
179		return nil
180	}
181}
182