package server import ( "encoding/json" "fmt" "net/http" "gitea.benny.dog/torjus/ezshare/store" "github.com/go-chi/chi/v5" "go.uber.org/zap" ) type HTTPServer struct { Logger *zap.SugaredLogger store store.FileStore serverGRPCCert []byte grpcEndpoint string http.Server } type MetadataResponse struct { GRPCEndpoint string `json:"grpc_endpoint"` } func NewHTTPSever(store store.FileStore, certBytes []byte, grpcEndpoint string) *HTTPServer { srv := &HTTPServer{ Logger: zap.NewNop().Sugar(), store: store, serverGRPCCert: certBytes, grpcEndpoint: grpcEndpoint, } r := chi.NewRouter() r.Get("/server.pem", srv.ServerCertHandler) r.Get("/metadata", srv.MetadataHandler) r.Get("/files/{id}", srv.FileHandler) srv.Handler = r return srv } func (s *HTTPServer) ServerCertHandler(w http.ResponseWriter, r *http.Request) { if _, err := w.Write(s.serverGRPCCert); err != nil { s.Logger.Warnw("Error sending server certificate.", "error", err, "remote_addr", r.RemoteAddr) } s.Logger.Infow("Sent server certificate.", "remote_addr", r.RemoteAddr) } func (s *HTTPServer) MetadataHandler(w http.ResponseWriter, r *http.Request) { md := &MetadataResponse{ GRPCEndpoint: s.grpcEndpoint, } encoder := json.NewEncoder(w) if err := encoder.Encode(md); err != nil { s.Logger.Warnw("Error encoding or sending metadata.", "error", err, "remote_addr", r.RemoteAddr) } s.Logger.Infow("Wrote server cert.", "remote_addr", r.RemoteAddr) } func (s *HTTPServer) FileHandler(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") f, err := s.store.GetFile(id) if err != nil { if err == store.ErrNoSuchItem { s.Logger.Debugw("Tried to get non-existing file.", "remote_addr", r.RemoteAddr) WriteErrorResponse(w, http.StatusNotFound, "file not found") return } s.Logger.Warnw("Error getting file from store.", "error", err, "remote_addr", r.RemoteAddr) WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) return } w.Header().Add("Content-Type", http.DetectContentType(f.Data)) if _, err := w.Write(f.Data); err != nil { s.Logger.Warnw("Error sending file.", "error", err, "remote_addr", r.RemoteAddr) } s.Logger.Infow("Sent file.", "remote_addr", r.RemoteAddr) } func WriteErrorResponse(w http.ResponseWriter, status int, message string) { errMessage := struct { Error string `json:"error"` }{ Error: message, } w.Header().Add("Content-Type", "application/json") w.WriteHeader(status) encoder := json.NewEncoder(w) encoder.Encode(&errMessage) }