diff --git a/main.go b/main.go index 3d01f3a..65811cc 100644 --- a/main.go +++ b/main.go @@ -1,16 +1,50 @@ package main import ( + "embed" + "html" "net/http" "os" + "text/template" "github.com/rs/zerolog" ) -var log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}). - With().Timestamp().Logger() +//go:embed static/* +var static embed.FS + +//go:embed templates/* +var templates embed.FS + +var ( + tmpl *template.Template + templateMapping = make(map[string]string) + + log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() +) func main() { + // initialize templates + // use a mapping to expressly link the templates and share them between more kinds/types + templateMapping["profile"] = "profile.html" + templateMapping["note"] = "note.html" + templateMapping["address"] = "other.html" + templateMapping["relay"] = "relay.html" + + funcMap := template.FuncMap{ + "basicFormatting": basicFormatting, + "mdToHTML": mdToHTML, + "escapeString": html.EscapeString, + "sanitizeXSS": sanitizeXSS, + } + + tmpl = template.Must( + template.New("tmpl"). + Funcs(funcMap). + ParseFS(templates, "templates/*"), + ) + + // routes http.HandleFunc("/njump/image/", generate) http.HandleFunc("/njump/proxy/", proxy) http.Handle("/njump/static/", http.StripPrefix("/njump/", http.FileServer(http.FS(static)))) diff --git a/render.go b/render.go index ff3ad10..996d88a 100644 --- a/render.go +++ b/render.go @@ -2,27 +2,18 @@ package main import ( "context" - "embed" _ "embed" "encoding/json" "fmt" - "html" "net/http" "regexp" "strings" - "text/template" "time" "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip19" ) -//go:embed static/* -var static embed.FS - -//go:embed templates/* -var templates embed.FS - type Event struct { Nevent string Content string @@ -50,8 +41,15 @@ func render(w http.ResponseWriter, r *http.Request) { hostname := r.Header.Get("X-Forwarded-Host") style := getPreviewStyle(r) + // code can be a nevent, nprofile, npub or nip05 identifier, in which case we try to fetch the associated event event, err := getEvent(r.Context(), code) if err != nil { + // this will fail if code is a relay URL, in which case we will handle it differently + if urlMatcher.MatchString(code) { + renderRelayPage(w, r) + return + } + http.Error(w, "error fetching event: "+err.Error(), 404) return } @@ -275,30 +273,11 @@ func render(w http.ResponseWriter, r *http.Request) { "parentNevent": parentNevent, } - // Use a mapping to expressly link the templates and share them between more kinds/types - templateMapping := make(map[string]string) - templateMapping["profile"] = "profile.html" - templateMapping["note"] = "note.html" - templateMapping["address"] = "other.html" - - // If a mapping is not found fallback to raw + // if a mapping is not found fallback to raw if templateMapping[typ] == "" { templateMapping[typ] = "other.html" } - funcMap := template.FuncMap{ - "basicFormatting": basicFormatting, - "mdToHTML": mdToHTML, - "escapeString": html.EscapeString, - "sanitizeXSS": sanitizeXSS, - } - - tmpl := template.Must( - template.New("tmpl"). - Funcs(funcMap). - ParseFS(templates, "templates/*"), - ) - w.Header().Set("Cache-Control", "max-age=604800") if err := tmpl.ExecuteTemplate(w, templateMapping[typ], params); err != nil { log.Error().Err(err).Msg("error rendering") diff --git a/render_relay.go b/render_relay.go new file mode 100644 index 0000000..ac0230e --- /dev/null +++ b/render_relay.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + "github.com/nbd-wtf/go-nostr" + "github.com/nbd-wtf/go-nostr/nip11" + "github.com/nbd-wtf/go-nostr/nip19" +) + +func renderRelayPage(w http.ResponseWriter, r *http.Request) { + code := r.URL.Path[1:] + + hostname := code + if strings.HasPrefix(code, "wss://") { + hostname = code[6:] + } + if strings.HasPrefix(code, "ws://") { + hostname = code[5:] + } + + fmt.Println("hostname", hostname) + + ctx, cancel := context.WithTimeout(r.Context(), time.Second*5) + defer cancel() + + // relay metadata + info, _ := nip11.Fetch(r.Context(), code) + if info == nil { + info = &nip11.RelayInformationDocument{ + Name: hostname, + } + } + + // last notes + var lastNotes []*nostr.Event + if relay, err := pool.EnsureRelay(code); err == nil { + lastNotes, _ = relay.QuerySync(ctx, nostr.Filter{ + Kinds: []int{1}, + Limit: 50, + }) + } + renderableLastNotes := make([]*Event, len(lastNotes)) + for i, n := range lastNotes { + nevent, _ := nip19.EncodeEvent(n.ID, []string{}, n.PubKey) + date := time.Unix(int64(n.CreatedAt), 0).Format("2006-01-02 15:04:05") + renderableLastNotes[i] = &Event{ + Nevent: nevent, + Content: n.Content, + CreatedAt: date, + ParentNevent: getParentNevent(n), + } + } + + params := map[string]any{ + "clients": []ClientReference{ + {Name: "Coracle", URL: "https://coracle.social/relays/" + hostname}, + }, + "type": "relay", + "info": info, + "hostname": hostname, + "proxy": "https://" + hostname + "/njump/proxy?src=", + "lastNotes": renderableLastNotes, + } + + w.Header().Set("Cache-Control", "max-age=604800") + if err := tmpl.ExecuteTemplate(w, templateMapping["relay"], params); err != nil { + log.Error().Err(err).Msg("error rendering") + return + } +} diff --git a/templates/head.html b/templates/head.html index 45d16c7..5f1cc15 100644 --- a/templates/head.html +++ b/templates/head.html @@ -55,8 +55,12 @@