Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSDK-7769, RSDK-7770 Add AppRobotClient and LogOutput dial option #233

Merged
merged 7 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions lib/src/app/robot.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'dart:async';

import 'package:logger/logger.dart';
import 'package:viam_sdk/src/gen/google/protobuf/timestamp.pb.dart';

import '../gen/app/v1/robot.pbgrpc.dart';
import '../gen/common/v1/common.pb.dart';

const flutterSdkLoggerName = 'flutter-sdk';

/// gRPC client for connecting to app's RobotService.
///
/// All calls must be authenticated.
class AppRobotClient {
final RobotServiceClient _client;

AppRobotClient(this._client);

/// Log the OutputEvent to app with the given partId.
Future<void> log(String partId, OutputEvent event) async {
late String level;
switch (event.level) {
case Level.debug:
level = 'debug';
case Level.warning:
level = 'warning';
case Level.error:
level = 'error';
default:
// Assume info level if none of the above.
level = 'info';
}

// Assume log was just output (OutputEvent has no timestamp field).
final Timestamp protoTs = Timestamp.fromDateTime(DateTime.now());

// Join lines with '\n' and suffix with '\n'.
final String message = '${event.lines.join('\n')}\n';

final LogEntry entry =
LogEntry(host: '$partId-$flutterSdkLoggerName', level: level, time: protoTs, loggerName: flutterSdkLoggerName, message: message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we allow the host/loggerName to be user defined?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah probably a good idea 👍🏻 .

final request = LogRequest(id: partId, logs: [entry]);
await _client.log(request);
}
}
15 changes: 13 additions & 2 deletions lib/src/rpc/dial.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ import '../utils.dart';
import 'grpc/grpc_or_grpcweb_channel.dart';
import 'web_rtc/web_rtc_client.dart';

final _logger = Logger(printer: PrettyPrinter(printTime: true));
Logger newDialLogger(LogOutput? output) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make this private as well please?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

// Use a SimplePrinter, as flutter dial logs from the RC app are sent to app.viam.com,
// and pretty-printed logs are overly formatted.
return Logger(output: output, printer: SimplePrinter(colors: false));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're curious what the logs look like on app.

For connection success (latest->oldest):

6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: chose host local candidate with IP 127.0.0.1:59852 @ 2024-06-17 12:10:05.493
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: chose host remote candidate with IP 127.0.0.1:49963 @ 2024-06-17 12:10:05.493
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: 10 call updates to the signaling server were made
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: max call update took 0:00:00.097045
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: average call update took 0:00:00.090000
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: all ICE candidates gathered in 0:00:00.661795
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 7 took 0:00:00.097045
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 9 took 0:00:00.091183
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 1 took 0:00:00.092558
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 6 took 0:00:00.091111
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 8 took 0:00:00.089822
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 0 took 0:00:00.091249
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 5 took 0:00:00.089269
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 2 took 0:00:00.088691
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 3 took 0:00:00.089009
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: call update 4 took 0:00:00.086586
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: adding remote ICE candidate of candidate:2878742611 1 udp 2130706431 127.0.0.1 49963 typ host
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: adding remote ICE candidate of candidate:1352458247 1 udp 1694498815 71.167.222.76 62792 typ srflx raddr 0.0.0.0 rport 62792
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: WebRTC connection made in 0:00:00.522645
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 9 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:2459122801 1 tcp 1518157055 ::1 61490 typ host tcptype passive generation 0 ufrag wNPI network-id 4 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:617964620 1 tcp 1518083839 127.0.0.1 61488 typ host tcptype passive generation 0 ufrag wNPI network-id 3 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 4 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 6 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 8 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:2901833412 1 tcp 1518285567 fd8f:df19:cb63:e74b:d3:4a65:9d96:f99b 61489 typ host tcptype passive generation 0 ufrag wNPI network-id 2 network-cost 10 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 5 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:103336020 1 tcp 1518214911 10.1.9.95 61487 typ host tcptype passive generation 0 ufrag wNPI network-id 1 network-cost 10 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:3613791393 1 udp 41820159 34.203.251.37 53375 typ relay raddr 71.167.222.76 rport 62973 generation 0 ufrag wNPI network-id 1 network-cost 10 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 7 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 2 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:1511687892 1 udp 2122063615 127.0.0.1 59852 typ host generation 0 ufrag wNPI network-id 3 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 3 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 1 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:3965509353 1 udp 2122136831 ::1 52084 typ host generation 0 ufrag wNPI network-id 4 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:3526988892 1 udp 2122265343 fd8f:df19:cb63:e74b:d3:4a65:9d96:f99b 54348 typ host generation 0 ufrag wNPI network-id 2 network-cost 10 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:2492806202 1 udp 1685987071 71.167.222.76 62973 typ srflx raddr 10.1.9.95 rport 62973 generation 0 ufrag wNPI network-id 1 network-cost 10 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: candidate candidate:2028415692 1 udp 2122194687 10.1.9.95 62973 typ host generation 0 ufrag wNPI network-id 1 network-cost 10 gathered
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: making call update 0 to the signaling server
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: adding remote ICE candidate of candidate:2323467334 1 udp 2130706431 10.1.9.95 50491 typ host
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: created peer connection and channels in 0:00:00.009970
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: connected to signaling in 0:00:00.129933
6/17/2024, 12:10:05 PM debug flutter-sdk [D] STATS: authentication took 0:00:00.129197
6/17/2024, 12:10:05 PM debug flutter-sdk [D] Authenticated to address: app.viam.com:443
6/17/2024, 12:10:04 PM debug flutter-sdk [D] STATS: dial function took 0:00:00.002614
6/17/2024, 12:10:04 PM debug flutter-sdk [D] Authenticating to address: app.viam.com:443, for entity: foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:10:04 PM debug flutter-sdk [D] Connecting to signaling server: app.viam.com
6/17/2024, 12:10:04 PM debug flutter-sdk [D] Auth entity is empty, setting to host: foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:10:04 PM debug flutter-sdk [D] Dialing direct GRPC to app.viam.com
6/17/2024, 12:10:04 PM debug flutter-sdk [D] Dialing WebRTC to foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:10:04 PM info flutter-sdk [I] Connecting to address foo-main.h9kzybd9wn.viam.cloud

For connection failure (latest->oldest):

6/17/2024, 12:09:01 PM error flutter-sdk [E] Could not authenticate to address: foo-main.h9kzybd9wn.viam.cloud:443 ERROR: gRPC Error (code: 14, codeName: UNAVAILABLE, message: Error connecting: SocketException: Connection refused (OS Error: Connection refused, errno = 61), address = foo-main.h9kzybd9wn.viam.cloud, port = 61303, details: null, rawResponse: null, trailers: {})
6/17/2024, 12:09:01 PM debug flutter-sdk [D] Authenticating to address: foo-main.h9kzybd9wn.viam.cloud:443, for entity: foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:09:01 PM debug flutter-sdk [D] Dialing direct GRPC to foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:09:01 PM info flutter-sdk [I] Could not connect via WebRTC, attempting direct gRPC connection ERROR: gRPC Error (code: 4, codeName: DEADLINE_EXCEEDED, message: context deadline exceeded, details: [], rawResponse: null, trailers: {})
6/17/2024, 12:08:51 PM debug flutter-sdk [D] STATS: created peer connection and channels in 0:00:00.009587
6/17/2024, 12:08:51 PM debug flutter-sdk [D] STATS: authentication took 0:00:00.130151
6/17/2024, 12:08:51 PM debug flutter-sdk [D] STATS: connected to signaling in 0:00:00.131668
6/17/2024, 12:08:51 PM debug flutter-sdk [D] Authenticated to address: app.viam.com:443
6/17/2024, 12:08:51 PM debug flutter-sdk [D] STATS: dial function took 0:00:00.013401
6/17/2024, 12:08:51 PM debug flutter-sdk [D] Authenticating to address: app.viam.com:443, for entity: foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:08:51 PM debug flutter-sdk [D] Dialing direct GRPC to app.viam.com
6/17/2024, 12:08:51 PM debug flutter-sdk [D] Auth entity is empty, setting to host: foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:08:51 PM debug flutter-sdk [D] Dialing WebRTC to foo-main.h9kzybd9wn.viam.cloud
6/17/2024, 12:08:51 PM debug flutter-sdk [D] Connecting to signaling server: app.viam.com
6/17/2024, 12:08:51 PM info flutter-sdk [I] Connecting to address foo-main.h9kzybd9wn.viam.cloud

}

var _logger = newDialLogger(null);

/// Describes the behavior for connecting to a robot
class DialOptions {
Expand Down Expand Up @@ -56,6 +62,9 @@ class DialOptions {

/// Timeout is the timeout for dial.
Duration timeout = Duration(seconds: 10);

/// If specified, a custom log output for dial logs.
LogOutput? logOutput;
}

/// The credentials used for connecting to the robot
Expand Down Expand Up @@ -113,9 +122,11 @@ class DialWebRtcOptions {

/// Connect to a robot at the provided address with the given options
Future<ClientChannelBase> dial(String address, DialOptions? options, String Function() sessionCallback) async {
final opts = options ?? DialOptions();
_logger = newDialLogger(opts.logOutput);

final dialSW = Stopwatch()..start();
_logger.i('Connecting to address $address');
final opts = options ?? DialOptions();

if (opts.attemptMdns) {
final mdnsSW = Stopwatch()..start();
Expand Down
4 changes: 4 additions & 0 deletions lib/src/viam_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import './app/app.dart';
import './app/billing.dart';
import './app/data.dart';
import './app/provisioning.dart';
import './app/robot.dart';
import './gen/app/v1/app.pbgrpc.dart';
import './robot/client.dart';
import './viam_sdk_impl.dart';
Expand All @@ -20,6 +21,9 @@ abstract class Viam {
/// A client to communicate with Viam's app service
AppClient get appClient;

/// A client to communicate with Viam's robot service
AppRobotClient get appRobotClient;

/// A client to communicate with Viam's billing services
BillingClient get billingClient;

Expand Down
10 changes: 10 additions & 0 deletions lib/src/viam_sdk_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,28 @@ import 'package:viam_sdk/protos/app/dataset.dart';
import '../protos/app/app.dart';
import '../protos/app/billing.dart';
import '../protos/app/data.dart';
import '../protos/app/robot.dart';
import '../protos/provisioning/provisioning.dart';
import './app/app.dart';
import './app/billing.dart';
import './app/data.dart';
import './app/provisioning.dart';
import './app/robot.dart';
import './robot/client.dart';
import './rpc/dial.dart';
import './viam_sdk.dart';

class ViamImpl implements Viam {
final ClientChannelBase _clientChannelBase;
late AppClient _appClient;
late AppRobotClient _appRobotClient;
late BillingClient _billingClient;
late DataClient _dataClient;
late ProvisioningClient _provisioningClient;

ViamImpl._withChannel(this._clientChannelBase) {
_appClient = AppClient(AppServiceClient(_clientChannelBase));
_appRobotClient = AppRobotClient(RobotServiceClient(_clientChannelBase));
_billingClient = BillingClient(BillingServiceClient(_clientChannelBase));
_dataClient = DataClient(
DataServiceClient(_clientChannelBase), DataSyncServiceClient(_clientChannelBase), DatasetServiceClient(_clientChannelBase));
Expand All @@ -33,6 +37,7 @@ class ViamImpl implements Viam {
ViamImpl.withAccessToken(String accessToken, {String serviceHost = 'app.viam.com', int servicePort = 443})
: _clientChannelBase = AuthenticatedChannel(serviceHost, servicePort, accessToken, servicePort == 443 ? false : true) {
_appClient = AppClient(AppServiceClient(_clientChannelBase));
_appRobotClient = AppRobotClient(RobotServiceClient(_clientChannelBase));
_billingClient = BillingClient(BillingServiceClient(_clientChannelBase));
_dataClient = DataClient(
DataServiceClient(_clientChannelBase), DataSyncServiceClient(_clientChannelBase), DatasetServiceClient(_clientChannelBase));
Expand Down Expand Up @@ -63,6 +68,11 @@ class ViamImpl implements Viam {
return _appClient;
}

@override
AppRobotClient get appRobotClient {
return _appRobotClient;
}

@override
BillingClient get billingClient {
return _billingClient;
Expand Down
1 change: 1 addition & 0 deletions lib/viam_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ library viam_sdk;
export 'src/app/data.dart' hide DataClient;
export 'src/app/permissions.dart';
export 'src/app/provisioning.dart';
export 'src/app/robot.dart';

/// Components
export 'src/components/arm/arm.dart';
Expand Down