backend for xcvr appview
at main 120 lines 5.1 kB view raw
1package handler 2 3import ( 4 "github.com/gorilla/sessions" 5 "net/http" 6 7 "os" 8 "rvcx/internal/db" 9 "rvcx/internal/log" 10 "rvcx/internal/model" 11 "rvcx/internal/oauth" 12 "rvcx/internal/recordmanager" 13) 14 15type Handler struct { 16 db *db.Store 17 sessionStore *sessions.CookieStore 18 router *http.ServeMux 19 logger *log.Logger 20 oauth *oauth.Service 21 model *model.Model 22 rm *recordmanager.RecordManager 23} 24 25func New(db *db.Store, logger *log.Logger, oauthserv *oauth.Service, model *model.Model, recordmanager *recordmanager.RecordManager) *Handler { 26 mux := http.NewServeMux() 27 sessionStore := sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY"))) 28 h := &Handler{db, sessionStore, mux, logger, oauthserv, model, recordmanager} 29 // lrc handlers 30 mux.HandleFunc("GET /lrc/{user}/{rkey}/ws", h.WithCORS(h.acceptWebsocket)) 31 mux.HandleFunc("DELETE /lrc/{user}/{rkey}/ws", h.oauthMiddleware(h.deleteChannel)) 32 mux.HandleFunc("POST /lrc/channel", h.oauthMiddleware(h.postChannel)) 33 mux.HandleFunc("POST /lrc/message", h.oauthMiddleware(h.postMessage)) 34 mux.HandleFunc("POST /lrc/image", h.oauthMiddleware(h.uploadImage)) 35 mux.HandleFunc("POST /lrc/media", h.oauthMiddleware(h.postMedia)) 36 mux.HandleFunc("GET /lrc/image", h.WithCORS(h.getImage)) 37 mux.HandleFunc("POST /lrc/mymessage", h.postMyMessage) 38 // xcvr handlers 39 mux.HandleFunc("POST /xcvr/profile", h.oauthMiddleware(h.postProfile)) 40 mux.HandleFunc("POST /xcvr/beep", h.oauthMiddleware(h.beep)) 41 // lexicon handlers 42 mux.HandleFunc("GET /xrpc/org.xcvr.feed.getChannels", h.WithCORS(h.getChannels)) 43 mux.HandleFunc("GET /xrpc/org.xcvr.feed.getChannel", h.WithCORS(h.getChannel)) 44 mux.HandleFunc("GET /xrpc/org.xcvr.lrc.getMessages", h.WithCORS(h.getMessages)) 45 mux.HandleFunc("GET /xrpc/org.xcvr.lrc.getHistory", h.WithCORS(h.getHistory)) 46 mux.HandleFunc("GET /xrpc/org.xcvr.lrc.getImage", h.WithCORS(h.getImage)) 47 mux.HandleFunc("GET /xrpc/org.xcvr.actor.resolveChannel", h.WithCORS(h.resolveChannel)) 48 mux.HandleFunc("GET /xrpc/org.xcvr.actor.getProfileView", h.WithCORS(h.getProfileView)) 49 mux.HandleFunc("GET /xrpc/org.xcvr.lrc.subscribeLexStream", h.WithCORS(h.subscribeLexStream)) 50 mux.HandleFunc("GET /xrpc/org.xcvr.actor.getLastSeen", h.WithCORS(h.getLastSeen)) 51 // backend metadata handlers 52 mux.HandleFunc(clientMetadataPath(), h.WithCORS(h.serveClientMetadata)) 53 mux.HandleFunc(clientTOSPath(), h.WithCORS(h.serveTOS)) 54 mux.HandleFunc(clientPolicyPath(), h.WithCORS(h.servePolicy)) 55 // oauth handlers 56 mux.HandleFunc(oauthJWKSPath(), h.WithCORS(h.serveJWKS)) 57 mux.HandleFunc("POST /oauth/login", h.oauthLogin) 58 mux.HandleFunc("POST /oauth/logout", h.oauthMiddleware(h.oauthLogout)) 59 mux.HandleFunc("POST /oauth/ban", h.postBan) 60 mux.HandleFunc("GET /oauth/ban", h.getBan) 61 mux.HandleFunc("GET /oauth/whoami", h.getSession) 62 mux.HandleFunc(oauthCallbackPath(), h.WithCORS(h.oauthCallback)) 63 return h 64} 65 66func (h *Handler) badRequest(w http.ResponseWriter, err error) { 67 h.logger.Deprintln(err.Error()) 68 w.Header().Set("Content-Type", "application/json") 69 http.Error(w, `{ 70 "error":"Invalid JSON", 71 "message":"Could not parse request body" 72 }`, http.StatusBadRequest) 73} 74 75func (h *Handler) serverError(w http.ResponseWriter, err error) { 76 h.logger.Println(err.Error()) 77 w.Header().Set("Content-Type", "application/json") 78 http.Error(w, `{"error":"Internal server error", "message":"Something went wrong"}`, http.StatusInternalServerError) 79} 80 81func (h *Handler) notFound(w http.ResponseWriter, err error) { 82 h.logger.Println(err.Error()) 83 w.Header().Set("Content-Type", "application/json") 84 http.Error(w, `{"error":"Not Found","message":"I couldn't find your resource"}`, http.StatusNotFound) 85} 86 87func (h *Handler) WithCORSAll() http.Handler { 88 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 89 h.logger.Deprintf("incoming request: %s %s", r.Method, r.URL.Path) 90 w.Header().Set("Access-Control-Allow-Origin", "http://localhost:5173") 91 w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") 92 w.Header().Set("Access-Control-Allow-Headers", "Content-Type") 93 if r.Method == "OPTIONS" { 94 w.WriteHeader(http.StatusNoContent) 95 return 96 } 97 h.router.ServeHTTP(w, r) 98 }) 99} 100 101func (h *Handler) WithCORS(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { 102 return func(w http.ResponseWriter, r *http.Request) { 103 w.Header().Set("Access-Control-Allow-Origin", "*") 104 w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") 105 w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorizaton, X-Requested-With, Sec-WebSocket-Protocol, Sec-WebSocket-Extensions, Sec-WebSocket-Key, Sec-WebSocket-Version") 106 w.Header().Set("Access-Control-Allow-Credentials", "true") 107 if r.Method == "Options" { 108 w.WriteHeader(http.StatusOK) 109 return 110 } 111 f(w, r) 112 } 113} 114 115func (h *Handler) Serve() http.Handler { 116 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 117 h.logger.Deprintf("incoming request: %s %s", r.Method, r.URL.Path) 118 h.router.ServeHTTP(w, r) 119 }) 120}