backend for xcvr appview

add getimage

Changed files
+148 -31
server
internal
+18
server/internal/atputils/blob.go
··· 1 + package atputils 2 + 3 + import ( 4 + "context" 5 + "net/http" 6 + 7 + "github.com/bluesky-social/indigo/api/atproto" 8 + "github.com/bluesky-social/indigo/atproto/client" 9 + ) 10 + 11 + func SyncGetBlob(did string, cid string, ctx context.Context) ([]byte, error) { 12 + host, err := GetPDSFromDid(ctx, did, http.DefaultClient) 13 + if err != nil { 14 + return nil, err 15 + } 16 + c := client.NewAPIClient(host) 17 + return atproto.SyncGetBlob(ctx, c, cid, did) 18 + }
+32
server/internal/db/lexicon.go
··· 398 398 image.URI = uri 399 399 return &image, nil 400 400 } 401 + 402 + func (s *Store) GetImageDidCID(did string, cid string, ctx context.Context) (*types.Image, error) { 403 + row := s.pool.QueryRow(ctx, `SELECT FROM images ( 404 + uri, 405 + signet_uri, 406 + blob_cid, 407 + blob_mime, 408 + alt, 409 + height, 410 + width, 411 + nick, 412 + color, 413 + posted_at 414 + ) WHERE did = $1 AND cid = $2`, did, cid) 415 + var image types.Image 416 + err := row.Scan(&image.URI, 417 + &image.SignetURI, 418 + &image.BlobCID, 419 + &image.BlobMIME, 420 + &image.Alt, 421 + &image.Height, 422 + &image.Width, 423 + &image.Nick, 424 + &image.Color, 425 + &image.PostedAt) 426 + if err != nil { 427 + return nil, errors.New("effor storing image: " + err.Error()) 428 + } 429 + image.DID = did 430 + image.CID = cid 431 + return &image, nil 432 + }
+1 -1
server/internal/handler/handler.go
··· 33 33 mux.HandleFunc("POST /lrc/message", h.oauthMiddleware(h.postMessage)) 34 34 mux.HandleFunc("POST /lrc/image", h.oauthMiddleware(h.uploadImage)) 35 35 mux.HandleFunc("POST /lrc/media", h.oauthMiddleware(h.postMedia)) 36 - // mux.HandleFunc("GET /lrc/image", h.getImage) 36 + mux.HandleFunc("GET /lrc/image", h.WithCORS(h.getImage)) 37 37 mux.HandleFunc("POST /lrc/mymessage", h.postMyMessage) 38 38 // xcvr handlers 39 39 mux.HandleFunc("POST /xcvr/profile", h.oauthMiddleware(h.postProfile))
+97 -30
server/internal/handler/lrcHandlers.go
··· 206 206 return &mr, nil 207 207 } 208 208 209 - // func (h *Handler) getImage(w http.ResponseWriter, r *http.Request) { 210 - // vals := r.URL.Query() 211 - // uri := vals.Get("uri") 212 - // if uri == "" { 213 - // h.badRequest(w, errors.New("must provide a did and cid")) 214 - // return 215 - // } 216 - // image, err := h.db.GetImage(uri, r.Context()) 217 - // if err != nil { 218 - // h.notFound(w, err) 219 - // return 220 - // } 221 - // uploadDir := fmt.Sprintf("./uploads/%s", image.DID) 222 - // _, err = os.Stat(uploadDir) 223 - // if os.IsNotExist(err) { 224 - // os.Mkdir(uploadDir, 0755) 225 - // } 226 - // 227 - // imgPath := fmt.Sprintf("./uploads/%s", image.ImageCID) 228 - // _, err = os.Stat(imgPath) 229 - // if err != nil { 230 - // syncGetBlob(image.DID, image.ImageCID) 231 - // } 232 - // 233 - // img, err := os.Open(fmt.Sprintf("%s/%s", uploadDir, image.ImageCID)) 234 - // img.WriteTo(w) 235 - // } 209 + func (h *Handler) getImage(w http.ResponseWriter, r *http.Request) { 210 + vals := r.URL.Query() 211 + var did string 212 + var cid string 213 + uri := vals.Get("uri") 214 + var image *types.Image 215 + var err error 216 + if uri != "" { 217 + image, err = h.db.GetImage(uri, r.Context()) 218 + if err == nil { 219 + did = image.DID 220 + if image.BlobCID != nil { 221 + cid = *image.BlobCID 222 + } 223 + } 224 + } 225 + if did == "" { 226 + did = vals.Get("did") 227 + if did == "" { 228 + handle := vals.Get("handle") 229 + if handle == "" { 230 + h.badRequest(w, errors.New("must provide an identity")) 231 + return 232 + } 233 + did, err = h.db.ResolveHandle(handle, r.Context()) 234 + if err != nil { 235 + h.badRequest(w, errors.New("failed to resolve handle")) 236 + return 237 + } 238 + } 239 + } 240 + if did == "" { 241 + h.serverError(w, errors.New("empty did")) 242 + return 243 + } 244 + if cid == "" { 245 + cid = vals.Get("cid") 246 + } 247 + if cid == "" { 248 + h.serverError(w, errors.New("empty cid")) 249 + } 250 + uploadDir := "./uploads" 251 + _, err = os.Stat(uploadDir) 252 + if os.IsNotExist(err) { 253 + os.Mkdir(uploadDir, 0755) 254 + } 255 + 256 + imgPath := fmt.Sprintf("%s/%s%s", uploadDir, did, cid) 257 + _, err = os.Stat(imgPath) 258 + if err != nil { 259 + blob, err := atputils.SyncGetBlob(did, cid, r.Context()) 260 + if err != nil { 261 + h.serverError(w, err) 262 + return 263 + } 264 + file, err := os.Create(imgPath) 265 + if err != nil { 266 + h.serverError(w, err) 267 + return 268 + } 269 + _, err = file.Write(blob) 270 + if err != nil { 271 + h.serverError(w, err) 272 + return 273 + } 274 + } 275 + 276 + stats, err := os.Stat(imgPath) 277 + if err != nil { 278 + h.serverError(w, errors.New("yikes, file not there even though it should?: "+err.Error())) 279 + return 280 + } 281 + 282 + if image == nil { 283 + image, err = h.db.GetImageDidCID(did, cid, r.Context()) 284 + if err != nil { 285 + h.serverError(w, err) 286 + return 287 + } 288 + if image == nil { 289 + h.serverError(w, errors.New("beep obop i didn't cache it")) 290 + return 291 + } 292 + } 293 + mime := "application/octet-stream" 294 + if image.BlobMIME != nil { 295 + mime = *image.BlobMIME 296 + } 297 + w.Header().Add("Content-Type", mime) 298 + w.Header().Add("Content-Length", fmt.Sprintf("%d", stats.Size())) 236 299 237 - // func syncGetBlob(did string, cid *string) { 238 - // //TODO: impl 239 - // } 300 + img, err := os.Open(imgPath) 301 + if err != nil { 302 + h.serverError(w, err) 303 + return 304 + } 305 + img.WriteTo(w) 306 + }