Skip to content

Commit 6eb9f12

Browse files
authoredMar 6, 2025··
Add actuating methods as a check (#344)
1 parent cbebf35 commit 6eb9f12

File tree

15 files changed

+6299
-21
lines changed

15 files changed

+6299
-21
lines changed
 

‎Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ buf:
1515
buf generate buf.build/viamrobotics/api:${API_VERSION}
1616
buf generate buf.build/googleapis/googleapis
1717
buf generate buf.build/protocolbuffers/wellknowntypes --path google/protobuf/any.proto
18+
buf generate buf.build/protocolbuffers/wellknowntypes --path google/protobuf/descriptor.proto
1819
buf generate buf.build/protocolbuffers/wellknowntypes --path google/protobuf/duration.proto
1920
buf generate buf.build/protocolbuffers/wellknowntypes --path google/protobuf/empty.proto
2021
buf generate buf.build/protocolbuffers/wellknowntypes --path google/protobuf/struct.proto
2122
buf generate buf.build/protocolbuffers/wellknowntypes --path google/protobuf/timestamp.proto
2223
buf generate buf.build/protocolbuffers/wellknowntypes --path google/protobuf/wrappers.proto
24+
buf generate buf.build/grpc/grpc --path grpc/reflection/v1/reflection.proto
2325
# There's a bug in dart protoc where it doesn't understand that `call` is already taken
2426
$(SED) 's/yield\* call(call, await request);/yield\* this\.call(call, await request);/g' ./lib/src/gen/proto/rpc/webrtc/v1/signaling.pbgrpc.dart
2527
dart run tool/export_protos.dart

‎example/viam_example_app/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
*.swp
66
.DS_Store
77
.atom/
8+
.build/
89
.buildlog/
910
.history
1011
.svn/
12+
.swiftpm/
1113
migrate_working_dir/
1214

1315
# IntelliJ related

‎example/viam_example_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
ignoresPersistentStateOnLaunch = "NO"
6060
debugDocumentVersioning = "YES"
6161
debugServiceExtension = "internal"
62+
enableGPUValidationMode = "1"
6263
allowLocationSimulation = "YES">
6364
<BuildableProductRunnable
6465
runnableDebuggingMode = "0">

‎example/viam_example_app/macos/Runner/AppDelegate.swift

+4
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@ class AppDelegate: FlutterAppDelegate {
66
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
77
return true
88
}
9+
10+
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
11+
return true
12+
}
913
}

‎lib/src/gen/google/protobuf/descriptor.pb.dart

+3,905
Large diffs are not rendered by default.

‎lib/src/gen/google/protobuf/descriptor.pbenum.dart

+380
Large diffs are not rendered by default.

‎lib/src/gen/google/protobuf/descriptor.pbjson.dart

+1,047
Large diffs are not rendered by default.

‎lib/src/gen/grpc/reflection/v1/reflection.pb.dart

+683
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//
2+
// Generated code. Do not modify.
3+
// source: grpc/reflection/v1/reflection.proto
4+
//
5+
// @dart = 2.12
6+
7+
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
8+
// ignore_for_file: constant_identifier_names, library_prefixes
9+
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
10+
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//
2+
// Generated code. Do not modify.
3+
// source: grpc/reflection/v1/reflection.proto
4+
//
5+
// @dart = 2.12
6+
7+
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
8+
// ignore_for_file: constant_identifier_names, library_prefixes
9+
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
10+
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
11+
12+
import 'dart:async' as $async;
13+
import 'dart:core' as $core;
14+
15+
import 'package:grpc/service_api.dart' as $grpc;
16+
import 'package:protobuf/protobuf.dart' as $pb;
17+
18+
import 'reflection.pb.dart' as $0;
19+
20+
export 'reflection.pb.dart';
21+
22+
@$pb.GrpcServiceName('grpc.reflection.v1.ServerReflection')
23+
class ServerReflectionClient extends $grpc.Client {
24+
static final _$serverReflectionInfo = $grpc.ClientMethod<$0.ServerReflectionRequest, $0.ServerReflectionResponse>(
25+
'/grpc.reflection.v1.ServerReflection/ServerReflectionInfo',
26+
($0.ServerReflectionRequest value) => value.writeToBuffer(),
27+
($core.List<$core.int> value) => $0.ServerReflectionResponse.fromBuffer(value));
28+
29+
ServerReflectionClient($grpc.ClientChannel channel,
30+
{$grpc.CallOptions? options,
31+
$core.Iterable<$grpc.ClientInterceptor>? interceptors})
32+
: super(channel, options: options,
33+
interceptors: interceptors);
34+
35+
$grpc.ResponseStream<$0.ServerReflectionResponse> serverReflectionInfo($async.Stream<$0.ServerReflectionRequest> request, {$grpc.CallOptions? options}) {
36+
return $createStreamingCall(_$serverReflectionInfo, request, options: options);
37+
}
38+
}
39+
40+
@$pb.GrpcServiceName('grpc.reflection.v1.ServerReflection')
41+
abstract class ServerReflectionServiceBase extends $grpc.Service {
42+
$core.String get $name => 'grpc.reflection.v1.ServerReflection';
43+
44+
ServerReflectionServiceBase() {
45+
$addMethod($grpc.ServiceMethod<$0.ServerReflectionRequest, $0.ServerReflectionResponse>(
46+
'ServerReflectionInfo',
47+
serverReflectionInfo,
48+
true,
49+
true,
50+
($core.List<$core.int> value) => $0.ServerReflectionRequest.fromBuffer(value),
51+
($0.ServerReflectionResponse value) => value.writeToBuffer()));
52+
}
53+
54+
$async.Stream<$0.ServerReflectionResponse> serverReflectionInfo($grpc.ServiceCall call, $async.Stream<$0.ServerReflectionRequest> request);
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//
2+
// Generated code. Do not modify.
3+
// source: grpc/reflection/v1/reflection.proto
4+
//
5+
// @dart = 2.12
6+
7+
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
8+
// ignore_for_file: constant_identifier_names, library_prefixes
9+
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
10+
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
11+
12+
import 'dart:convert' as $convert;
13+
import 'dart:core' as $core;
14+
import 'dart:typed_data' as $typed_data;
15+
16+
@$core.Deprecated('Use serverReflectionRequestDescriptor instead')
17+
const ServerReflectionRequest$json = {
18+
'1': 'ServerReflectionRequest',
19+
'2': [
20+
{'1': 'host', '3': 1, '4': 1, '5': 9, '10': 'host'},
21+
{'1': 'file_by_filename', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'fileByFilename'},
22+
{'1': 'file_containing_symbol', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'fileContainingSymbol'},
23+
{'1': 'file_containing_extension', '3': 5, '4': 1, '5': 11, '6': '.grpc.reflection.v1.ExtensionRequest', '9': 0, '10': 'fileContainingExtension'},
24+
{'1': 'all_extension_numbers_of_type', '3': 6, '4': 1, '5': 9, '9': 0, '10': 'allExtensionNumbersOfType'},
25+
{'1': 'list_services', '3': 7, '4': 1, '5': 9, '9': 0, '10': 'listServices'},
26+
],
27+
'8': [
28+
{'1': 'message_request'},
29+
],
30+
};
31+
32+
/// Descriptor for `ServerReflectionRequest`. Decode as a `google.protobuf.DescriptorProto`.
33+
final $typed_data.Uint8List serverReflectionRequestDescriptor = $convert.base64Decode(
34+
'ChdTZXJ2ZXJSZWZsZWN0aW9uUmVxdWVzdBISCgRob3N0GAEgASgJUgRob3N0EioKEGZpbGVfYn'
35+
'lfZmlsZW5hbWUYAyABKAlIAFIOZmlsZUJ5RmlsZW5hbWUSNgoWZmlsZV9jb250YWluaW5nX3N5'
36+
'bWJvbBgEIAEoCUgAUhRmaWxlQ29udGFpbmluZ1N5bWJvbBJiChlmaWxlX2NvbnRhaW5pbmdfZX'
37+
'h0ZW5zaW9uGAUgASgLMiQuZ3JwYy5yZWZsZWN0aW9uLnYxLkV4dGVuc2lvblJlcXVlc3RIAFIX'
38+
'ZmlsZUNvbnRhaW5pbmdFeHRlbnNpb24SQgodYWxsX2V4dGVuc2lvbl9udW1iZXJzX29mX3R5cG'
39+
'UYBiABKAlIAFIZYWxsRXh0ZW5zaW9uTnVtYmVyc09mVHlwZRIlCg1saXN0X3NlcnZpY2VzGAcg'
40+
'ASgJSABSDGxpc3RTZXJ2aWNlc0IRCg9tZXNzYWdlX3JlcXVlc3Q=');
41+
42+
@$core.Deprecated('Use extensionRequestDescriptor instead')
43+
const ExtensionRequest$json = {
44+
'1': 'ExtensionRequest',
45+
'2': [
46+
{'1': 'containing_type', '3': 1, '4': 1, '5': 9, '10': 'containingType'},
47+
{'1': 'extension_number', '3': 2, '4': 1, '5': 5, '10': 'extensionNumber'},
48+
],
49+
};
50+
51+
/// Descriptor for `ExtensionRequest`. Decode as a `google.protobuf.DescriptorProto`.
52+
final $typed_data.Uint8List extensionRequestDescriptor = $convert.base64Decode(
53+
'ChBFeHRlbnNpb25SZXF1ZXN0EicKD2NvbnRhaW5pbmdfdHlwZRgBIAEoCVIOY29udGFpbmluZ1'
54+
'R5cGUSKQoQZXh0ZW5zaW9uX251bWJlchgCIAEoBVIPZXh0ZW5zaW9uTnVtYmVy');
55+
56+
@$core.Deprecated('Use serverReflectionResponseDescriptor instead')
57+
const ServerReflectionResponse$json = {
58+
'1': 'ServerReflectionResponse',
59+
'2': [
60+
{'1': 'valid_host', '3': 1, '4': 1, '5': 9, '10': 'validHost'},
61+
{'1': 'original_request', '3': 2, '4': 1, '5': 11, '6': '.grpc.reflection.v1.ServerReflectionRequest', '10': 'originalRequest'},
62+
{'1': 'file_descriptor_response', '3': 4, '4': 1, '5': 11, '6': '.grpc.reflection.v1.FileDescriptorResponse', '9': 0, '10': 'fileDescriptorResponse'},
63+
{'1': 'all_extension_numbers_response', '3': 5, '4': 1, '5': 11, '6': '.grpc.reflection.v1.ExtensionNumberResponse', '9': 0, '10': 'allExtensionNumbersResponse'},
64+
{'1': 'list_services_response', '3': 6, '4': 1, '5': 11, '6': '.grpc.reflection.v1.ListServiceResponse', '9': 0, '10': 'listServicesResponse'},
65+
{'1': 'error_response', '3': 7, '4': 1, '5': 11, '6': '.grpc.reflection.v1.ErrorResponse', '9': 0, '10': 'errorResponse'},
66+
],
67+
'8': [
68+
{'1': 'message_response'},
69+
],
70+
};
71+
72+
/// Descriptor for `ServerReflectionResponse`. Decode as a `google.protobuf.DescriptorProto`.
73+
final $typed_data.Uint8List serverReflectionResponseDescriptor = $convert.base64Decode(
74+
'ChhTZXJ2ZXJSZWZsZWN0aW9uUmVzcG9uc2USHQoKdmFsaWRfaG9zdBgBIAEoCVIJdmFsaWRIb3'
75+
'N0ElYKEG9yaWdpbmFsX3JlcXVlc3QYAiABKAsyKy5ncnBjLnJlZmxlY3Rpb24udjEuU2VydmVy'
76+
'UmVmbGVjdGlvblJlcXVlc3RSD29yaWdpbmFsUmVxdWVzdBJmChhmaWxlX2Rlc2NyaXB0b3Jfcm'
77+
'VzcG9uc2UYBCABKAsyKi5ncnBjLnJlZmxlY3Rpb24udjEuRmlsZURlc2NyaXB0b3JSZXNwb25z'
78+
'ZUgAUhZmaWxlRGVzY3JpcHRvclJlc3BvbnNlEnIKHmFsbF9leHRlbnNpb25fbnVtYmVyc19yZX'
79+
'Nwb25zZRgFIAEoCzIrLmdycGMucmVmbGVjdGlvbi52MS5FeHRlbnNpb25OdW1iZXJSZXNwb25z'
80+
'ZUgAUhthbGxFeHRlbnNpb25OdW1iZXJzUmVzcG9uc2USXwoWbGlzdF9zZXJ2aWNlc19yZXNwb2'
81+
'5zZRgGIAEoCzInLmdycGMucmVmbGVjdGlvbi52MS5MaXN0U2VydmljZVJlc3BvbnNlSABSFGxp'
82+
'c3RTZXJ2aWNlc1Jlc3BvbnNlEkoKDmVycm9yX3Jlc3BvbnNlGAcgASgLMiEuZ3JwYy5yZWZsZW'
83+
'N0aW9uLnYxLkVycm9yUmVzcG9uc2VIAFINZXJyb3JSZXNwb25zZUISChBtZXNzYWdlX3Jlc3Bv'
84+
'bnNl');
85+
86+
@$core.Deprecated('Use fileDescriptorResponseDescriptor instead')
87+
const FileDescriptorResponse$json = {
88+
'1': 'FileDescriptorResponse',
89+
'2': [
90+
{'1': 'file_descriptor_proto', '3': 1, '4': 3, '5': 12, '10': 'fileDescriptorProto'},
91+
],
92+
};
93+
94+
/// Descriptor for `FileDescriptorResponse`. Decode as a `google.protobuf.DescriptorProto`.
95+
final $typed_data.Uint8List fileDescriptorResponseDescriptor = $convert.base64Decode(
96+
'ChZGaWxlRGVzY3JpcHRvclJlc3BvbnNlEjIKFWZpbGVfZGVzY3JpcHRvcl9wcm90bxgBIAMoDF'
97+
'ITZmlsZURlc2NyaXB0b3JQcm90bw==');
98+
99+
@$core.Deprecated('Use extensionNumberResponseDescriptor instead')
100+
const ExtensionNumberResponse$json = {
101+
'1': 'ExtensionNumberResponse',
102+
'2': [
103+
{'1': 'base_type_name', '3': 1, '4': 1, '5': 9, '10': 'baseTypeName'},
104+
{'1': 'extension_number', '3': 2, '4': 3, '5': 5, '10': 'extensionNumber'},
105+
],
106+
};
107+
108+
/// Descriptor for `ExtensionNumberResponse`. Decode as a `google.protobuf.DescriptorProto`.
109+
final $typed_data.Uint8List extensionNumberResponseDescriptor = $convert.base64Decode(
110+
'ChdFeHRlbnNpb25OdW1iZXJSZXNwb25zZRIkCg5iYXNlX3R5cGVfbmFtZRgBIAEoCVIMYmFzZV'
111+
'R5cGVOYW1lEikKEGV4dGVuc2lvbl9udW1iZXIYAiADKAVSD2V4dGVuc2lvbk51bWJlcg==');
112+
113+
@$core.Deprecated('Use listServiceResponseDescriptor instead')
114+
const ListServiceResponse$json = {
115+
'1': 'ListServiceResponse',
116+
'2': [
117+
{'1': 'service', '3': 1, '4': 3, '5': 11, '6': '.grpc.reflection.v1.ServiceResponse', '10': 'service'},
118+
],
119+
};
120+
121+
/// Descriptor for `ListServiceResponse`. Decode as a `google.protobuf.DescriptorProto`.
122+
final $typed_data.Uint8List listServiceResponseDescriptor = $convert.base64Decode(
123+
'ChNMaXN0U2VydmljZVJlc3BvbnNlEj0KB3NlcnZpY2UYASADKAsyIy5ncnBjLnJlZmxlY3Rpb2'
124+
'4udjEuU2VydmljZVJlc3BvbnNlUgdzZXJ2aWNl');
125+
126+
@$core.Deprecated('Use serviceResponseDescriptor instead')
127+
const ServiceResponse$json = {
128+
'1': 'ServiceResponse',
129+
'2': [
130+
{'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
131+
],
132+
};
133+
134+
/// Descriptor for `ServiceResponse`. Decode as a `google.protobuf.DescriptorProto`.
135+
final $typed_data.Uint8List serviceResponseDescriptor = $convert.base64Decode(
136+
'Cg9TZXJ2aWNlUmVzcG9uc2USEgoEbmFtZRgBIAEoCVIEbmFtZQ==');
137+
138+
@$core.Deprecated('Use errorResponseDescriptor instead')
139+
const ErrorResponse$json = {
140+
'1': 'ErrorResponse',
141+
'2': [
142+
{'1': 'error_code', '3': 1, '4': 1, '5': 5, '10': 'errorCode'},
143+
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
144+
],
145+
};
146+
147+
/// Descriptor for `ErrorResponse`. Decode as a `google.protobuf.DescriptorProto`.
148+
final $typed_data.Uint8List errorResponseDescriptor = $convert.base64Decode(
149+
'Cg1FcnJvclJlc3BvbnNlEh0KCmVycm9yX2NvZGUYASABKAVSCWVycm9yQ29kZRIjCg1lcnJvcl'
150+
'9tZXNzYWdlGAIgASgJUgxlcnJvck1lc3NhZ2U=');
151+

‎lib/src/robot/client.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import 'package:grpc/grpc_connection_interface.dart';
55
import 'package:logger/logger.dart';
66

77
import '../gen/common/v1/common.pb.dart';
8-
import '../gen/robot/v1/robot.pb.dart';
98
import '../gen/google/protobuf/struct.pb.dart';
9+
import '../gen/robot/v1/robot.pb.dart';
1010
import '../gen/robot/v1/robot.pbgrpc.dart' as rpb;
1111
import '../gen/stream/v1/stream.pbgrpc.dart';
1212
import '../media/stream/client.dart';
@@ -141,7 +141,7 @@ class RobotClient {
141141
client._address = url;
142142
client._options = options;
143143
client._channel = await dial(url, options.dialOptions, () => client._sessionsClient.metadata());
144-
client._sessionsClient = SessionsClient(client._channel, options.enableSessions);
144+
client._sessionsClient = SessionsClient(client._channel, options.enableSessions, url);
145145
client._sessionsClient.start();
146146
client._client = rpb.RobotServiceClient(client._channel);
147147
client._streamManager = StreamManager(client._channel as WebRtcClientChannel);
@@ -256,7 +256,7 @@ class RobotClient {
256256
_channel = channel;
257257
_streamManager.channel = _channel as WebRtcClientChannel;
258258
_client = client;
259-
_sessionsClient = SessionsClient(_channel, _options.enableSessions);
259+
_sessionsClient = SessionsClient(_channel, _options.enableSessions, this._address);
260260
await refresh();
261261
_connected = true;
262262
_logger.i('Successfully reconnected to robot');

‎lib/src/robot/sessions_client.dart

+53-16
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ import 'dart:async';
22

33
import 'package:grpc/grpc_connection_interface.dart';
44
import 'package:logger/logger.dart';
5-
import 'package:viam_sdk/protos/robot/robot.dart';
5+
import 'package:protobuf/protobuf.dart';
66

7+
import '../gen/common/v1/common.pb.dart';
8+
import '../gen/google/protobuf/descriptor.pb.dart';
79
import '../gen/google/rpc/code.pbenum.dart';
10+
import '../gen/grpc/reflection/v1/reflection.pbgrpc.dart';
11+
import '../gen/robot/v1/robot.pbgrpc.dart';
812
import '../resource/base.dart';
913

1014
final _logger = Logger();
@@ -13,17 +17,7 @@ final _logger = Logger();
1317
/// and supports stopping actuating components when it's not.
1418
class SessionsClient implements ResourceRPCClient {
1519
static const sessionMetadataKey = 'viam-sid';
16-
static const unallowedMethods = {
17-
'/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo',
18-
'/proto.rpc.webrtc.v1.SignalingService/Call',
19-
'/proto.rpc.webrtc.v1.SignalingService/CallUpdate',
20-
'/proto.rpc.webrtc.v1.SignalingService/OptionalWebRTCConfig',
21-
'/proto.rpc.v1.AuthService/Authenticate',
22-
'/viam.robot.v1.RobotService/ResourceNames',
23-
'/viam.robot.v1.RobotService/ResourceRPCSubtypes',
24-
'/viam.robot.v1.RobotService/StartSession',
25-
'/viam.robot.v1.RobotService/SendSessionHeartbeat',
26-
};
20+
static Map<String, bool> heartbeatMonitoredMethods = {};
2721

2822
@override
2923
ClientChannelBase channel;
@@ -34,9 +28,10 @@ class SessionsClient implements ResourceRPCClient {
3428
String _currentId = '';
3529
final bool _enabled;
3630
bool? _supported;
37-
late Duration _heartbeatInterval;
31+
Duration _heartbeatInterval = Duration(seconds: 1);
32+
final String _host;
3833

39-
SessionsClient(this.channel, this._enabled) {
34+
SessionsClient(this.channel, this._enabled, this._host) {
4035
metadata();
4136
}
4237

@@ -87,6 +82,7 @@ class SessionsClient implements ResourceRPCClient {
8782
_supported = null;
8883
metadata();
8984
_heartbeatTask();
85+
_applyHeartbeatMonitoredMethods();
9086
}
9187

9288
/// Stop the session client and heartbeat tasks
@@ -104,15 +100,15 @@ class SessionsClient implements ResourceRPCClient {
104100

105101
Future<void> _heartbeatTask() async {
106102
if (!_enabled) return;
107-
while (_supported == true) {
103+
while (_supported != false) {
108104
await _heartbeatTick();
109105
await Future.delayed(_heartbeatInterval);
110106
}
111107
}
112108

113109
Future<void> _heartbeatTick() async {
114110
if (!_enabled) return;
115-
if (_supported == false) return;
111+
if (_supported != true) return;
116112

117113
final request = SendSessionHeartbeatRequest()..id = _currentId;
118114

@@ -123,4 +119,45 @@ class SessionsClient implements ResourceRPCClient {
123119
reset();
124120
}
125121
}
122+
123+
Future<void> _applyHeartbeatMonitoredMethods() async {
124+
final reflectClient = ServerReflectionClient(channel);
125+
final request = ServerReflectionRequest(host: _host, listServices: '');
126+
final responseStream = reflectClient.serverReflectionInfo(
127+
Stream.value(request),
128+
options: CallOptions(timeout: Duration(seconds: 10)),
129+
);
130+
final serviceResponse = await responseStream.first;
131+
final fdpRequests = serviceResponse.listServicesResponse.service
132+
.map((service) => ServerReflectionRequest(host: _host, fileContainingSymbol: service.name));
133+
final fdpResponseStream = reflectClient.serverReflectionInfo(
134+
Stream.fromIterable(fdpRequests),
135+
options: CallOptions(timeout: Duration(seconds: 10)),
136+
);
137+
final subscription = fdpResponseStream.listen((fdpResponse) {
138+
for (final fdp in fdpResponse.fileDescriptorResponse.fileDescriptorProto) {
139+
final protoFile = FileDescriptorProto.fromBuffer(fdp);
140+
for (final service in protoFile.service) {
141+
for (final method in service.method) {
142+
final options = method.options;
143+
144+
// Manually parse the extension
145+
final parsedOptions = ExtensionRegistry()..add(Common.safetyHeartbeatMonitored);
146+
final parsedOptionsMessage = options.createEmptyInstance();
147+
parsedOptionsMessage.mergeFromBuffer(options.writeToBuffer(), parsedOptions);
148+
149+
if (parsedOptionsMessage.hasExtension(Common.safetyHeartbeatMonitored)) {
150+
final value = parsedOptionsMessage.getExtension(Common.safetyHeartbeatMonitored);
151+
SessionsClient.heartbeatMonitoredMethods['/${protoFile.package}.${service.name}/${method.name}'] = value;
152+
} else {
153+
SessionsClient.heartbeatMonitoredMethods['/${protoFile.package}.${service.name}/${method.name}'] = false;
154+
}
155+
}
156+
}
157+
}
158+
});
159+
await Future.delayed(Duration(seconds: 9), () {
160+
subscription.cancel();
161+
});
162+
}
126163
}

‎lib/src/rpc/dial.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ class AuthenticatedChannel extends ViamGrpcOrGrpcWebChannel {
596596

597597
@override
598598
ClientCall<Q, R> createCall<Q, R>(ClientMethod<Q, R> method, Stream<Q> requests, CallOptions options) {
599-
if (!SessionsClient.unallowedMethods.contains(method.path) && _sessionId != null) {
599+
if ((SessionsClient.heartbeatMonitoredMethods[method.path] ?? false) && _sessionId != null) {
600600
options = options.mergedWith(CallOptions(metadata: {SessionsClient.sessionMetadataKey: _sessionId!()}));
601601
}
602602

‎lib/src/rpc/web_rtc/web_rtc_client.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class WebRtcClientChannel extends ClientChannelBase {
2929

3030
@override
3131
ClientCall<Q, R> createCall<Q, R>(ClientMethod<Q, R> method, Stream<Q> requests, CallOptions options) {
32-
if (!SessionsClient.unallowedMethods.contains(method.path)) {
32+
if (SessionsClient.heartbeatMonitoredMethods[method.path] ?? false) {
3333
final sessionMetadata = _sessionId();
3434
if (sessionMetadata.isNotEmpty) {
3535
options = options.mergedWith(CallOptions(metadata: {SessionsClient.sessionMetadataKey: sessionMetadata}));

0 commit comments

Comments
 (0)
Please sign in to comment.