|
1 | | - |
2 | 1 | ##============================================================================== |
3 | 2 | ## Blobentry |
4 | 3 | ##============================================================================== |
5 | | -#TODO think origin and buildSourceString should be deprecated, description can be used instead |
6 | | -#TODO hash - maybe use both crc32c for fast error check and sha256 for strong integrity check |
7 | | -# stored seperately as crc and sha or as a tuple `hash::Tuple{Symbol, String}` where Symbol is :crc32c or :sha256 |
8 | | -# or an enum with suppored hash types |
9 | 4 | """ |
10 | 5 | $(TYPEDEF) |
11 | 6 |
|
12 | 7 | A `Blobentry` is a small about of structured data that holds reference information to find an actual blob. Many `Blobentry`s |
13 | 8 | can exist on different graph nodes spanning Agents and Factor Graphs which can all reference the same `Blob`. |
14 | 9 |
|
15 | 10 | Notes: |
16 | | -- `blobId`s should be unique within a blobstore and are immutable. |
| 11 | +- `blobid`s should be unique within a blobstore and are immutable. |
17 | 12 | """ |
18 | | -Base.@kwdef struct Blobentry |
19 | | - """ Remotely assigned and globally unique identifier for the `Blobentry` itself (not the `.blobId`). """ |
20 | | - id::Union{UUID, Nothing} = nothing |
21 | | - """ Machine friendly and globally unique identifier of the 'Blob', usually assigned from a common point in the system. This can be used to guarantee unique retrieval of the large data blob. """ |
22 | | - blobId::UUID = uuid4() |
| 13 | +StructUtils.@kwarg struct Blobentry |
23 | 14 | """ Human friendly label of the `Blob` and also used as unique identifier per node on which a `Blobentry` is added. E.g. do "LEFTCAM_1", "LEFTCAM_2", ... of you need to repeat a label on the same variable. """ |
24 | 15 | label::Symbol |
25 | | - """ A hint about where the `Blob` itself might be stored. Remember that a Blob may be duplicated over multiple blobstores. """ |
| 16 | + """ The label of the `Blobstore` in which the `Blob` is stored. Default is `:default`.""" |
26 | 17 | blobstore::Symbol = :default |
27 | | - """ A hash value to ensure data consistency which must correspond to the stored hash upon retrieval. Use `bytes2hex(sha256(blob))`. [Legacy: some usage functions allow the check to be skipped if needed.] """ |
28 | | - hash::String = ""# Probably https://docs.julialang.org/en/v1/stdlib/SHA |
29 | | - """ Context from which a Blobentry=>Blob was first created. E.g. agent|graph|varlabel. """ |
| 18 | + """ Machine friendly and unique within a `Blobstore` identifier of the 'Blob'.""" |
| 19 | + blobid::UUID = uuid4() # was blobId |
| 20 | + """ (Optional) crc32c hash value to ensure data consistency which must correspond to the stored hash upon retrieval.""" |
| 21 | + crchash::Union{UInt32, Nothing} = |
| 22 | + nothing & ( |
| 23 | + json=( |
| 24 | + lower = h->isnothing(h) ? nothing : string(h, base = 16), |
| 25 | + lift = s->isnothing(s) ? nothing : parse(UInt32, s; base = 16), |
| 26 | + ) |
| 27 | + ) |
| 28 | + """ (Optional) sha256 hash value to ensure data consistency which must correspond to the stored hash upon retrieval.""" |
| 29 | + shahash::Union{Vector{UInt8}, Nothing} = |
| 30 | + nothing & ( |
| 31 | + json=( |
| 32 | + lower = h->isnothing(h) ? nothing : bytes2hex(h), |
| 33 | + lift = s->isnothing(s) ? nothing : hex2bytes(s), |
| 34 | + ) |
| 35 | + ) |
| 36 | + """ Source system or application where the blob was created (e.g., webapp, sdk, robot)""" |
30 | 37 | origin::String = "" |
31 | | - """ number of bytes in blob as a string""" |
32 | | - size::String = "-1" |
| 38 | + """Number of bytes in blob serialized as a string""" |
| 39 | + size::Int64 = -1 & (json=(lower = string, lift = x->parse(Int64, x))) |
33 | 40 | """ Additional information that can help a different user of the Blob. """ |
34 | 41 | description::String = "" |
35 | | - """ MIME description describing the format of binary data in the `Blob`, e.g. 'image/png' or 'application/json; _type=CameraModel'. """ |
36 | | - mimeType::String = "application/octet-stream" |
37 | | - """ Additional storage for functional metadata used in some scenarios, e.g. to support advanced features such as `parsejson(base64decode(entry.metadata))['time_sync']`. """ |
38 | | - metadata::String = "e30=" |
39 | | - """ When the Blob itself was first created. """ |
40 | | - timestamp::ZonedDateTime = now(localzone()) |
41 | | - """ When the Blobentry was created. """ |
42 | | - createdTimestamp::Union{ZonedDateTime, Nothing} = nothing |
43 | | - """ Use carefully, but necessary to support advanced usage such as time synchronization over Blob data. """ |
44 | | - lastUpdatedTimestamp::Union{ZonedDateTime, Nothing} = nothing |
| 42 | + """ MIME description describing the format of binary data in the `Blob`, e.g. 'image/png' or 'application/json'. """ |
| 43 | + mimetype::String = "application/octet-stream" #FIXME ::MIME = MIME("application/octet-stream") |
| 44 | + """ Storage for a couple of bytes directly in the graph. Use with caution and keep it small and simple.""" |
| 45 | + metadata::JSONText = JSONText("{}") |
| 46 | + """ When the Blob itself was first created. Serialized as an ISO 8601 string.""" |
| 47 | + timestamp::NanoDate = ndnow(UTC) & (json = (lower = timestamp,),) |
45 | 48 | """ Type version of this Blobentry.""" |
46 | | - _version::VersionNumber = _getDFGVersion() |
| 49 | + version::VersionNumber = version(Blobentry) |
47 | 50 | end |
| 51 | +version(::Type{Blobentry}) = v"0.1.0" |
| 52 | +version(node) = node.version |
48 | 53 |
|
49 | 54 | function Blobentry(label::Symbol, blobstore = :default; kwargs...) |
50 | 55 | return Blobentry(; label, blobstore, kwargs...) |
51 | 56 | end |
52 | 57 | # construction helper from existing Blobentry for user overriding via kwargs |
53 | 58 | function Blobentry( |
54 | 59 | entry::Blobentry; |
55 | | - id::Union{UUID, Nothing} = entry.id, |
56 | | - blobId::UUID = entry.blobId, |
| 60 | + blobid::UUID = entry.blobid, |
57 | 61 | label::Symbol = entry.label, |
58 | 62 | blobstore::Symbol = entry.blobstore, |
59 | | - hash::String = entry.hash, |
60 | | - size::Union{String, Int, Nothing} = entry.size, |
| 63 | + crchash = entry.crchash, |
| 64 | + shahash = entry.shahash, |
| 65 | + size::Int64 = entry.size, |
61 | 66 | origin::String = entry.origin, |
62 | 67 | description::String = entry.description, |
63 | | - mimeType::String = entry.mimeType, |
64 | | - metadata::String = entry.metadata, |
| 68 | + mimetype::String = entry.mimetype, |
| 69 | + metadata::JSONText = entry.metadata, |
65 | 70 | timestamp::ZonedDateTime = entry.timestamp, |
66 | | - createdTimestamp = entry.createdTimestamp, |
67 | | - lastUpdatedTimestamp = entry.lastUpdatedTimestamp, |
68 | | - _version = entry._version, |
| 71 | + version = entry.version, |
69 | 72 | ) |
70 | 73 | return Blobentry(; |
71 | | - id, |
72 | | - blobId, |
73 | 74 | label, |
74 | 75 | blobstore, |
75 | | - hash, |
| 76 | + blobid, |
| 77 | + crchash, |
| 78 | + shahash, |
76 | 79 | origin, |
77 | | - size = string(size), |
| 80 | + size, |
78 | 81 | description, |
79 | | - mimeType, |
| 82 | + mimetype, |
80 | 83 | metadata, |
81 | 84 | timestamp, |
82 | | - createdTimestamp, |
83 | | - lastUpdatedTimestamp, |
84 | | - _version, |
| 85 | + version, |
85 | 86 | ) |
86 | 87 | end |
| 88 | + |
| 89 | +#TODO deprecated in v0.29 |
| 90 | +function Base.getproperty(x::Blobentry, f::Symbol) |
| 91 | + if f in [:id, :createdTimestamp, :lastUpdatedTimestamp] |
| 92 | + error("Blobentry field $f has been deprecated") |
| 93 | + elseif f == :hash |
| 94 | + error("Blobentry field :hash has been deprecated; use :crchash or :shahash instead") |
| 95 | + elseif f == :blobId |
| 96 | + @warn "Blobentry field :blobId has been renamed to :blobid" |
| 97 | + return getfield(x, :blobid) |
| 98 | + elseif f == :mimeType |
| 99 | + @warn "Blobentry field :mimeType has been renamed to :mimetype" |
| 100 | + return getfield(x, :mimetype) |
| 101 | + elseif f == :_version |
| 102 | + @warn "Blobentry field :_version has been renamed to :version" |
| 103 | + return getfield(x, :version) |
| 104 | + else |
| 105 | + getfield(x, f) |
| 106 | + end |
| 107 | +end |
| 108 | + |
| 109 | +function Base.setproperty!(x::Blobentry, f::Symbol, val) |
| 110 | + if f == :blobId |
| 111 | + @warn "Blobentry field :blobId has been renamed to :blobid" |
| 112 | + setfield!(x, :blobid, val) |
| 113 | + elseif f == :mimeType |
| 114 | + @warn "Blobentry field :mimeType has been renamed to :mimetype" |
| 115 | + setfield!(x, :mimetype, val) |
| 116 | + elseif f == :_version |
| 117 | + @warn "Blobentry field :_version has been renamed to :version" |
| 118 | + setfield!(x, :version, val) |
| 119 | + elseif f in [:id, :createdTimestamp, :lastUpdatedTimestamp, :hash] |
| 120 | + error("Blobentry field $f has been deprecated") |
| 121 | + else |
| 122 | + setfield!(x, f, val) |
| 123 | + end |
| 124 | +end |
0 commit comments