Skip to content

Commit

Permalink
feat: add metadata to the manifest (#960)
Browse files Browse the repository at this point in the history
* Add metadata to the manifest

* Remove useless import

* Fix the openapi documentation

* Use optional fields instead of default values

* Remove testRestApi target

* Return failure when the protobuf cannot get the field

* Set download headers and fix cors headers when an error is returned

* Add tests to verify the download headers

* Try to adjust the content length header

* Fix convertion to string

* Remove the content length header

* Remove testRestApi target

* Removing debug messages
  • Loading branch information
2-towns authored Oct 25, 2024
1 parent bcc1468 commit 2fb7031
Show file tree
Hide file tree
Showing 9 changed files with 344 additions and 39 deletions.
40 changes: 38 additions & 2 deletions codex/manifest/coders.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# This module implements serialization and deserialization of Manifest

import pkg/upraises
import times

push: {.upraises: [].}

Expand Down Expand Up @@ -59,6 +60,9 @@ proc encode*(manifest: Manifest): ?!seq[byte] =
# optional hcodec: MultiCodec = 5 # Multihash codec
# optional version: CidVersion = 6; # Cid version
# optional ErasureInfo erasure = 7; # erasure coding info
# optional filename: ?string = 8; # original filename
# optional mimetype: ?string = 9; # original mimetype
# optional uploadedAt: ?int64 = 10; # original uploadedAt
# }
# ```
#
Expand All @@ -70,6 +74,7 @@ proc encode*(manifest: Manifest): ?!seq[byte] =
header.write(4, manifest.codec.uint32)
header.write(5, manifest.hcodec.uint32)
header.write(6, manifest.version.uint32)

if manifest.protected:
var erasureInfo = initProtoBuffer()
erasureInfo.write(1, manifest.ecK.uint32)
Expand All @@ -90,6 +95,15 @@ proc encode*(manifest: Manifest): ?!seq[byte] =
erasureInfo.finish()
header.write(7, erasureInfo)

if manifest.filename.isSome:
header.write(8, manifest.filename.get())

if manifest.mimetype.isSome:
header.write(9, manifest.mimetype.get())

if manifest.uploadedAt.isSome:
header.write(10, manifest.uploadedAt.get().uint64)

pbNode.write(1, header) # set the treeCid as the data field
pbNode.finish()

Expand Down Expand Up @@ -118,6 +132,9 @@ proc decode*(_: type Manifest, data: openArray[byte]): ?!Manifest =
slotRoots: seq[seq[byte]]
cellSize: uint32
verifiableStrategy: uint32
filename: string
mimetype: string
uploadedAt: uint64

# Decode `Header` message
if pbNode.getField(1, pbHeader).isErr:
Expand Down Expand Up @@ -145,6 +162,15 @@ proc decode*(_: type Manifest, data: openArray[byte]): ?!Manifest =
if pbHeader.getField(7, pbErasureInfo).isErr:
return failure("Unable to decode `erasureInfo` from manifest!")

if pbHeader.getField(8, filename).isErr:
return failure("Unable to decode `filename` from manifest!")

if pbHeader.getField(9, mimetype).isErr:
return failure("Unable to decode `mimetype` from manifest!")

if pbHeader.getField(10, uploadedAt).isErr:
return failure("Unable to decode `uploadedAt` from manifest!")

let protected = pbErasureInfo.buffer.len > 0
var verifiable = false
if protected:
Expand Down Expand Up @@ -183,6 +209,10 @@ proc decode*(_: type Manifest, data: openArray[byte]): ?!Manifest =
let
treeCid = ? Cid.init(treeCidBuf).mapFailure

var filenameOption = if filename.len == 0: string.none else: filename.some
var mimetypeOption = if mimetype.len == 0: string.none else: mimetype.some
var uploadedAtOption = if uploadedAt == 0: int64.none else: uploadedAt.int64.some

let
self = if protected:
Manifest.new(
Expand All @@ -196,15 +226,21 @@ proc decode*(_: type Manifest, data: openArray[byte]): ?!Manifest =
ecM = ecM.int,
originalTreeCid = ? Cid.init(originalTreeCid).mapFailure,
originalDatasetSize = originalDatasetSize.NBytes,
strategy = StrategyType(protectedStrategy))
strategy = StrategyType(protectedStrategy),
filename = filenameOption,
mimetype = mimetypeOption,
uploadedAt = uploadedAtOption)
else:
Manifest.new(
treeCid = treeCid,
datasetSize = datasetSize.NBytes,
blockSize = blockSize.NBytes,
version = CidVersion(version),
hcodec = hcodec.MultiCodec,
codec = codec.MultiCodec)
codec = codec.MultiCodec,
filename = filenameOption,
mimetype = mimetypeOption,
uploadedAt = uploadedAtOption)

? self.verify()

Expand Down
89 changes: 69 additions & 20 deletions codex/manifest/manifest.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ type
codec: MultiCodec # Dataset codec
hcodec: MultiCodec # Multihash codec
version: CidVersion # Cid version
filename {.serialize.}: ?string # The filename of the content uploaded (optional)
mimetype {.serialize.}: ?string # The mimetype of the content uploaded (optional)
uploadedAt {.serialize.}: ?int64 # The UTC creation timestamp in seconds
case protected {.serialize.}: bool # Protected datasets have erasure coded info
of true:
ecK: int # Number of blocks to encode
Expand Down Expand Up @@ -121,6 +124,14 @@ func verifiableStrategy*(self: Manifest): StrategyType =
func numSlotBlocks*(self: Manifest): int =
divUp(self.blocksCount, self.numSlots)

func filename*(self: Manifest): ?string =
self.filename

func mimetype*(self: Manifest): ?string =
self.mimetype

func uploadedAt*(self: Manifest): ?int64 =
self.uploadedAt
############################################################
# Operations on block list
############################################################
Expand Down Expand Up @@ -163,6 +174,9 @@ func `==`*(a, b: Manifest): bool =
(a.hcodec == b.hcodec) and
(a.codec == b.codec) and
(a.protected == b.protected) and
(a.filename == b.filename) and
(a.mimetype == b.mimetype) and
(a.uploadedAt == b.uploadedAt) and
(if a.protected:
(a.ecK == b.ecK) and
(a.ecM == b.ecM) and
Expand All @@ -181,26 +195,38 @@ func `==`*(a, b: Manifest): bool =
true)

func `$`*(self: Manifest): string =
"treeCid: " & $self.treeCid &
result = "treeCid: " & $self.treeCid &
", datasetSize: " & $self.datasetSize &
", blockSize: " & $self.blockSize &
", version: " & $self.version &
", hcodec: " & $self.hcodec &
", codec: " & $self.codec &
", protected: " & $self.protected &
(if self.protected:
", ecK: " & $self.ecK &
", ecM: " & $self.ecM &
", originalTreeCid: " & $self.originalTreeCid &
", originalDatasetSize: " & $self.originalDatasetSize &
", verifiable: " & $self.verifiable &
(if self.verifiable:
", verifyRoot: " & $self.verifyRoot &
", slotRoots: " & $self.slotRoots
else:
"")
", protected: " & $self.protected

if self.filename.isSome:
result &= ", filename: " & $self.filename

if self.mimetype.isSome:
result &= ", mimetype: " & $self.mimetype

if self.uploadedAt.isSome:
result &= ", uploadedAt: " & $self.uploadedAt

result &= (if self.protected:
", ecK: " & $self.ecK &
", ecM: " & $self.ecM &
", originalTreeCid: " & $self.originalTreeCid &
", originalDatasetSize: " & $self.originalDatasetSize &
", verifiable: " & $self.verifiable &
(if self.verifiable:
", verifyRoot: " & $self.verifyRoot &
", slotRoots: " & $self.slotRoots
else:
"")
else:
"")

return result

############################################################
# Constructors
Expand All @@ -214,7 +240,10 @@ func new*(
version: CidVersion = CIDv1,
hcodec = Sha256HashCodec,
codec = BlockCodec,
protected = false): Manifest =
protected = false,
filename: ?string = string.none,
mimetype: ?string = string.none,
uploadedAt: ?int64 = int64.none): Manifest =

T(
treeCid: treeCid,
Expand All @@ -223,7 +252,10 @@ func new*(
version: version,
codec: codec,
hcodec: hcodec,
protected: protected)
protected: protected,
filename: filename,
mimetype: mimetype,
uploadedAt: uploadedAt)

func new*(
T: type Manifest,
Expand All @@ -247,7 +279,11 @@ func new*(
ecK: ecK, ecM: ecM,
originalTreeCid: manifest.treeCid,
originalDatasetSize: manifest.datasetSize,
protectedStrategy: strategy)
protectedStrategy: strategy,
filename: manifest.filename,
mimetype: manifest.mimetype,
uploadedAt: manifest.uploadedAt
)

func new*(
T: type Manifest,
Expand All @@ -263,7 +299,10 @@ func new*(
codec: manifest.codec,
hcodec: manifest.hcodec,
blockSize: manifest.blockSize,
protected: false)
protected: false,
filename: manifest.filename,
mimetype: manifest.mimetype,
uploadedAt: manifest.uploadedAt)

func new*(
T: type Manifest,
Expand All @@ -277,7 +316,10 @@ func new*(
ecM: int,
originalTreeCid: Cid,
originalDatasetSize: NBytes,
strategy = SteppedStrategy): Manifest =
strategy = SteppedStrategy,
filename: ?string = string.none,
mimetype: ?string = string.none,
uploadedAt: ?int64 = int64.none): Manifest =

Manifest(
treeCid: treeCid,
Expand All @@ -291,7 +333,10 @@ func new*(
ecM: ecM,
originalTreeCid: originalTreeCid,
originalDatasetSize: originalDatasetSize,
protectedStrategy: strategy)
protectedStrategy: strategy,
filename: filename,
mimetype: mimetype,
uploadedAt: uploadedAt)

func new*(
T: type Manifest,
Expand Down Expand Up @@ -329,7 +374,11 @@ func new*(
verifyRoot: verifyRoot,
slotRoots: @slotRoots,
cellSize: cellSize,
verifiableStrategy: strategy)
verifiableStrategy: strategy,
filename: manifest.filename,
mimetype: manifest.mimetype,
uploadedAt: manifest.uploadedAt
)

func new*(
T: type Manifest,
Expand Down
12 changes: 10 additions & 2 deletions codex/node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import std/sequtils
import std/strformat
import std/sugar
import std/cpuinfo
import times

import pkg/questionable
import pkg/questionable/results
Expand Down Expand Up @@ -297,6 +298,8 @@ proc retrieve*(
proc store*(
self: CodexNodeRef,
stream: LPStream,
filename: ?string = string.none,
mimetype: ?string = string.none,
blockSize = DefaultBlockSize): Future[?!Cid] {.async.} =
## Save stream contents as dataset with given blockSize
## to nodes's BlockStore, and return Cid of its manifest
Expand Down Expand Up @@ -355,7 +358,10 @@ proc store*(
datasetSize = NBytes(chunker.offset),
version = CIDv1,
hcodec = hcodec,
codec = dataCodec)
codec = dataCodec,
filename = filename,
mimetype = mimetype,
uploadedAt = now().utc.toTime.toUnix.some)

without manifestBlk =? await self.storeManifest(manifest), err:
error "Unable to store manifest"
Expand All @@ -364,7 +370,9 @@ proc store*(
info "Stored data", manifestCid = manifestBlk.cid,
treeCid = treeCid,
blocks = manifest.blocksCount,
datasetSize = manifest.datasetSize
datasetSize = manifest.datasetSize,
filename = manifest.filename,
mimetype = manifest.mimetype

return manifestBlk.cid.success

Expand Down
Loading

0 comments on commit 2fb7031

Please sign in to comment.