initial broken draft of relays page.

This commit is contained in:
fiatjaf
2023-07-11 18:19:11 -03:00
parent bfa2f5f537
commit d734b189d9
7 changed files with 174 additions and 33 deletions

38
main.go
View File

@@ -1,16 +1,50 @@
package main package main
import ( import (
"embed"
"html"
"net/http" "net/http"
"os" "os"
"text/template"
"github.com/rs/zerolog" "github.com/rs/zerolog"
) )
var log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}). //go:embed static/*
With().Timestamp().Logger() 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() { 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/image/", generate)
http.HandleFunc("/njump/proxy/", proxy) http.HandleFunc("/njump/proxy/", proxy)
http.Handle("/njump/static/", http.StripPrefix("/njump/", http.FileServer(http.FS(static)))) http.Handle("/njump/static/", http.StripPrefix("/njump/", http.FileServer(http.FS(static))))

View File

@@ -2,27 +2,18 @@ package main
import ( import (
"context" "context"
"embed"
_ "embed" _ "embed"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html"
"net/http" "net/http"
"regexp" "regexp"
"strings" "strings"
"text/template"
"time" "time"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19" "github.com/nbd-wtf/go-nostr/nip19"
) )
//go:embed static/*
var static embed.FS
//go:embed templates/*
var templates embed.FS
type Event struct { type Event struct {
Nevent string Nevent string
Content string Content string
@@ -50,8 +41,15 @@ func render(w http.ResponseWriter, r *http.Request) {
hostname := r.Header.Get("X-Forwarded-Host") hostname := r.Header.Get("X-Forwarded-Host")
style := getPreviewStyle(r) 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) event, err := getEvent(r.Context(), code)
if err != nil { 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) http.Error(w, "error fetching event: "+err.Error(), 404)
return return
} }
@@ -275,30 +273,11 @@ func render(w http.ResponseWriter, r *http.Request) {
"parentNevent": parentNevent, "parentNevent": parentNevent,
} }
// Use a mapping to expressly link the templates and share them between more kinds/types // if a mapping is not found fallback to raw
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 templateMapping[typ] == "" { if templateMapping[typ] == "" {
templateMapping[typ] = "other.html" 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") w.Header().Set("Cache-Control", "max-age=604800")
if err := tmpl.ExecuteTemplate(w, templateMapping[typ], params); err != nil { if err := tmpl.ExecuteTemplate(w, templateMapping[typ], params); err != nil {
log.Error().Err(err).Msg("error rendering") log.Error().Err(err).Msg("error rendering")

75
render_relay.go Normal file
View File

@@ -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
}
}

View File

@@ -55,8 +55,12 @@
<title>Nostr Address {{.naddr | escapeString }}</title> <title>Nostr Address {{.naddr | escapeString }}</title>
{{end}} {{end}}
<!-----------> <!----------->
{{ if eq .type "relay" }}
<title>Nostr Relay {{.hostname}}</title>
{{end}}
<!----------->
{{ if eq .type "other" }} {{ if eq .type "other" }}
<title>Nostr Event {{.kindID }} - {{.kindDescription | escapeString }}</title> <title>Nostr Event {{.kindID}} - {{.kindDescription | escapeString }}</title>
{{end}} {{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@@ -63,6 +63,7 @@
<div class="field separator"></div> <div class="field separator"></div>
{{if .lastNotes}}
<div class="field last_notes"> <div class="field last_notes">
<h2>Last Notes</h2> <h2>Last Notes</h2>
{{range .lastNotes}} {{range .lastNotes}}
@@ -75,8 +76,8 @@
</a> </a>
{{end}} {{end}}
</div> </div>
<div class="field separator"></div> <div class="field separator"></div>
{{end}}
<div class="field advanced-switch-wrapper"> <div class="field advanced-switch-wrapper">
<input <input

46
templates/relay.html Normal file
View File

@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html class="theme--default">
<meta charset="UTF-8" />
{{template "head.html" .}}
<body class="profile">
{{template "top.html" .}}
<div class="container_wrapper">
<div class="container">
<div class="column columnA">
<div class="info-wrapper">
{{.info.Name | escapeString}}
<span class="display">{{.info.Description | escapeString}}</span>
</div>
<div class="pic-wrapper">
<img class="pic" src="{{.info.Icon | escapeString}}" />
</div>
</div>
<div class="column column_content">
<div class="field last_notes">
<h2>Last Notes</h2>
{{range .lastNotes}}
<a href="/{{.Nevent | escapeString}}" class="note">
<div class="published_at">{{.CreatedAt | escapeString}}</div>
{{if not (eq .ParentNevent "")}}
<div class="is_reply">- reply</div>
{{end}}
<div class="content">{{.Content | escapeString}}</div>
</a>
{{end}}
</div>
</div>
{{template "column_clients.html" .}}
</div>
</div>
{{template "footer.html"}}
<script>
{{template "scripts.js"}}
</script>
</body>
</html>

View File

@@ -92,6 +92,8 @@ var kindNIPS = map[int]string{
30078: "78", 30078: "78",
} }
var urlMatcher = regexp.MustCompile(`^(wss?:\/\/)?[\w-_.]+\.[\w-_.]+(\/[\/\w]*)?$`)
type ClientReference struct { type ClientReference struct {
Name string Name string
URL string URL string