package grasp import ( "context" "fmt" "net/http" "os" "fiatjaf.com/nostr" "fiatjaf.com/nostr/khatru" ) type GraspServer struct { ServiceURL string RepositoryDir string Relay *khatru.Relay Log func(str string, args ...any) OnWrite func(context.Context, nostr.PubKey, string) (reject bool, reason string) OnRead func(context.Context, nostr.PubKey, string) (reject bool, reason string) } // New creates a new GraspServer and registers its handlers on the relay's router func New(rl *khatru.Relay, repositoryDir string) *GraspServer { gs := &GraspServer{ Relay: rl, RepositoryDir: repositoryDir, Log: func(str string, args ...any) { fmt.Fprintf(os.Stderr, str, args...) }, } rl.Info.AddSupportedNIP("34") rl.Info.SupportedGrasps = append(rl.Info.SupportedGrasps, "GRASP-01") base := rl.Router() mux := http.NewServeMux() // use specific route patterns for git endpoints mux.HandleFunc("GET /{npub}/{repo}/info/refs", func(w http.ResponseWriter, r *http.Request) { gs.handleGitRequest(w, r, base, gs.handleInfoRefs) }) mux.HandleFunc("POST /{npub}/{repo}/git-upload-pack", func(w http.ResponseWriter, r *http.Request) { gs.handleGitRequest(w, r, base, gs.handleGitUploadPack) }) mux.HandleFunc("POST /{npub}/{repo}/git-receive-pack", func(w http.ResponseWriter, r *http.Request) { gs.handleGitRequest(w, r, base, gs.handleGitReceivePack) }) mux.HandleFunc("GET /{npub}/{repo}", func(w http.ResponseWriter, r *http.Request) { gs.handleGitRequest(w, r, base, func(w http.ResponseWriter, r *http.Request, pubkey nostr.PubKey, repoName string) { if r.URL.RawQuery == "" { if gs.repoExists(r.Context(), pubkey, repoName) { gs.serveRepoPage(w, r, r.PathValue("npub"), repoName) } else { http.NotFound(w, r) } } else { base.ServeHTTP(w, r) } }) }) // fallback handler for all other paths mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { base.ServeHTTP(w, r) }) rl.SetRouter(mux) return gs }