aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillermo Serrahima <dev@vylion.com>2026-03-20 01:18:24 +0100
committerGuillermo Serrahima <dev@vylion.com>2026-03-20 19:55:05 +0100
commitd52fd6ba58a883a49f5b691d4db53e5d1fc78e61 (patch)
treeb4f43324c439f8e935be00a67aeeb16a2967f68f
parentc2472b20ae056bee40cec95fe11bbbef04651d52 (diff)
downloadllostre-d52fd6ba58a883a49f5b691d4db53e5d1fc78e61.tar.xz
llostre-d52fd6ba58a883a49f5b691d4db53e5d1fc78e61.zip
Single post handler
-rw-r--r--backend/fetchers/app.bsky.feed.go2
-rw-r--r--backend/main.go44
-rw-r--r--backend/notes/note.go9
3 files changed, 55 insertions, 0 deletions
diff --git a/backend/fetchers/app.bsky.feed.go b/backend/fetchers/app.bsky.feed.go
index 1b9acc1..5d87cca 100644
--- a/backend/fetchers/app.bsky.feed.go
+++ b/backend/fetchers/app.bsky.feed.go
@@ -152,6 +152,8 @@ func FetchParents(logger *slog.Logger, replyToURI string, slingshotURL string, s
note, err := GetAppBskyFeedPostByURI(logger, currentURI, slingshotURL, session, cache)
if err != nil {
logger.Warn("failed to fetch parent", "uri", currentURI, "error", err)
+ cache.Set(currentURI, notes.MissingNote(currentURI))
+ parents = append(parents, currentURI)
break
}
diff --git a/backend/main.go b/backend/main.go
index 234d57d..c7a463e 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -7,6 +7,7 @@ import (
"llostre/backend/fetchers"
"log/slog"
"net/http"
+ "net/url"
"os"
"strings"
"sync"
@@ -317,6 +318,48 @@ func postsHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(posts)
}
+func postHandler(w http.ResponseWriter, r *http.Request) {
+ uri := strings.TrimPrefix(r.URL.Path, "/api/post/")
+ if uri == "" {
+ http.Error(w, "uri required", http.StatusBadRequest)
+ return
+ }
+
+ // decode if URL-encoded
+ uri, err := url.QueryUnescape(uri)
+ if err != nil {
+ http.Error(w, "invalid uri", http.StatusBadRequest)
+ return
+ }
+
+ var currentSession *auth.OAuthState
+ cookie, err := r.Cookie("session_token")
+ if err != nil {
+ logger.Warn("unauthorized")
+ } else {
+ sessionsMutex.RLock()
+ session, exists := sessions[cookie.Value]
+ sessionsMutex.RUnlock()
+
+ if !exists {
+ logger.Warn("invalid session")
+ } else {
+ refreshTokens(session, cookie.Value)
+
+ currentSession = session
+ }
+ }
+
+ note, err := fetchers.GetAppBskyFeedPostByURI(logger, uri, slingshotURL, currentSession, cache)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(note)
+}
+
func main() {
// serve static files
fs := http.FileServer(http.Dir("../frontend/dist"))
@@ -327,5 +370,6 @@ func main() {
http.HandleFunc("/api/session", sessionHandler)
http.HandleFunc("/api/login", loginHandler)
http.HandleFunc("/api/callback", callbackHandler)
+ http.HandleFunc("/api/post/", postHandler) // /api/post/{uri}
http.ListenAndServe("0.0.0.0:8080", nil)
}
diff --git a/backend/notes/note.go b/backend/notes/note.go
index 591caff..569188c 100644
--- a/backend/notes/note.go
+++ b/backend/notes/note.go
@@ -26,6 +26,15 @@ type Facet struct {
Value string `json:"value"` // the link destination, whether url, profile or tag
}
+func MissingNote(uri string) *Note {
+ return &Note{
+ URI: uri,
+ AuthorDID: "MISSING",
+ Text: "This post could not be fetched. It may have been deleted.",
+ CreatedAt: time.Time{},
+ }
+}
+
func isChainContained(smallChain, bigChain []string) bool {
if len(smallChain) > len(bigChain) {
return false