package main import ( "context" "io" "log" "net/http" "golang.org/x/time/rate" ) type S struct { ctx context.Context limiter *rate.Limiter config Config } func (s *S) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := s.serveHTTP(w, r); err != nil { log.Println(s.Session(r.Context()), "//", r.URL.Path, "//", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) } } func (s *S) serveHTTP(w http.ResponseWriter, r *http.Request) error { if isV1(r) || isWS(r) { return s.serveAPI(w, r) } return s.serveStatic(w, r) } func (s *S) serveStatic(w http.ResponseWriter, r *http.Request) error { fs := http.Dir(s.config.Root) http.FileServer(fs).ServeHTTP(w, r) return nil } func (s *S) serveAPI(w http.ResponseWriter, r *http.Request) error { if err := s.injectContext(w, r); err == io.EOF { http.Redirect(w, r, "/", http.StatusSeeOther) return nil } else if err != nil { return err } if isWS(r) { return s.serveWS(w, r) } else if isV1(r) { return s.serveV1(w, r) } http.NotFound(w, r) return nil } type Session struct { ID string } func (s *S) injectContext(w http.ResponseWriter, r *http.Request) error { id, err := r.Cookie("uuid") if err != nil || id.Value == "" { return io.EOF } ctx := r.Context() ctx = context.WithValue(ctx, "session", Session{ ID: id.Value, }) *r = *r.WithContext(ctx) return nil } func (s *S) Session(ctx context.Context) Session { v, _ := ctx.Value("session").(Session) return v }