func (server *Server) serveHTTP(w http.ResponseWriter, r *http.Request, tr *itime.Timer) { var ( b *Bucket ok bool hb time.Duration // heartbeat key string cb string err error trd *itime.TimerData conn net.Conn rwr *bufio.ReadWriter hj http.Hijacker // no client send ch = NewChannel(1, define.NoRoom) ) if key, cb, hb, err = server.authHTTP(r, ch); err != nil { http.Error(w, "auth failed", http.StatusForbidden) return } if hj, ok = w.(http.Hijacker); !ok { log.Error("w.(http.Hijacker) type assection failed") http.Error(w, "not support", http.StatusInternalServerError) return } if conn, rwr, err = hj.Hijack(); err != nil { log.Error("hj.Hijack() error(%v)", err) http.Error(w, "not support", http.StatusInternalServerError) return } // register key->channel b = server.Bucket(key) b.Put(key, ch, tr) // hanshake ok start dispatch goroutine server.dispatchHTTP(rwr, cb, ch, hb) tr.Del(trd) conn.Close() b.Del(key) // don't use close chan, Signal can be reused // if chan full, writer goroutine next fetch from chan will exit // if chan empty, send a 0(close) let the writer exit if err = server.operator.Disconnect(key, ch.RoomId); err != nil { log.Error("%s operator do disconnect error(%v)", key, err) } if Debug { log.Debug("%s serverconn goroutine exit", key) } return }
func (server *Server) serveHTTP(w http.ResponseWriter, r *http.Request, tr *Timer) { var ( b *Bucket ch *Channel hb time.Duration // heartbeat key string cb string err error trd *TimerData conn net.Conn rwr *bufio.ReadWriter hj http.Hijacker p = new(Proto) ok bool ) if key, cb, hb, err = server.authHTTP(r, p); err != nil { http.Error(w, "auth failed", http.StatusForbidden) return } if hj, ok = w.(http.Hijacker); !ok { log.Error("w.(http.Hijacker) type assection failed") http.Error(w, "not support", http.StatusInternalServerError) return } if conn, rwr, err = hj.Hijack(); err != nil { log.Error("hj.Hijack() error(%v)", err) http.Error(w, "not support", http.StatusInternalServerError) return } if trd, err = tr.Add(hb, conn); err != nil { log.Error("handshake: timer.Add() error(%v)", err) if err = conn.Close(); err != nil { log.Error("handshake: conn.Close() error(%v)", err) } return } // TODO how to reuse channel // register key->channel b = server.Bucket(key) // no client send ch = NewChannel(0, 1) b.Put(key, ch) // hanshake ok start dispatch goroutine server.dispatchHTTP(rwr, cb, ch) // dialog finish // revoke the subkey // revoke the remote subkey // close the net.Conn // read & write goroutine // return channel to bucket's free list if err = conn.Close(); err != nil { log.Error("conn.Close() error(%v)", err) } b.Del(key) tr.Del(trd) // don't use close chan, Signal can be reused // if chan full, writer goroutine next fetch from chan will exit // if chan empty, send a 0(close) let the writer exit if err = server.operator.Disconnect(key); err != nil { log.Error("%s operator do disconnect error(%v)", key, err) } log.Debug("%s serverconn goroutine exit", key) return }