// newSocket creates a new socket and initializes it. func newSocket(server *Server, bs backend.BackendSocket) *Socket { // Create a new socket value. s := &Socket{ server: server, bs: bs, id: utils.RandomString(socketIDLength), channels: newChannels(), writeChan: bs.WriteChan(), readChan: bs.ReadChan(), isClosedChan: make(chan struct{}), pingTimer: time.NewTimer(pingPeriod), pingTimeout: time.NewTimer(pingResponseTimeout), } // Create the main channel. s.mainChannel = s.Channel(mainChannelName) // Set the event functions. bs.OnClose(s.onClose) // Stop the timeout again. It will be started by the ping timer. s.pingTimeout.Stop() // Add the new socket to the active sockets map. // If the ID is already present, then generate a new one. func() { // Lock the mutex. s.server.socketsMutex.Lock() defer s.server.socketsMutex.Unlock() // Be sure that the ID is unique. for { if _, ok := s.server.sockets[s.id]; !ok { break } s.id = utils.RandomString(socketIDLength) } // Add the socket to the map. s.server.sockets[s.id] = s }() // Start the loops and handlers in new goroutines. go s.pingTimeoutHandler() go s.readLoop() go s.pingLoop() return s }
func (s *Server) initAjaxRequest(remoteAddr, userAgent string, w http.ResponseWriter) { var uid string // Create a new ajax socket value. a := newSocket(s) a.remoteAddr = remoteAddr a.userAgent = userAgent func() { // Lock the mutex s.socketsMutex.Lock() defer s.socketsMutex.Unlock() // Obtain a new unique ID. for { // Generate it. uid = utils.RandomString(ajaxUIDLength) // Check if the new UID is already used. // This is very unlikely, but we have to check this! _, ok := s.sockets[uid] if !ok { // Break the loop if the UID is unique. break } } // Set the UID. a.uid = uid // Add the new ajax socket to the map. s.sockets[uid] = a }() // Create a new poll token. a.pollToken = utils.RandomString(ajaxPollTokenLength) // Tell the client the UID and poll token. io.WriteString(w, uid+ajaxSocketDataDelimiter+a.pollToken) // Trigger the event that a new socket connection was made. s.onNewSocketConnection(a) }
func (s *Server) pollAjaxRequest(uid, remoteAddr, userAgent, data string, w http.ResponseWriter) { // Obtain the ajax socket with the uid. a := func() *Socket { // Lock the mutex. s.socketsMutex.Lock() defer s.socketsMutex.Unlock() // Obtain the ajax socket with the uid- a, ok := s.sockets[uid] if !ok { return nil } return a }() if a == nil { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, "uid": uid, }).Warningf("ajax: client requested an invalid ajax socket: uid is invalid!") http.Error(w, "Bad Request", 400) return } // The user agents have to match. if a.userAgent != userAgent { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, "uid": uid, "clientUserAgent": userAgent, "socketUserAgent": a.userAgent, }).Warningf("ajax: client poll request: user agents do not match!") http.Error(w, "Bad Request", 400) return } // Check if the poll tokens matches. // The poll token is the data value. if a.pollToken != data { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, "uid": uid, "clientPollToken": data, "socketPollToken": a.pollToken, }).Warningf("ajax: client poll request: poll tokens do not match!") http.Error(w, "Bad Request", 400) return } // Create a new poll token. a.pollToken = utils.RandomString(ajaxPollTokenLength) // Create a timeout timer for the poll. timeout := time.NewTimer(ajaxPollTimeout) defer func() { // Stop the timeout timer. timeout.Stop() }() // Send messages as soon as there are some available. select { case data := <-a.writeChan: // Send the new poll token and message data to the client. io.WriteString(w, a.pollToken+ajaxSocketDataDelimiter+data) case <-timeout.C: // Tell the client that this ajax connection has reached the timeout. io.WriteString(w, ajaxPollCmdTimeout) case <-a.closer.IsClosedChan: // Tell the client that this ajax connection is closed. io.WriteString(w, ajaxPollCmdClosed) } }