blossom.go raw

   1  package app
   2  
   3  import (
   4  	"context"
   5  	"net/http"
   6  	"strings"
   7  
   8  	"next.orly.dev/pkg/lol/log"
   9  	"next.orly.dev/app/config"
  10  	"next.orly.dev/pkg/acl"
  11  	"next.orly.dev/pkg/database"
  12  	blossom "next.orly.dev/pkg/blossom"
  13  )
  14  
  15  // initializeBlossomServer creates and configures the Blossom blob storage server
  16  func initializeBlossomServer(
  17  	ctx context.Context, cfg *config.C, db database.Database,
  18  ) (*blossom.Server, error) {
  19  	// Create blossom server configuration
  20  	blossomCfg := &blossom.Config{
  21  		BaseURL:          "", // Will be set dynamically per request
  22  		MaxBlobSize:      100 * 1024 * 1024, // 100MB default
  23  		AllowedMimeTypes: nil,               // Allow all MIME types by default
  24  		RequireAuth:      cfg.AuthRequired || cfg.AuthToWrite,
  25  		// Rate limiting for non-followed users
  26  		RateLimitEnabled: cfg.BlossomRateLimitEnabled,
  27  		DailyLimitMB:     cfg.BlossomDailyLimitMB,
  28  		BurstLimitMB:     cfg.BlossomBurstLimitMB,
  29  		// Delete replay protection (proposed BUD enhancement)
  30  		DeleteRequireServerTag: cfg.BlossomDeleteRequireServerTag,
  31  	}
  32  
  33  	// Create blossom server with relay's ACL registry
  34  	bs := blossom.NewServer(db, acl.Registry, blossomCfg)
  35  
  36  	// Override baseURL getter to use request-based URL
  37  	// We'll need to modify the handler to inject the baseURL per request
  38  	// For now, we'll use a middleware approach
  39  
  40  	if cfg.BlossomRateLimitEnabled {
  41  		log.I.F("blossom server initialized with ACL mode: %s, rate limit: %dMB/day (burst: %dMB)",
  42  			cfg.ACLMode, cfg.BlossomDailyLimitMB, cfg.BlossomBurstLimitMB)
  43  	} else {
  44  		log.I.F("blossom server initialized with ACL mode: %s", cfg.ACLMode)
  45  	}
  46  	return bs, nil
  47  }
  48  
  49  // blossomHandler wraps the blossom server handler to inject baseURL per request
  50  func (s *Server) blossomHandler(w http.ResponseWriter, r *http.Request) {
  51  	// Strip /blossom prefix and pass to blossom handler
  52  	r.URL.Path = strings.TrimPrefix(r.URL.Path, "/blossom")
  53  	if !strings.HasPrefix(r.URL.Path, "/") {
  54  		r.URL.Path = "/" + r.URL.Path
  55  	}
  56  
  57  	// Set baseURL in request context for blossom server to use
  58  	// Use the exported key type from the blossom package
  59  	baseURL := s.ServiceURL(r) + "/blossom"
  60  	r = r.WithContext(context.WithValue(r.Context(), blossom.BaseURLKey{}, baseURL))
  61  
  62  	s.blossomServer.Handler().ServeHTTP(w, r)
  63  }
  64  
  65  // blossomRootHandler handles blossom requests at root level (for clients like Jumble)
  66  // Note: Even though requests come to root-level paths like /upload, we return URLs
  67  // with /blossom prefix because that's where the blob download handlers are registered.
  68  func (s *Server) blossomRootHandler(w http.ResponseWriter, r *http.Request) {
  69  	// Set baseURL with /blossom prefix so returned blob URLs point to working handlers
  70  	baseURL := s.ServiceURL(r) + "/blossom"
  71  	r = r.WithContext(context.WithValue(r.Context(), blossom.BaseURLKey{}, baseURL))
  72  
  73  	s.blossomServer.Handler().ServeHTTP(w, r)
  74  }
  75  
  76