package node import ( "fmt" "net/http" "strings" "go-blockchain/blockchain" "go-blockchain/wallet" ) // GET /api/nfts — list all NFTs. func apiNFTs(q ExplorerQuery) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if q.GetNFTs == nil { jsonErr(w, fmt.Errorf("NFT query not available"), 503) return } nfts, err := q.GetNFTs() if err != nil { jsonErr(w, err, 500) return } if nfts == nil { nfts = []blockchain.NFTRecord{} } jsonOK(w, map[string]any{ "count": len(nfts), "nfts": nfts, }) } } // GET /api/nfts/{id} — single NFT metadata // GET /api/nfts/owner/{pubkey} — NFTs owned by address func apiNFTByID(q ExplorerQuery) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/api/nfts/") parts := strings.SplitN(path, "/", 2) // /api/nfts/owner/{pubkey} if parts[0] == "owner" { if len(parts) < 2 || parts[1] == "" { jsonErr(w, fmt.Errorf("pubkey required"), 400) return } pubKey := parts[1] if strings.HasPrefix(pubKey, "DC") && q.AddressToPubKey != nil { if pk, err := q.AddressToPubKey(pubKey); err == nil && pk != "" { pubKey = pk } } if q.NFTsByOwner == nil { jsonErr(w, fmt.Errorf("NFT query not available"), 503) return } nfts, err := q.NFTsByOwner(pubKey) if err != nil { jsonErr(w, err, 500) return } if nfts == nil { nfts = []blockchain.NFTRecord{} } jsonOK(w, map[string]any{"count": len(nfts), "nfts": nfts}) return } // /api/nfts/{id} nftID := parts[0] if nftID == "" { jsonErr(w, fmt.Errorf("NFT ID required"), 400) return } if q.GetNFT == nil { jsonErr(w, fmt.Errorf("NFT query not available"), 503) return } rec, err := q.GetNFT(nftID) if err != nil { jsonErr(w, err, 500) return } if rec == nil { jsonErr(w, fmt.Errorf("NFT %s not found", nftID), 404) return } // Attach owner address for convenience. ownerAddr := "" if rec.Owner != "" { ownerAddr = wallet.PubKeyToAddress(rec.Owner) } jsonOK(w, map[string]any{ "nft": rec, "owner_address": ownerAddr, }) } } // GET /api/tokens — list all issued tokens. func apiTokens(q ExplorerQuery) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if q.GetTokens == nil { jsonErr(w, fmt.Errorf("token query not available"), 503) return } tokens, err := q.GetTokens() if err != nil { jsonErr(w, err, 500) return } if tokens == nil { tokens = []blockchain.TokenRecord{} } jsonOK(w, map[string]any{ "count": len(tokens), "tokens": tokens, }) } } // GET /api/tokens/{id} — token metadata // GET /api/tokens/{id}/balance/{pub} — token balance for a public key or DC address func apiTokenByID(q ExplorerQuery) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/api/tokens/") parts := strings.SplitN(path, "/", 3) tokenID := parts[0] if tokenID == "" { jsonErr(w, fmt.Errorf("token ID required"), 400) return } // /api/tokens/{id}/balance/{pub} if len(parts) == 3 && parts[1] == "balance" { pubOrAddr := parts[2] if pubOrAddr == "" { jsonErr(w, fmt.Errorf("pubkey or address required"), 400) return } // Resolve DC address to pubkey if needed. pubKey := pubOrAddr if strings.HasPrefix(pubOrAddr, "DC") && q.AddressToPubKey != nil { if pk, err := q.AddressToPubKey(pubOrAddr); err == nil && pk != "" { pubKey = pk } } if q.TokenBalance == nil { jsonErr(w, fmt.Errorf("token balance query not available"), 503) return } bal, err := q.TokenBalance(tokenID, pubKey) if err != nil { jsonErr(w, err, 500) return } jsonOK(w, map[string]any{ "token_id": tokenID, "pub_key": pubKey, "address": wallet.PubKeyToAddress(pubKey), "balance": bal, }) return } // /api/tokens/{id} if q.GetToken == nil { jsonErr(w, fmt.Errorf("token query not available"), 503) return } rec, err := q.GetToken(tokenID) if err != nil { jsonErr(w, err, 500) return } if rec == nil { jsonErr(w, fmt.Errorf("token %s not found", tokenID), 404) return } jsonOK(w, rec) } }