mirror of
https://github.com/aljazceru/njump.git
synced 2025-12-17 14:24:27 +01:00
initial broken draft of relays page.
This commit is contained in:
38
main.go
38
main.go
@@ -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))))
|
||||||
|
|||||||
37
render.go
37
render.go
@@ -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
75
render_relay.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,10 @@
|
|||||||
<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}}
|
||||||
|
|||||||
@@ -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
46
templates/relay.html
Normal 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>
|
||||||
Reference in New Issue
Block a user