Skip to content

Commit 7672ba5

Browse files
committed
fixed blobs entries docs page
1 parent 7c9f559 commit 7672ba5

File tree

6 files changed

+105
-97
lines changed

6 files changed

+105
-97
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ docs_cicd:
2626

2727
docs:
2828
$(SDKPY_DOCS_BUILDER) build docs/
29+
$(SDKPY_DOCS_BUILDER) build docs/
2930

3031
docs_firefox: docs
3132
firefox docs/_build/html/index.html

docs/blobs.md

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,100 @@
11
# Data `BlobEntry=>Blob`
22

3-
## Getting BlobEntries
3+
Many `BlobEntry`s from various location can all reference the same large and heavy binary data `Blob`. Furthermore, this system allows a distributed usage over a large networked system.
44

5-
Additional (large) data attached to variables exist in a few different ways. The primary method for storing additional large data blobs with a variable, is to look at the `BlobEntry`s associated with a particular variable. For example:
5+
:::{tip}
6+
`Blob`s are separate from `BlobEntry`s. Various nodes on the graph can have any number of `BlobEntry`s (including duplicates), but the user does not necessary have the need to pull the bandwidth heavy blobs across all parts of the system network.
7+
:::
8+
9+
## What is a `BlobEntry`
10+
11+
Additional (large) data attached to variables exist in a few different ways. The primary method for storing additional large data as a `Blob`, however, a blob just "barcoded" binary blob. we use `BlobEntry`s to organize, find, share, distribute, make available and useful across the divergent network how a `Blob` is associated with the graph.
12+
13+
A blob entry is small about of structed data that holds reference information to find an actual binary blob which is possibly a massive amount of data.
14+
15+
### Listing BlobEntries on a Node
16+
17+
The `list` verb is purposefully limited to just returning a list of labels (i.e. `List[string]`), and therefore the following call only returns the labels of `BlobEntry`s attached a particular node (variable, session, robot, etc.):
618
```python
7-
entries = await listBlobEntries(client, context, "x0") |> fetch
19+
ent_labels = listBlobEntries(fgclient, 'x0')
20+
# ent_labels = await listBlobEntriesAsync(fgclient, 'x0')
21+
822
# human friendly labels
9-
print([en.label for en in entries])
10-
# e.g. ['Camera0', 'UserCalib', 'GPS', 'JoystickCmds']
23+
print('Human friendly BlobEntry labels on x0 are', ent_labels)
24+
# e.g. ['LEFTCAM_1002', 'LEFTCAM_1003', 'UserCalib', 'GPS', 'JoystickCmds']
25+
```
1126

12-
# machine friendly system wide unique identifier
13-
print([en.id for en in entries])
27+
```{eval-rst}
28+
.. autofunction:: navability.services.listBlobEntries
29+
.. autofunction:: navability.services.listBlobEntriesAsync
1430
```
1531

16-
:::{tip}
17-
`Blob`s are separate from `BlobEntry`s. Various nodes on the graph can have any number of `BlobEntry`s (including duplicates), but the user does not necessary have the need to pull the bandwidth heavy blobs across all parts of the system network.
18-
:::
32+
### Getting a `BlobEntry`
33+
34+
Using the human friendly label from the `listBlobEntries` above, we can fetch the `BlobEntry`
35+
```python
36+
entry = getBlobEntry(fgclient, 'LEFTCAM_1002')
37+
# entry = await getBlobEntryAsync(fgclient, 'LEFTCAM_1002')
38+
```
39+
40+
The entry object is well structured
41+
```{eval-rst}
42+
.. autoclass:: navability.entities.BlobEntry
43+
```
1944

20-
Data blobs can be fetched via, e.g. using the unique `id` (or `blobId`) of from a `BlobEntry`:
45+
## Getting the associated `Blob`
46+
47+
A binary `Blob` is basically just a "barcoded" piece of data that can be associated (via individual `BlobEntry`s) multiple times across multiple graph nodes, sessions, or robots.
48+
49+
Data blobs can be fetched via, e.g. using the unique `.blobId` as primary (or `.originId` as secondary) reference. Also note that the blob itself may also be replicated across any number of blob stores, depending on the application:
2150
```python
22-
blob = await getBlob(client, context, entries[1].id]; checkhash=false)
23-
# b'{"latitude":41.7325,"altitude":2.211,"header":{"stamp":{"secs":1670378554,"nsecs":000624417},"seq":91,"frame_id":"gps","_type":"ROS1/std_msgs/Header"},"status":{"status":0,"service":1},"position_covariance":[0.265225,0.0,0.0,0.0,0.265225,0.0,0.0,0.0,0.556516],"longitude":-49.946944,"_type":"ROS1/sensor_msgs/NavSatFix","position_covariance_type":2}'
51+
blob = getBlob(fgclient, entry.blobId]; checkhash=false) # legacy versions did not use .hash check
52+
# blob = await getBlobAsync(fgclient, entry.blobId]; checkhash=false)
2453
```
2554

26-
Data blobs are provided in binary format. A blob can be associated via any number of `BlobEntry`s across multiple graph nodes, sessions, or robots. `BlobEntry` also stores a hash value to ensure data consistency which must correspond to the stored hash upon retrieval. The check can be skipped as indicated by the option in the function call above.
55+
The blob contains binary information, for example this `mimeType = application/octet-stream/json; _type=ROS.sensor_msgs.NavSatFix`:
56+
```
57+
b'{"latitude":41.7325,"altitude":2.211,"header":{"stamp":{"secs":1670378554,"nsecs":000624417},"seq":91,"frame_id":"gps","_type":"ROS1/std_msgs/Header"},"status":{"status":0,"service":1},"position_covariance":[0.265225,0.0,0.0,0.0,0.265225,0.0,0.0,0.0,0.556516],"longitude":-49.946944,"_type":"ROS1/sensor_msgs/NavSatFix","position_covariance_type":2}'
58+
```
2759

60+
:::{tip}
61+
Depending on the blob store, it may also be possible to retrieve a blob using the `.originId` rather than `.blobId`.
62+
:::
2863

2964
:::{tip}
3065
A blob is owned by a `user` and only accessible by other users if allowed via approved roles or permissions.
3166
:::
3267

3368
:::{tip}
34-
All `blobId`s are unique across the entire distributed system and are immutable.
69+
`BlobEntry.hash` helps ensure data consistency by rehasing the retrieved blob binary data itself.
3570
:::
3671

3772
## Adding BlobEntries
3873

39-
Blobs can be linked to any variable (future node) in the graph. This is easily done by adding a BlobEntry:
40-
```python
41-
res = await addBlobEntry(client, context, 'x12', entries[1].id, entries[1].label, len(blob), entries[1].mimeType)
42-
```
43-
44-
:::{tip}
45-
More ubiqitous use of `blob` size was recently introduced to `BlobEntry` and will be unified with less user input as part of SDKs v0.6 upgrades.
74+
:::{warning}
75+
Adding `Blob` or `BlobEntry`s from the Python SDK are under construction and expected to be part of the v0.6.1 release. This functionality has already been released with the JuliaLang SDK.
4676
:::
4777

48-
## BlobEntry Structure
49-
50-
To simplify many different requirements, a `BlobEntry` has the following field structure:
51-
```
52-
{
53-
id: UUID
54-
label: string
55-
description: string
56-
blobstore: string
57-
hash: string
58-
mimeType: string
59-
origin: string
60-
61-
## planned future fields
62-
# blobId: UUID
63-
# originId: UUID
64-
# createdTimestamp: datetime
65-
# size: int
66-
# metadata: string
67-
}
78+
Blobs can be linked to any variable (future node) in the graph. This is easily done by adding a BlobEntry:
79+
```python
80+
res = addBlobEntry(fgclient, 'x12', entries[1].id, entries[1].label, len(blob), entries[1].mimeType)
81+
# res = await addBlobEntryAsync(fgclient, 'x12', entries[1].id, entries[1].label, len(blob), entries[1].mimeType)
6882
```
6983

7084
## Adding New Blobs
7185

7286
It is also possible to push data blobs:
7387
```python
74-
blobId = await addBlob(client, "testimage.png", imgblob)
88+
client = NavAbilityHttpsClient()
89+
blobId = await addBlob(fgclient.client, "testimage.png", imgblob)
7590
```
7691

7792
Remember to add at least one BlobEntry somewhere in your session so that you might find it again in the future, see `addBlobEntry` above.
7893

94+
:::{eval-rst}
95+
.. autofunction:: navability.entities.NavAbilityHttpsClient
96+
:::
97+
7998
:::{seealso}
8099
See [Tutorial 5 from ICRA 2022 for a more in-depth example of working with data blobs](sdkpynb:python/navability-sdk/icra-5-marineexample).
81100
:::
82-
83-
<!-- ```@docs
84-
listBlobEntries
85-
getBlob
86-
``` -->

docs/variables.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ The `getVariable` call returns a `Variable` object containing many fields. For
5555
```python
5656
print('The tags on this variable are', v0.tags)
5757
```
58+
5859
which would print the list of tags similar to:
5960
```
6061
The tags on this variable are ["VARIABLE", "POSE", "DOCS_EXAMPLE"]

src/navability/entities/blob/blobentry.py

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,33 @@
1111
from navability.common.timestamps import TS_FORMAT
1212
from navability.common.versions import payload_version
1313

14-
# type BlobEntry {
15-
# # This is created by server-side GraphQL #
16-
# id: ID! @id
17-
# # This is the forced server generated blobId, or the filesystem blobId. #
18-
# blobId: ID!
19-
# # This is the ID at creation at the edge, do whatever you want with this, but make sure you populate it. #
20-
# originId: ID!
21-
# label: String!
22-
# description: String
23-
# hash: String
24-
# mimeType: String
25-
# blobstore: String
26-
# origin: String
27-
# metadata: Metadata
28-
# timestamp: DateTime
29-
# nstime: BigInt
30-
# _type: String!
31-
# _version: String!
32-
33-
# createdTimestamp: DateTime! @timestamp(operations: [CREATE])
34-
# lastUpdatedTimestamp: DateTime! @timestamp(operations: [CREATE, UPDATE])
35-
36-
# user: [Variable!]! @relationship(type: "DATA_USER", direction: IN)
37-
# robot: [Robot!]! @relationship(type: "DATA_ROBOT", direction: IN)
38-
# session: [Session!]! @relationship(type: "DATA_SESSION", direction: IN)
39-
# variable: [Variable!]! @relationship(type: "DATA_VARIABLE", direction: IN)
40-
# factor: [Factor!]! @relationship(type: "DATA_FACTOR", direction: IN)
41-
42-
# # NOTE: This is for the unique label constraints
43-
# # In this situation, someone has to own this, so cannot be required
44-
# userLabel: String
45-
# robotLabel: String
46-
# sessionLabel: String
47-
# variableLabel: String
48-
# factorLabel: String
49-
# }
50-
5114

5215
@dataclass()
5316
class BlobEntry:
17+
""" A `BlobEntry` is a small about of structured data that holds reference information to find an actual blob. Many `BlobEntry`s
18+
can exist on different graph nodes spanning Robots, and Sessions which can all reference the same `Blob`. A `BlobEntry`
19+
is also a equivalent to a bridging entry between local `.originId` and a remotely assigned `.blobIds`.
20+
21+
All `.blobId`s are unique across the entire distributed system and are immutable. The `.originId` should be
22+
globally unique except for stochastic `uuid4` collisions that cannot be checked from a main reference owing to practical limitations such as network connectivity.
23+
24+
Args:
25+
id: Remotely assigned and globally unique identifier for the `BlobEntry` itself (not the `.blobId`).
26+
label: 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.
27+
blobId: 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.
28+
originId: 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 uuid to data store elements.
29+
timestamp: When the Blob itself was first created.
30+
description: Additional information that can help a different user of the Blob.
31+
blobstore: A hint about where the `Blob` itself might be stored. Remember that a Blob may be duplicated over multiple blobstores.
32+
hash: 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.]
33+
mimeType: MIME description describing the format of binary data in the `Blob`, e.g. 'image/png' or 'application/json; _type=CameraModel'.
34+
origin: Context from which a BlobEntry=>Blob was first created. E.g. user|robot|session|varlabel.
35+
metadata: Additional storage for functional metadata used in some scenarios, e.g. to support advanced features such as `parsejson(base64decode(entry.metadata))['time_sync']`.
36+
createdTimestamp: When the BlobEntry was created.
37+
lastUpdatedTimestamp: Use carefully, but necessary to support advanced usage such as time synchronization over Blob data.
38+
_type: Self type declaration for when duck-typing happens.
39+
_version: Type version of this BlobEntry.
40+
"""
5441
id: Optional[UUID]
5542
label: str
5643
blobId: Optional[UUID]

src/navability/entities/navabilityclient.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ async def mutate(self, options: MutationOptions):
5757

5858

5959
class NavAbilityHttpsClient(NavAbilityClient):
60-
"""Connection object for queries and mutations to API server.
60+
"""Connection object for queries and mutations to API server. Note, this is used but higher level objects such as DFGClient.
6161
6262
Args:
63-
NavAbilityClient (NavAbilityClient): the connection object
63+
NavAbilityClient: the connection object to a server (cloud our deployed).
64+
url: Network path to the API (cloud or deployed).
65+
auth_token: Token for auth, likely provided by NavAbility App Connect page.
6466
"""
6567
def __init__(self, url: str = "https://api.navability.io", auth_token: str = "") -> None:
6668
super().__init__()

src/navability/services/blobentry.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,16 @@ async def listBlobEntriesAsync(
7272
fgclient: DFGClient,
7373
variableLabel: str,
7474
):
75-
client = fgclient.client
76-
context = fgclient.context
77-
78-
""" List the blob entries associated with a particular variable.
75+
""" Return a list of `BlobEntry` labels (asynchronous version).
7976
8077
Args:
81-
fgclient (NavAbilityClient): client connection to API server
82-
and unique context with (user, robot, session)
78+
fgclient (DFGClient): client connection to API server
79+
with unique context (user, robot, session)
8380
variableLabel (string): list data entries connected to which variable
84-
85-
Returns:
86-
List[String]: A list of `BlobEntry` labels
87-
8881
"""
82+
client = fgclient.client
83+
context = fgclient.context
84+
8985
params = {
9086
"userLabel": context.userLabel,
9187
"robotLabel": context.robotLabel,
@@ -127,6 +123,13 @@ def listBlobEntries(
127123
fgclient: DFGClient,
128124
variableLabel: str,
129125
):
126+
""" Return a list of `BlobEntry` labels (synchronous version).
127+
128+
Args:
129+
fgclient (DFGClient): client connection to API server
130+
with unique context (user, robot, session)
131+
variableLabel (string): list data entries connected to which variable
132+
"""
130133
tsk = listBlobEntriesAsync(fgclient, variableLabel)
131134
return asyncio.run(tsk)
132135

0 commit comments

Comments
 (0)