package main import ( "context" "fmt" "io" "log" "net/http" "strings" "github.com/coder/websocket" "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 isV1(r *http.Request) bool { return strings.HasPrefix(r.URL.Path, "/v1/") } func isWS(r *http.Request) bool { return r.URL.Path == "/ws" || strings.HasPrefix(r.URL.Path, "/ws/") } func (s *S) serveStatic(w http.ResponseWriter, r *http.Request) error { http.FS(http.Dir(s.config.Root)).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 } func (s *S) serveWS(httpw http.ResponseWriter, httpr *http.Request) error { ctx := httpr.Context() c, err := websocket.Accept(httpw, httpr, nil) if err != nil { return err } defer c.CloseNow() if err := c.Write(ctx, 1, []byte("hello world")); err != nil { return err } return fmt.Errorf("not impl") } func (s *S) serveV1(w http.ResponseWriter, r *http.Request) error { return fmt.Errorf("not impl: v1") }