diff --git a/http/api.go b/http/api.go index df900de..01838b7 100644 --- a/http/api.go +++ b/http/api.go @@ -1,9 +1,11 @@ package http import ( + "errors" "io" "net/http" + blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p/core/peer" "go.sia.tech/fsd/config" @@ -40,7 +42,8 @@ func (as *apiServer) handleCARPin(jc jape.Context) { } } -func (as *apiServer) handleCIDPin(jc jape.Context) { +// handleBlocksCIDPUT handles requests to pin a block by CID +func (as *apiServer) handleBlocksCIDPUT(jc jape.Context) { var c cid.Cid var recursive bool if jc.DecodeParam("cid", &c) != nil { @@ -54,6 +57,37 @@ func (as *apiServer) handleCIDPin(jc jape.Context) { } } +// handleBlocksPUT handles requests to upload a raw block +func (as *apiServer) handleBlocksPUT(jc jape.Context) { + ctx := jc.Request.Context() + defer jc.Request.Body.Close() + + lr := io.LimitReader(jc.Request.Body, 4<<20) // 4MB + buf, err := io.ReadAll(lr) + if errors.Is(err, io.ErrUnexpectedEOF) { + jc.Error(err, http.StatusRequestEntityTooLarge) + return + } else if err != nil { + jc.Error(err, http.StatusBadRequest) + return + } + + block := blocks.NewBlock(buf) + + ok, err := as.ipfs.HasBlock(ctx, block.Cid()) + if err != nil { + jc.Error(err, http.StatusBadRequest) + return + } else if ok { + jc.Encode(block.Cid()) + return + } else if err := as.ipfs.AddBlock(ctx, block); err != nil { + jc.Error(err, http.StatusInternalServerError) + return + } + jc.Encode(block.Cid()) +} + // NewAPIHandler returns a new http.Handler that handles requests to the api func NewAPIHandler(ipfs *ipfs.Node, cfg config.Config, log *zap.Logger) http.Handler { s := &apiServer{ @@ -63,7 +97,8 @@ func NewAPIHandler(ipfs *ipfs.Node, cfg config.Config, log *zap.Logger) http.Han return jape.Mux(map[string]jape.Handler{ "POST /api/unixfs/upload": s.handleUnixFSUpload, "PUT /api/car/pin": s.handleCARPin, - "PUT /api/cid/:cid/pin": s.handleCIDPin, + "PUT /api/blocks": s.handleBlocksPUT, + "PUT /api/blocks/:cid": s.handleBlocksCIDPUT, "GET /api/peers": s.handleListPeers, "PUT /api/peers": s.handleAddPeer, }) diff --git a/ipfs/node.go b/ipfs/node.go index 1c5fd04..e7994b1 100644 --- a/ipfs/node.go +++ b/ipfs/node.go @@ -12,6 +12,7 @@ import ( "github.com/ipfs/boxo/blockstore" "github.com/ipfs/boxo/ipld/merkledag" "github.com/ipfs/boxo/provider" + blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" format "github.com/ipfs/go-ipld-format" @@ -71,6 +72,11 @@ func (n *Node) HasBlock(ctx context.Context, c cid.Cid) (bool, error) { return n.blockService.Blockstore().Has(ctx, c) } +// AddBlock adds a generic block to the IPFS node +func (n *Node) AddBlock(ctx context.Context, block blocks.Block) error { + return n.blockService.AddBlock(ctx, block) +} + // PeerID returns the peer ID of the node func (n *Node) PeerID() peer.ID { return n.frt.Host().ID()