viam-sdk 0.55.1__py3-none-manylinux2014_aarch64.whl → 0.57.0__py3-none-manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of viam-sdk might be problematic. Click here for more details.
- viam/app/app_client.py +3 -5
- viam/app/billing_client.py +3 -5
- viam/app/data_client.py +129 -11
- viam/app/ml_training_client.py +3 -5
- viam/app/provisioning_client.py +3 -5
- viam/app/viam_client.py +19 -1
- viam/gen/app/agent/v1/agent_pb2.py +1 -1
- viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +1 -1
- viam/gen/app/data/v1/data_grpc.py +26 -2
- viam/gen/app/data/v1/data_pb2.py +123 -105
- viam/gen/app/data/v1/data_pb2.pyi +186 -4
- viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +1 -1
- viam/gen/app/dataset/v1/dataset_pb2.py +1 -1
- viam/gen/app/datasync/v1/data_sync_pb2.py +1 -1
- viam/gen/app/mlinference/v1/ml_inference_pb2.py +1 -1
- viam/gen/app/mltraining/v1/ml_training_pb2.py +1 -1
- viam/gen/app/packages/v1/packages_pb2.py +1 -1
- viam/gen/app/v1/app_pb2.py +1 -1
- viam/gen/app/v1/billing_pb2.py +52 -48
- viam/gen/app/v1/billing_pb2.pyi +59 -3
- viam/gen/app/v1/end_user_pb2.py +1 -1
- viam/gen/app/v1/robot_pb2.py +1 -1
- viam/gen/common/v1/common_pb2.py +1 -1
- viam/gen/component/arm/v1/arm_pb2.py +1 -1
- viam/gen/component/audioinput/v1/audioinput_pb2.py +1 -1
- viam/gen/component/base/v1/base_pb2.py +1 -1
- viam/gen/component/board/v1/board_pb2.py +1 -1
- viam/gen/component/button/v1/button_pb2.py +1 -1
- viam/gen/component/camera/v1/camera_pb2.py +1 -1
- viam/gen/component/encoder/v1/encoder_pb2.py +1 -1
- viam/gen/component/gantry/v1/gantry_pb2.py +1 -1
- viam/gen/component/generic/v1/generic_pb2.py +1 -1
- viam/gen/component/gripper/v1/gripper_pb2.py +1 -1
- viam/gen/component/inputcontroller/v1/input_controller_pb2.py +1 -1
- viam/gen/component/motor/v1/motor_pb2.py +1 -1
- viam/gen/component/movementsensor/v1/movementsensor_pb2.py +1 -1
- viam/gen/component/posetracker/v1/pose_tracker_pb2.py +1 -1
- viam/gen/component/powersensor/v1/powersensor_pb2.py +1 -1
- viam/gen/component/sensor/v1/sensor_pb2.py +1 -1
- viam/gen/component/servo/v1/servo_pb2.py +1 -1
- viam/gen/component/switch/v1/switch_pb2.py +1 -1
- viam/gen/component/testecho/v1/testecho_pb2.py +1 -1
- viam/gen/module/v1/module_pb2.py +1 -1
- viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +1 -1
- viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +1 -1
- viam/gen/proto/rpc/v1/auth_pb2.py +1 -1
- viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +1 -1
- viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +1 -1
- viam/gen/provisioning/v1/provisioning_pb2.py +1 -1
- viam/gen/robot/v1/robot_pb2.py +1 -1
- viam/gen/service/datamanager/v1/data_manager_pb2.py +1 -1
- viam/gen/service/discovery/v1/discovery_pb2.py +1 -1
- viam/gen/service/generic/v1/generic_pb2.py +1 -1
- viam/gen/service/mlmodel/v1/mlmodel_pb2.py +1 -1
- viam/gen/service/motion/v1/motion_pb2.py +87 -63
- viam/gen/service/motion/v1/motion_pb2.pyi +92 -66
- viam/gen/service/navigation/v1/navigation_pb2.py +1 -1
- viam/gen/service/sensors/v1/sensors_pb2.py +1 -1
- viam/gen/service/shell/v1/shell_pb2.py +1 -1
- viam/gen/service/slam/v1/slam_pb2.py +1 -1
- viam/gen/service/vision/v1/vision_pb2.py +1 -1
- viam/gen/service/worldstatestore/v1/world_state_store_pb2.py +1 -1
- viam/gen/stream/v1/stream_pb2.py +1 -1
- viam/gen/tagger/v1/tagger_pb2.py +1 -1
- viam/proto/app/billing.py +4 -0
- viam/proto/app/data/__init__.py +18 -0
- viam/services/motion/client.py +8 -9
- viam/services/motion/motion.py +37 -43
- viam/services/worldstatestore/worldstatestore.py +2 -2
- viam/sessions_client.py +34 -25
- viam/version_metadata.py +2 -2
- {viam_sdk-0.55.1.dist-info → viam_sdk-0.57.0.dist-info}/METADATA +1 -1
- {viam_sdk-0.55.1.dist-info → viam_sdk-0.57.0.dist-info}/RECORD +75 -75
- {viam_sdk-0.55.1.dist-info → viam_sdk-0.57.0.dist-info}/WHEEL +0 -0
- {viam_sdk-0.55.1.dist-info → viam_sdk-0.57.0.dist-info}/licenses/LICENSE +0 -0
viam/services/motion/client.py
CHANGED
|
@@ -10,7 +10,6 @@ from viam.proto.common import (
|
|
|
10
10
|
GeoPoint,
|
|
11
11
|
Pose,
|
|
12
12
|
PoseInFrame,
|
|
13
|
-
ResourceName,
|
|
14
13
|
Transform,
|
|
15
14
|
WorldState,
|
|
16
15
|
)
|
|
@@ -54,7 +53,7 @@ class MotionClient(Motion, ReconfigurableResourceRPCClientBase):
|
|
|
54
53
|
|
|
55
54
|
async def move(
|
|
56
55
|
self,
|
|
57
|
-
component_name:
|
|
56
|
+
component_name: str,
|
|
58
57
|
destination: PoseInFrame,
|
|
59
58
|
world_state: Optional[WorldState] = None,
|
|
60
59
|
constraints: Optional[Constraints] = None,
|
|
@@ -77,9 +76,9 @@ class MotionClient(Motion, ReconfigurableResourceRPCClientBase):
|
|
|
77
76
|
|
|
78
77
|
async def move_on_globe(
|
|
79
78
|
self,
|
|
80
|
-
component_name:
|
|
79
|
+
component_name: str,
|
|
81
80
|
destination: GeoPoint,
|
|
82
|
-
movement_sensor_name:
|
|
81
|
+
movement_sensor_name: str,
|
|
83
82
|
obstacles: Optional[Sequence[GeoGeometry]] = None,
|
|
84
83
|
heading: Optional[float] = None,
|
|
85
84
|
configuration: Optional[MotionConfiguration] = None,
|
|
@@ -106,9 +105,9 @@ class MotionClient(Motion, ReconfigurableResourceRPCClientBase):
|
|
|
106
105
|
|
|
107
106
|
async def move_on_map(
|
|
108
107
|
self,
|
|
109
|
-
component_name:
|
|
108
|
+
component_name: str,
|
|
110
109
|
destination: Pose,
|
|
111
|
-
slam_service_name:
|
|
110
|
+
slam_service_name: str,
|
|
112
111
|
configuration: Optional[MotionConfiguration] = None,
|
|
113
112
|
obstacles: Optional[Sequence[Geometry]] = None,
|
|
114
113
|
*,
|
|
@@ -131,7 +130,7 @@ class MotionClient(Motion, ReconfigurableResourceRPCClientBase):
|
|
|
131
130
|
|
|
132
131
|
async def stop_plan(
|
|
133
132
|
self,
|
|
134
|
-
component_name:
|
|
133
|
+
component_name: str,
|
|
135
134
|
*,
|
|
136
135
|
extra: Optional[Mapping[str, ValueTypes]] = None,
|
|
137
136
|
timeout: Optional[float] = None,
|
|
@@ -149,7 +148,7 @@ class MotionClient(Motion, ReconfigurableResourceRPCClientBase):
|
|
|
149
148
|
|
|
150
149
|
async def get_plan(
|
|
151
150
|
self,
|
|
152
|
-
component_name:
|
|
151
|
+
component_name: str,
|
|
153
152
|
last_plan_only: bool = False,
|
|
154
153
|
execution_id: Optional[str] = None,
|
|
155
154
|
*,
|
|
@@ -189,7 +188,7 @@ class MotionClient(Motion, ReconfigurableResourceRPCClientBase):
|
|
|
189
188
|
|
|
190
189
|
async def get_pose(
|
|
191
190
|
self,
|
|
192
|
-
component_name:
|
|
191
|
+
component_name: str,
|
|
193
192
|
destination_frame: str,
|
|
194
193
|
supplemental_transforms: Optional[Sequence[Transform]] = None,
|
|
195
194
|
*,
|
viam/services/motion/motion.py
CHANGED
|
@@ -7,7 +7,7 @@ if sys.version_info >= (3, 10):
|
|
|
7
7
|
else:
|
|
8
8
|
from typing_extensions import TypeAlias
|
|
9
9
|
|
|
10
|
-
from viam.proto.common import GeoGeometry, Geometry, GeoPoint, Pose, PoseInFrame,
|
|
10
|
+
from viam.proto.common import GeoGeometry, Geometry, GeoPoint, Pose, PoseInFrame, Transform, WorldState
|
|
11
11
|
from viam.proto.service.motion import Constraints, GetPlanResponse, MotionConfiguration, PlanStatusWithID
|
|
12
12
|
from viam.resource.types import API, RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_SERVICE
|
|
13
13
|
from viam.utils import ValueTypes
|
|
@@ -33,7 +33,7 @@ class Motion(ServiceBase):
|
|
|
33
33
|
@abc.abstractmethod
|
|
34
34
|
async def move(
|
|
35
35
|
self,
|
|
36
|
-
component_name:
|
|
36
|
+
component_name: str,
|
|
37
37
|
destination: PoseInFrame,
|
|
38
38
|
world_state: Optional[WorldState] = None,
|
|
39
39
|
constraints: Optional[Constraints] = None,
|
|
@@ -44,18 +44,17 @@ class Motion(ServiceBase):
|
|
|
44
44
|
"""Plan and execute a movement to move the component specified to its goal destination.
|
|
45
45
|
|
|
46
46
|
Note: Frames designated with respect to components can also be used as the ``component_name`` when calling for a move. This
|
|
47
|
-
technique allows for planning and moving the frame itself to the ``destination``.
|
|
48
|
-
|
|
47
|
+
technique allows for planning and moving the frame itself to the ``destination``.
|
|
48
|
+
To do so, simply pass in a string into ``component_name``. Ex::
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
success = await MotionServiceClient.move(resource_name, ...)
|
|
50
|
+
success = await MotionServiceClient.move("externalFrame", ...)
|
|
52
51
|
|
|
53
52
|
::
|
|
54
53
|
|
|
55
54
|
motion = MotionClient.from_robot(robot=machine, name="builtin")
|
|
56
55
|
|
|
57
|
-
# Assumes
|
|
58
|
-
gripper_name =
|
|
56
|
+
# Assumes "my_gripper" on the machine
|
|
57
|
+
gripper_name = "my_gripper"
|
|
59
58
|
my_frame = "my_gripper_offset"
|
|
60
59
|
|
|
61
60
|
goal_pose = Pose(x=0, y=0, z=300, o_x=0, o_y=0, o_z=1, theta=0)
|
|
@@ -69,7 +68,7 @@ class Motion(ServiceBase):
|
|
|
69
68
|
extra={})
|
|
70
69
|
|
|
71
70
|
Args:
|
|
72
|
-
component_name (
|
|
71
|
+
component_name (str): Name of a component on a given robot.
|
|
73
72
|
destination (viam.proto.common.PoseInFrame): The destination to move to, expressed as a ``Pose`` and the frame in which it was
|
|
74
73
|
observed.
|
|
75
74
|
world_state (viam.proto.common.WorldState): When supplied, the motion service will create a plan that obeys any constraints
|
|
@@ -95,9 +94,9 @@ class Motion(ServiceBase):
|
|
|
95
94
|
@abc.abstractmethod
|
|
96
95
|
async def move_on_globe(
|
|
97
96
|
self,
|
|
98
|
-
component_name:
|
|
97
|
+
component_name: str,
|
|
99
98
|
destination: GeoPoint,
|
|
100
|
-
movement_sensor_name:
|
|
99
|
+
movement_sensor_name: str,
|
|
101
100
|
obstacles: Optional[Sequence[GeoGeometry]] = None,
|
|
102
101
|
heading: Optional[float] = None,
|
|
103
102
|
configuration: Optional[MotionConfiguration] = None,
|
|
@@ -120,24 +119,23 @@ class Motion(ServiceBase):
|
|
|
120
119
|
|
|
121
120
|
motion = MotionClient.from_robot(robot=machine, name="builtin")
|
|
122
121
|
|
|
123
|
-
# Get the
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"my_movement_sensor")
|
|
122
|
+
# Get the names of the base and movement sensor
|
|
123
|
+
my_base_name = "my_base"
|
|
124
|
+
mvmnt_sensor_name = "my_movement_sensor"
|
|
127
125
|
# Define a destination GeoPoint at the GPS coordinates [0, 0]
|
|
128
126
|
my_destination = movement_sensor.GeoPoint(latitude=0, longitude=0)
|
|
129
127
|
|
|
130
128
|
# Move the base component to the designated geographic location, as reported by the movement sensor
|
|
131
129
|
execution_id = await motion.move_on_globe(
|
|
132
|
-
component_name=
|
|
130
|
+
component_name=my_base_name,
|
|
133
131
|
destination=my_destination,
|
|
134
|
-
movement_sensor_name=
|
|
132
|
+
movement_sensor_name=mvmnt_sensor_name)
|
|
135
133
|
|
|
136
134
|
Args:
|
|
137
|
-
component_name (
|
|
135
|
+
component_name (str): The name of the base to move.
|
|
138
136
|
destination (GeoPoint): The location of the component's destination, represented in geographic notation as a
|
|
139
137
|
GeoPoint (lat, lng).
|
|
140
|
-
movement_sensor_name (
|
|
138
|
+
movement_sensor_name (str): The name of the movement sensor that you want to use to check
|
|
141
139
|
the machine's location.
|
|
142
140
|
obstacles (Optional[Sequence[GeoGeometry]]): Obstacles to consider when planning the motion of the component,
|
|
143
141
|
with each represented as a GeoGeometry. Default: None
|
|
@@ -170,9 +168,9 @@ class Motion(ServiceBase):
|
|
|
170
168
|
@abc.abstractmethod
|
|
171
169
|
async def move_on_map(
|
|
172
170
|
self,
|
|
173
|
-
component_name:
|
|
171
|
+
component_name: str,
|
|
174
172
|
destination: Pose,
|
|
175
|
-
slam_service_name:
|
|
173
|
+
slam_service_name: str,
|
|
176
174
|
configuration: Optional[MotionConfiguration] = None,
|
|
177
175
|
obstacles: Optional[Sequence[Geometry]] = None,
|
|
178
176
|
*,
|
|
@@ -194,23 +192,23 @@ class Motion(ServiceBase):
|
|
|
194
192
|
|
|
195
193
|
motion = MotionClient.from_robot(robot=machine, name="builtin")
|
|
196
194
|
|
|
197
|
-
# Get the
|
|
198
|
-
|
|
199
|
-
my_slam_service_name =
|
|
195
|
+
# Get the names of the base component and SLAM service
|
|
196
|
+
my_base_name = "my_base"
|
|
197
|
+
my_slam_service_name = "my_slam_service"
|
|
200
198
|
|
|
201
199
|
# Define a destination pose with respect to the origin of the map from the SLAM service "my_slam_service"
|
|
202
200
|
my_pose = Pose(y=10)
|
|
203
201
|
|
|
204
202
|
# Move the base component to the destination pose of Y=10, a location of
|
|
205
203
|
# (0, 10, 0) in respect to the origin of the map
|
|
206
|
-
execution_id = await motion.move_on_map(component_name=
|
|
204
|
+
execution_id = await motion.move_on_map(component_name=my_base_name,
|
|
207
205
|
destination=my_pose,
|
|
208
206
|
slam_service_name=my_slam_service_name)
|
|
209
207
|
|
|
210
208
|
Args:
|
|
211
|
-
component_name (
|
|
209
|
+
component_name (str): The name of the base to move.
|
|
212
210
|
destination (Pose): The destination, which can be any Pose with respect to the SLAM map's origin.
|
|
213
|
-
slam_service_name (
|
|
211
|
+
slam_service_name (str): The name of the SLAM service from which the SLAM map is requested.
|
|
214
212
|
configuration (Optional[MotionConfiguration]): The configuration you want to set across this machine for this motion service.
|
|
215
213
|
This parameter and each of its fields are optional.
|
|
216
214
|
|
|
@@ -237,7 +235,7 @@ class Motion(ServiceBase):
|
|
|
237
235
|
@abc.abstractmethod
|
|
238
236
|
async def stop_plan(
|
|
239
237
|
self,
|
|
240
|
-
component_name:
|
|
238
|
+
component_name: str,
|
|
241
239
|
*,
|
|
242
240
|
extra: Optional[Mapping[str, ValueTypes]] = None,
|
|
243
241
|
timeout: Optional[float] = None,
|
|
@@ -251,11 +249,11 @@ class Motion(ServiceBase):
|
|
|
251
249
|
# Assuming a `move_on_globe()` started the execution
|
|
252
250
|
# Stop the base component which was instructed to move by `move_on_globe()`
|
|
253
251
|
# or `move_on_map()`
|
|
254
|
-
|
|
252
|
+
my_base_name = "my_base"
|
|
255
253
|
await motion.stop_plan(component_name=mvmnt_sensor)
|
|
256
254
|
|
|
257
255
|
Args:
|
|
258
|
-
component_name (
|
|
256
|
+
component_name (str): The component to stop
|
|
259
257
|
|
|
260
258
|
For more information, see `Motion service <https://docs.viam.com/dev/reference/apis/services/motion/#stopplan>`_.
|
|
261
259
|
"""
|
|
@@ -264,7 +262,7 @@ class Motion(ServiceBase):
|
|
|
264
262
|
@abc.abstractmethod
|
|
265
263
|
async def get_plan(
|
|
266
264
|
self,
|
|
267
|
-
component_name:
|
|
265
|
+
component_name: str,
|
|
268
266
|
last_plan_only: bool = False,
|
|
269
267
|
execution_id: Optional[str] = None,
|
|
270
268
|
*,
|
|
@@ -291,12 +289,12 @@ class Motion(ServiceBase):
|
|
|
291
289
|
::
|
|
292
290
|
|
|
293
291
|
motion = MotionClient.from_robot(robot=machine, name="builtin")
|
|
294
|
-
|
|
292
|
+
my_base_name = "my_base"
|
|
295
293
|
# Get the plan(s) of the base component which was instructed to move by `MoveOnGlobe()` or `MoveOnMap()`
|
|
296
|
-
resp = await motion.get_plan(component_name=
|
|
294
|
+
resp = await motion.get_plan(component_name=my_base_name)
|
|
297
295
|
|
|
298
296
|
Args:
|
|
299
|
-
component_name (
|
|
297
|
+
component_name (str): The component to stop
|
|
300
298
|
last_plan_only (Optional[bool]): If supplied, the response will only return the last plan for the component / execution.
|
|
301
299
|
execution_id (Optional[str]): If supplied, the response will only return plans with the provided execution_id.
|
|
302
300
|
|
|
@@ -343,7 +341,7 @@ class Motion(ServiceBase):
|
|
|
343
341
|
@abc.abstractmethod
|
|
344
342
|
async def get_pose(
|
|
345
343
|
self,
|
|
346
|
-
component_name:
|
|
344
|
+
component_name: str,
|
|
347
345
|
destination_frame: str,
|
|
348
346
|
supplemental_transforms: Optional[Sequence[Transform]] = None,
|
|
349
347
|
*,
|
|
@@ -358,22 +356,18 @@ class Motion(ServiceBase):
|
|
|
358
356
|
# Note that the example uses the ``Gripper`` class, but any component class that inherits from ``ComponentBase`` will work
|
|
359
357
|
# (``Arm``, ``Base``, etc).
|
|
360
358
|
|
|
361
|
-
# Create a `component_name`:
|
|
362
|
-
component_name = Gripper.get_resource_name("my_gripper")
|
|
363
|
-
|
|
364
359
|
from viam.components.gripper import Gripper
|
|
365
360
|
from viam.services.motion import MotionClient
|
|
366
361
|
|
|
367
362
|
# Assume that the connect function is written and will return a valid machine.
|
|
368
|
-
|
|
363
|
+
machine = await connect()
|
|
369
364
|
|
|
370
365
|
motion = MotionClient.from_robot(robot=machine, name="builtin")
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
destination_frame="world")
|
|
366
|
+
gripperPoseInWorld = await motion.get_pose(component_name="my_gripper",
|
|
367
|
+
destination_frame="world")
|
|
374
368
|
|
|
375
369
|
Args:
|
|
376
|
-
component_name (
|
|
370
|
+
component_name (str): Name of a component on a robot.
|
|
377
371
|
destination_frame (str): Name of the desired reference frame.
|
|
378
372
|
supplemental_transforms (Optional[List[viam.proto.common.Transform]]): Transforms used to augment the robot's frame while
|
|
379
373
|
calculating pose.
|
|
@@ -17,7 +17,7 @@ class WorldStateStore(ServiceBase):
|
|
|
17
17
|
changes to world state transforms, which represent the pose of objects in different
|
|
18
18
|
reference frames. This functionality can be used to create custom visualizations of the world state.
|
|
19
19
|
|
|
20
|
-
For more information, see `WorldStateStore service <https://docs.viam.com/dev/reference/apis/services/
|
|
20
|
+
For more information, see `WorldStateStore service <https://docs.viam.com/dev/reference/apis/services/world-state-store/>`_.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
API: Final = API( # pyright: ignore [reportIncompatibleVariableOverride]
|
|
@@ -85,6 +85,6 @@ class WorldStateStore(ServiceBase):
|
|
|
85
85
|
print(f"Transform {change.transform.uuid} {change.change_type}")
|
|
86
86
|
|
|
87
87
|
Returns:
|
|
88
|
-
|
|
88
|
+
AsyncGenerator[StreamTransformChangesResponse, None]: A stream of transform changes
|
|
89
89
|
"""
|
|
90
90
|
...
|
viam/sessions_client.py
CHANGED
|
@@ -2,6 +2,8 @@ import asyncio
|
|
|
2
2
|
import importlib
|
|
3
3
|
import pkgutil
|
|
4
4
|
import sys
|
|
5
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
6
|
+
from contextlib import asynccontextmanager
|
|
5
7
|
from copy import deepcopy
|
|
6
8
|
from datetime import timedelta
|
|
7
9
|
from enum import IntEnum
|
|
@@ -46,6 +48,7 @@ class SessionsClient:
|
|
|
46
48
|
_heartbeat_interval: Optional[timedelta]
|
|
47
49
|
_supported: _SupportedState
|
|
48
50
|
_thread: Optional[Thread]
|
|
51
|
+
_pool: ThreadPoolExecutor
|
|
49
52
|
|
|
50
53
|
_HEARTBEAT_MONITORED_METHODS: MutableMapping[str, bool] = {}
|
|
51
54
|
|
|
@@ -71,6 +74,7 @@ class SessionsClient:
|
|
|
71
74
|
self._heartbeat_interval = None
|
|
72
75
|
self._supported = _SupportedState.UNKNOWN
|
|
73
76
|
self._thread = None
|
|
77
|
+
self._pool = ThreadPoolExecutor()
|
|
74
78
|
|
|
75
79
|
listen(self.channel, SendRequest, self._send_request)
|
|
76
80
|
listen(self.channel, RecvTrailingMetadata, self._recv_trailers)
|
|
@@ -105,39 +109,45 @@ class SessionsClient:
|
|
|
105
109
|
LOGGER.debug("Session expired")
|
|
106
110
|
self.reset()
|
|
107
111
|
|
|
112
|
+
@asynccontextmanager
|
|
113
|
+
async def _acquire_lock_async(self):
|
|
114
|
+
loop = asyncio.get_event_loop()
|
|
115
|
+
await loop.run_in_executor(self._pool, self._lock.acquire)
|
|
116
|
+
try:
|
|
117
|
+
yield
|
|
118
|
+
finally:
|
|
119
|
+
self._lock.release()
|
|
120
|
+
|
|
108
121
|
@property
|
|
109
122
|
async def metadata(self) -> _MetadataLike:
|
|
110
|
-
with self.
|
|
123
|
+
async with self._acquire_lock_async():
|
|
111
124
|
if self._disabled or self._supported != _SupportedState.UNKNOWN:
|
|
112
125
|
return self._metadata
|
|
113
126
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
with self._lock:
|
|
127
|
+
request = StartSessionRequest(resume=self._current_id)
|
|
128
|
+
try:
|
|
129
|
+
response: StartSessionResponse = await self.client.StartSession(request)
|
|
130
|
+
except GRPCError as error:
|
|
131
|
+
if error.status == Status.UNIMPLEMENTED:
|
|
120
132
|
self._reset()
|
|
121
133
|
self._supported = _SupportedState.FALSE
|
|
122
134
|
return self._metadata
|
|
123
|
-
|
|
124
|
-
|
|
135
|
+
else:
|
|
136
|
+
raise
|
|
125
137
|
|
|
126
|
-
|
|
127
|
-
|
|
138
|
+
if response is None:
|
|
139
|
+
raise GRPCError(status=Status.INTERNAL, message="Expected response to start session")
|
|
128
140
|
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
if response.heartbeat_window is None:
|
|
142
|
+
raise GRPCError(status=Status.INTERNAL, message="Expected heartbeat window in response to start session")
|
|
131
143
|
|
|
132
|
-
with self._lock:
|
|
133
144
|
self._supported = _SupportedState.TRUE
|
|
134
145
|
self._heartbeat_interval = response.heartbeat_window.ToTimedelta()
|
|
135
146
|
self._current_id = response.id
|
|
136
147
|
|
|
137
|
-
|
|
138
|
-
|
|
148
|
+
# tick once to ensure heartbeats are supported
|
|
149
|
+
await self._heartbeat_tick(self.client)
|
|
139
150
|
|
|
140
|
-
with self._lock:
|
|
141
151
|
if self._thread is not None:
|
|
142
152
|
self._reset()
|
|
143
153
|
if self._supported == _SupportedState.TRUE:
|
|
@@ -156,17 +166,16 @@ class SessionsClient:
|
|
|
156
166
|
return self._metadata
|
|
157
167
|
|
|
158
168
|
async def _heartbeat_tick(self, client: RobotServiceStub):
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
request = SendSessionHeartbeatRequest(id=self._current_id)
|
|
169
|
+
if not self._current_id:
|
|
170
|
+
LOGGER.debug("Failed to send heartbeat, session client reset")
|
|
171
|
+
return
|
|
172
|
+
request = SendSessionHeartbeatRequest(id=self._current_id)
|
|
164
173
|
|
|
165
174
|
try:
|
|
166
175
|
await client.SendSessionHeartbeat(request)
|
|
167
176
|
except (GRPCError, StreamTerminatedError):
|
|
168
177
|
LOGGER.debug("Heartbeat terminated", exc_info=True)
|
|
169
|
-
self.
|
|
178
|
+
self._reset()
|
|
170
179
|
else:
|
|
171
180
|
LOGGER.debug("Sent heartbeat successfully")
|
|
172
181
|
|
|
@@ -185,10 +194,10 @@ class SessionsClient:
|
|
|
185
194
|
channel = await dial(address=addr, options=self._dial_options)
|
|
186
195
|
client = RobotServiceStub(channel.channel)
|
|
187
196
|
while True:
|
|
188
|
-
with self.
|
|
197
|
+
async with self._acquire_lock_async():
|
|
189
198
|
if self._supported != _SupportedState.TRUE:
|
|
190
199
|
return
|
|
191
|
-
|
|
200
|
+
await self._heartbeat_tick(client)
|
|
192
201
|
await asyncio.sleep(wait)
|
|
193
202
|
|
|
194
203
|
@property
|
viam/version_metadata.py
CHANGED