diff --git a/api/model.go b/api/model.go index 3763476..5d81ed6 100644 --- a/api/model.go +++ b/api/model.go @@ -18,9 +18,13 @@ type ( Replicas []Replica `json:"Replicas,omitempty"` } Replica struct { - Provider string `json:"provider"` - Status string `json:"status"` - LastVerified time.Time `json:"lastVerified"` + Provider string `json:"provider"` + Pieces []Piece `json:"pieces"` + } + Piece struct { Expiration time.Time `json:"expiration"` + LastVerified time.Time `json:"lastVerified"` + PieceCID string `json:"pieceCid"` + Status string `json:"status"` } ) diff --git a/api/server/handler.go b/api/server/handler.go index 851b65c..b4d3913 100644 --- a/api/server/handler.go +++ b/api/server/handler.go @@ -152,14 +152,21 @@ func (m *HttpServer) handleBlobGetStatusByID(w http.ResponseWriter, r *http.Requ ID: idUriSegment, } - if blobDesc.Status != nil { - response.Replicas = make([]api.Replica, 0, len(blobDesc.Status.Replicas)) - for _, replica := range blobDesc.Status.Replicas { + if len(blobDesc.Replicas) != 0 { + response.Replicas = make([]api.Replica, 0, len(blobDesc.Replicas)) + for _, replica := range blobDesc.Replicas { + apiPieces := make([]api.Piece, 0, len(replica.Pieces)) + for _, piece := range replica.Pieces { + apiPieces = append(apiPieces, api.Piece{ + Expiration: piece.Expiration, + LastVerified: piece.LastUpdated, + PieceCID: piece.PieceCID, + Status: piece.Status, + }) + } response.Replicas = append(response.Replicas, api.Replica{ - Provider: replica.Provider, - Status: replica.Status, - LastVerified: replica.LastUpdated, - Expiration: replica.Expiration, + Provider: replica.Provider, + Pieces: apiPieces, }) } } diff --git a/blob/blob.go b/blob/blob.go index 29d7553..70bb518 100644 --- a/blob/blob.go +++ b/blob/blob.go @@ -30,16 +30,17 @@ type ( Size uint64 // ModificationTime is the latest time at which the blob was modified. ModificationTime time.Time - Status *Status - } - Status struct { - Replicas []Replica + Replicas []Replica } Replica struct { - Provider string - Status string - LastUpdated time.Time + Provider string + Pieces []Piece + } + Piece struct { Expiration time.Time + LastUpdated time.Time + PieceCID string + Status string } Store interface { Put(context.Context, io.ReadCloser) (*Descriptor, error) diff --git a/integration/singularity/store.go b/integration/singularity/store.go index b209857..df3e74f 100644 --- a/integration/singularity/store.go +++ b/integration/singularity/store.go @@ -460,23 +460,29 @@ func (s *SingularityStore) Describe(ctx context.Context, id blob.ID) (*blob.Desc if err != nil { return nil, err } + + if len(getFileDealsRes.Payload) == 0 { + return descriptor, nil + } + replicas := make([]blob.Replica, 0, len(getFileDealsRes.Payload)) for _, deal := range getFileDealsRes.Payload { updatedAt, err := time.Parse("2006-01-02 15:04:05-07:00", deal.UpdatedAt) if err != nil { updatedAt = time.Time{} } - - replicas = append(replicas, blob.Replica{ + piece := blob.Piece{ + Expiration: epochutil.EpochToTime(int32(deal.EndEpoch)), LastUpdated: updatedAt, - Provider: deal.Provider, + PieceCID: deal.PieceCid, Status: string(deal.State), - Expiration: epochutil.EpochToTime(int32(deal.EndEpoch)), + } + replicas = append(replicas, blob.Replica{ + Provider: deal.Provider, + Pieces: []blob.Piece{piece}, }) } - descriptor.Status = &blob.Status{ - Replicas: replicas, - } + descriptor.Replicas = replicas return descriptor, nil } diff --git a/integration/test/integration_test.go b/integration/test/integration_test.go index 1f3ebb8..b8e12bd 100644 --- a/integration/test/integration_test.go +++ b/integration/test/integration_test.go @@ -100,7 +100,9 @@ func TestRoundTripPutStatusAndFullStorage(t *testing.T) { var decoded api.GetStatusResponse err = jsonResp.Decode(&decoded) assert.NoError(c, err) - assert.Equal(c, len(decoded.Replicas), 2) + assert.Equal(c, 2, len(decoded.Replicas)) + assert.Equal(c, 1, len(decoded.Replicas[0].Pieces)) + assert.Equal(c, 1, len(decoded.Replicas[1].Pieces)) }, 2*time.Minute, 5*time.Second, "never initiated deal making") } @@ -142,9 +144,10 @@ func TestRoundTripPutStatusAndFullStorage(t *testing.T) { var decoded api.GetStatusResponse err = jsonResp.Decode(&decoded) assert.NoError(c, err) - assert.Equal(c, len(decoded.Replicas), 2) + assert.Equal(c, 2, len(decoded.Replicas), 2) for _, replica := range decoded.Replicas { - assert.Contains(c, []string{"published", "active"}, replica.Status) + assert.Equal(c, 1, len(replica.Pieces)) + assert.Contains(c, []string{"published", "active"}, replica.Pieces[0].Status) } }, 2*time.Minute, 5*time.Second, "published deals") } diff --git a/openapi.yaml b/openapi.yaml index 1008832..8b553a9 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -107,26 +107,36 @@ paths: provider: type: string description: 'ID of the Filecoin storage provider.' - status: - type: string - description: 'Status of this replica. Can be "active", "slashed" or "expired".' - lastVerified: - type: string - format: date-time - description: 'Last verification time of the replica. Follows the RFC 3339 format.' - expiration: - type: string - format: date-time - description: 'Expiration time of the blob storage. Follows the RFC 3339 format.' + pieces: + type: array + items: + type: object + properties: + expiration: + type: string + format: date-time + description: 'Expiration time of the blob storage. Follows the RFC 3339 format.' + lastVerified: + type: string + format: date-time + description: 'Last verification time of the replica. Follows the RFC 3339 format.' + pieceCid: + type: string + description: 'Piece CID identifying this piece.' + status: + type: string + description: 'Status of this replica. Can be "active", "slashed" or "expired".' examples: default: value: id: 'unique-blob-id' - replicas: - - provider: 'f0xxxx' - status: 'active' - lastVerified: '2023-05-29T00:00:00Z' - expiration: '2023-06-29T00:00:00Z' + replica: + provider: 'f0xxxx' + pieces: + - expiration: '2023-06-29T00:00:00Z' + lastVerified: '2023-05-29T00:00:00Z' + pieceCid: 'baguqexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' + status: 'active' '404': description: 'No status found for the given ID.' content: