Skip to content

Commit 339bcde

Browse files
authored
Merge pull request #1011 from JuliaRobotics/23Q2/docs/blobentry
add optional timestamp size fields BlobEntry, (un)packBlob, docs
2 parents 73dafd0 + c1c190f commit 339bcde

File tree

9 files changed

+292
-153
lines changed

9 files changed

+292
-153
lines changed

LICENSE

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,4 @@
1-
Copyright (c) 2017-2022 NavAbility
2-
3-
The source code in this repository is separated into two parts
4-
that are licensed separately. The Neo4jDFG library/driver
5-
is licensed separately. For more details see:
6-
https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/blob/develop/src/Neo4jDFG/LICENSE
7-
8-
DistributedFactorGraphs' Neo4jDFG Driver is not licensed for hosted, webservice or cloud
9-
solutions (public or private). Please contact NavAbility via email at
10-
<[email protected]> for clarification or additional licensing options.
11-
NavAbility reserves all rights regarding, and to deny use of the software
12-
for hosted webservice or cloud offerings or deployments; over and above
13-
any conflicts that may arise with the licenses herein.
14-
15-
Other general use or modification of the software beyond that of
16-
webservices or clouds (private or public) is permitted
17-
according to terms defined by Apache 2.0 or other library specifc licenses.
18-
19-
Copyright 2017-2022 NavAbility
20-
21-
Licensed under the Apache License, Version 2.0 (the "License");
22-
you may not use this file except in compliance with the License.
23-
24-
Unless required by applicable law or agreed to in writing, software
25-
distributed under the License is distributed on an "AS IS" BASIS,
26-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27-
See the License for the specific language governing permissions and
28-
limitations under the License.
29-
1+
Copyright (c) 2017-2023 NavAbility Contributors
302

313
Apache License
324
Version 2.0, January 2004

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
99
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
1010
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1111
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
12+
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
1213
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1314
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
1415
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -37,6 +38,7 @@ CSV = "0.10"
3738
Colors = "0.10, 0.11, 0.12"
3839
Distributions = "0.23, 0.24, 0.25"
3940
DocStringExtensions = "0.8, 0.9"
41+
FileIO = "1"
4042
GraphPlot = "0.5.0"
4143
Graphs = "1.4"
4244
JSON3 = "1"

src/DataBlobs/entities/BlobEntry.jl

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,50 @@
55

66
"""
77
$(TYPEDEF)
8-
General Data Store Entry.
8+
9+
A `BlobEntry` is a small about of structured data that holds reference information to find an actual blob. Many `BlobEntry`s
10+
can exist on different graph nodes spanning Robots, and Sessions which can all reference the same `Blob`. A `BlobEntry`
11+
is also a equivalent to a bridging entry between local `.originId` and a remotely assigned `.blobIds`.
12+
13+
Notes:
14+
- All `.blobId`s are unique across the entire distributed system and are immutable. The `.originId` should be globally unique except for stochastic `uuid4` collisions that cannot be checked from a main reference owing to practical limitations such as network connectivity.
915
"""
1016
@Base.kwdef struct BlobEntry
11-
""" This is created by server-side GraphQL """
12-
id::Union{UUID, Nothing}=nothing
13-
""" This is the forced server generated blobId, or the filesystem blobId. """
14-
blobId::Union{UUID, Nothing}=nothing
15-
""" This is the ID at creation at the edge, do whatever you want with this, but make sure you populate it. """
16-
originId::UUID
17+
""" Remotely assigned and globally unique identifier for the `BlobEntry` itself (not the `.blobId`). """
18+
id::Union{UUID, Nothing} = nothing
19+
""" 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. """
20+
blobId::Union{UUID, Nothing} = nothing
21+
""" Machine friendly and locally assigned identifier of the 'Blob'. `.originId`s are mandatory upon first creation at the origin regardless of network access. Separate from `.blobId` since some architectures do not allow edge processes to assign a uuid4 to data store elements. """
22+
originId::UUID = uuid4()
23+
""" 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. """
1724
label::Symbol
25+
""" A hint about where the `Blob` itself might be stored. Remember that a Blob may be duplicated over multiple blobstores. """
1826
blobstore::Symbol
27+
""" A hash value to ensure data consistency which must correspond to the stored hash upon retrieval. [Legacy: some usage functions allow the check to be skipped if needed.] """
1928
hash::String # Probably https://docs.julialang.org/en/v1/stdlib/SHA
20-
origin::String # E.g. user|robot|session|varlabel
21-
description::String
22-
mimeType::String
29+
""" Context from which a BlobEntry=>Blob was first created. E.g. user|robot|session|varlabel. """
30+
origin::String
31+
""" number of bytes in blob """
32+
size::Union{Int, Nothing} = nothing
33+
""" Additional information that can help a different user of the Blob. """
34+
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']`. """
2338
metadata::String = ""
39+
""" When the Blob itself was first created. """
2440
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
45+
""" Self type declaration for when duck-typing happens. """
2546
_type::String = "BlobEntry"
26-
_version::String = string(_getDFGVersion()) # TBD consider upgrading to ::VersionNumber
47+
""" Type version of this BlobEntry. TBD.jl consider upgrading to `::VersionNumber`. """
48+
_version::String = string(_getDFGVersion())
2749
end
2850

51+
2952
StructTypes.StructType(::Type{BlobEntry}) = StructTypes.UnorderedStruct()
3053
StructTypes.idproperty(::Type{BlobEntry}) = :id
3154
StructTypes.omitempties(::Type{BlobEntry}) = (:id,)

src/DataBlobs/services/BlobPacking.jl

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# using FileIO
2+
# using ImageIO
3+
# using LasIO
4+
# using BSON
5+
# using OrderedCollections
6+
7+
# 2 types for now with MIME type
8+
# 1. JSON - application/octet-stream/json
9+
# 2. FileIO - application/octet-stream
10+
# - application/bson
11+
# - image/jpeg
12+
# - image/png
13+
14+
const _MIMETypes = OrderedDict{MIME, DataType}()
15+
push!(_MIMETypes, MIME("application/octet-stream/json")=>format"JSON")
16+
push!(_MIMETypes, MIME("application/bson")=>format"BSON")
17+
push!(_MIMETypes, MIME("image/png")=>format"PNG")
18+
push!(_MIMETypes, MIME("image/jpeg")=>format"JPG")
19+
push!(_MIMETypes, MIME("application/octet-stream; ext=las")=>format"LAS")
20+
21+
"""
22+
packBlob
23+
Convert a file (JSON, JPG, PNG, BSON, LAS) to Vector{UInt8} for use as a Blob.
24+
Returns the blob and MIME type.
25+
"""
26+
function packBlob end
27+
"""
28+
unpackBlob
29+
Convert a Blob back to the origanal typ using the MIME type or DataFormat type.
30+
"""
31+
function unpackBlob end
32+
33+
unpackBlob(mime::String, blob) = unpackBlob(MIME(mime), blob)
34+
35+
function unpackBlob(T::MIME, blob)
36+
dataformat = get(_MIMETypes, T, nothing)
37+
isnothing(dataformat) && error("Format not found for MIME type $(T)")
38+
return unpackBlob(dataformat, blob)
39+
end
40+
41+
42+
# 1. JSON strings are saved as is
43+
function packBlob(::Type{format"JSON"}, json_str::String)
44+
mimetype = findfirst(==(format"JSON"), _MIMETypes)
45+
# blob = codeunits(json_str)
46+
blob = Vector{UInt8}(json_str)
47+
return blob, mimetype
48+
end
49+
50+
function unpackBlob(::Type{format"JSON"}, blob::Vector{UInt8})
51+
return String(copy(blob))
52+
end
53+
54+
55+
# 2/ FileIO
56+
function packBlob(::Type{T}, data::Any; kwargs...) where T <: DataFormat
57+
io = IOBuffer()
58+
save(Stream{T}(io), data; kwargs...)
59+
blob = take!(io)
60+
mimetype = findfirst(==(T), _MIMETypes)
61+
if isnothing(mimetype)
62+
@warn "No MIME type found for format $T"
63+
mimetype = MIME"application/octet-stream"
64+
end
65+
return blob, mimetype
66+
end
67+
68+
function unpackBlob(::Type{T}, blob::Vector{UInt8}) where T <: DataFormat
69+
io = IOBuffer(blob)
70+
return load(Stream{T}(io))
71+
end
72+
73+
74+
75+
76+
# if false
77+
# json_str = "{\"name\":\"John\"}"
78+
# blob, mimetype = packBlob(format"JSON", json_str)
79+
# @assert json_str == unpackBlob(format"JSON", blob)
80+
# @assert json_str == unpackBlob(MIME("application/octet-stream/json"), blob)
81+
# @assert json_str == unpackBlob("application/octet-stream/json", blob)
82+
83+
84+
# blob,mime = packBlob(format"PNG", img)
85+
# up_img = unpackBlob(format"PNG", blob)
86+
87+
# #TODO BSON does not work yet, can extend [un]packBlob(::Type{format"BSON"}, ...)
88+
# packBlob(format"BSON", Dict("name"=>"John"))
89+
# unpackBlob(format"BSON", Dict("name"=>"John"))
90+
91+
92+
# end
93+
94+
95+

src/DataBlobs/services/HelpersDataWrapEntryBlob.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,14 @@ BlobEntry(
5151
label::Symbol = entry.label,
5252
blobstore::Symbol = entry.blobstore,
5353
hash::String = entry.hash,
54+
size::Union{Int,Nothing} = entry.size,
5455
origin::String = entry.origin,
5556
description::String = entry.description,
5657
mimeType::String = entry.mimeType,
5758
metadata::String = entry.metadata,
5859
timestamp::ZonedDateTime = entry.timestamp,
60+
createdTimestamp = entry.createdTimestamp,
61+
lastUpdatedTimestamp = entry.lastUpdatedTimestamp,
5962
_type::String = entry._type,
6063
_version::String = entry._version,
6164
) = BlobEntry(;
@@ -66,10 +69,13 @@ BlobEntry(
6669
blobstore,
6770
hash,
6871
origin,
72+
size,
6973
description,
7074
mimeType,
7175
metadata,
7276
timestamp,
77+
createdTimestamp,
78+
lastUpdatedTimestamp,
7379
_type,
7480
_version
7581
)

src/Deprecated.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
2+
3+
## ================================================================================
4+
## Remove in v0.23
5+
##=================================================================================
6+
7+
@deprecate BlobEntry(id, blobId, originId::UUID, label::Symbol, blobstore::Symbol, hash::String, origin::String, description::String, mimeType::String, metadata::String, timestamp::ZonedDateTime, _type::String, _version::String) BlobEntry(id, blobId, originId, label, blobstore, hash, origin, -1, description, mimeType, metadata, timestamp, nothing, nothing, _type, _version)
8+
19
## ================================================================================
210
## Remove in v0.22
311
##=================================================================================

src/DistributedFactorGraphs.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ using Pkg
3030
using TensorCast
3131
using ProgressMeter
3232
using SHA
33+
using OrderedCollections
34+
using FileIO
3335

3436
using CSV
3537

@@ -210,6 +212,7 @@ export listDataEntrySequence
210212
export mergeDataEntries!
211213
# aliases
212214
export addBlob!
215+
export packBlob, unpackBlob
213216

214217
##------------------------------------------------------------------------------
215218
# Factors
@@ -338,6 +341,7 @@ include("services/CompareUtils.jl")
338341
#Blobs
339342
include("DataBlobs/services/BlobEntry.jl")
340343
include("DataBlobs/services/BlobStores.jl")
344+
include("DataBlobs/services/BlobPacking.jl")
341345
include("DataBlobs/services/HelpersDataWrapEntryBlob.jl")
342346

343347
# Include the FilesDFG API.

0 commit comments

Comments
 (0)