// WSHandler handles request of creating session channel. // // When a channel closed, releases all resources associated with it. func WSHandler(w http.ResponseWriter, r *http.Request) { sid := r.URL.Query()["sid"][0] conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024) wsChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()} ret := map[string]interface{}{"output": "Session initialized", "cmd": "init-session"} err := wsChan.WriteJSON(&ret) if nil != err { return } SessionWS[sid] = &wsChan wSession := WideSessions.Get(sid) if nil == wSession { httpSession, _ := HTTPSession.Get(r, "wide-session") if httpSession.IsNew { return } httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge httpSession.Save(r, w) wSession = WideSessions.new(httpSession, sid) logger.Tracef("Created a wide session [%s] for websocket reconnecting, user [%s]", sid, wSession.Username) } logger.Tracef("Open a new [Session Channel] with session [%s], %d", sid, len(SessionWS)) input := map[string]interface{}{} wsChan.Conn.SetReadDeadline(time.Now().Add(pongWait)) wsChan.Conn.SetPongHandler(func(string) error { wsChan.Conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) ticker := time.NewTicker(pingPeriod) defer func() { WideSessions.Remove(sid) ticker.Stop() wsChan.Close() }() // send websocket ping message. go func(t *time.Ticker, channel util.WSChannel) { for { select { case <-t.C: if err := channel.Conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil { return } } } }(ticker, wsChan) for { if err := wsChan.ReadJSON(&input); err != nil { logger.Tracef("[Session Channel] of session [%s] disconnected, releases all resources with it, user [%s]", sid, wSession.Username) return } ret = map[string]interface{}{"output": "", "cmd": "session-output"} if err := wsChan.WriteJSON(&ret); err != nil { logger.Error("Session WS ERROR: " + err.Error()) return } wsChan.Time = time.Now() } }