Skip to content

Commit c98dad4

Browse files
authored
Documentation (#98)
1 parent bb69e88 commit c98dad4

14 files changed

+119
-20
lines changed

lib/src/app/app.dart

+12
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,71 @@ import 'dart:async';
22

33
import '../gen/app/v1/app.pbgrpc.dart';
44

5+
/// gRPC client for connecting to Viam's App Service
6+
///
7+
/// All calls must be authenticated.
58
class AppClient {
69
final AppServiceClient _client;
710

811
AppClient(this._client);
912

13+
/// List all the [Organization] the currently authenticated user has access to
1014
Future<List<Organization>> listOrganizations() async {
1115
final listOrganizationsRequest = ListOrganizationsRequest();
1216
final ListOrganizationsResponse response = await _client.listOrganizations(listOrganizationsRequest);
1317
return response.organizations;
1418
}
1519

20+
/// Get a specific [Organization] by ID
1621
Future<Organization> getOrganization(String organizationId) async {
1722
final getOrganizationRequest = GetOrganizationRequest()..organizationId = organizationId;
1823
final GetOrganizationResponse response = await _client.getOrganization(getOrganizationRequest);
1924
return response.organization;
2025
}
2126

27+
/// List the [Location] of a specific [Organization] that the currently authenticated user has access to
2228
Future<List<Location>> listLocations(Organization organization) async {
2329
final listLocationsRequest = ListLocationsRequest()..organizationId = organization.id;
2430
final ListLocationsResponse response = await _client.listLocations(listLocationsRequest);
2531
return response.locations;
2632
}
2733

34+
/// Get a specific [Location] by ID
2835
Future<Location> getLocation(String locationId) async {
2936
final getLocationRequest = GetLocationRequest()..locationId = locationId;
3037
final GetLocationResponse response = await _client.getLocation(getLocationRequest);
3138
return response.location;
3239
}
3340

41+
/// List the [Robot] of a specific [Location] that the currently authenticated user has access to
3442
Future<List<Robot>> listRobots(Location location) async {
3543
final listRobotsRequest = ListRobotsRequest()..locationId = location.id;
3644
final ListRobotsResponse response = await _client.listRobots(listRobotsRequest);
3745
return response.robots;
3846
}
3947

48+
/// Get a specific [Robot] by ID
4049
Future<Robot> getRobot(String robotId) async {
4150
final getRobotRequest = GetRobotRequest()..id = robotId;
4251
final GetRobotResponse response = await _client.getRobot(getRobotRequest);
4352
return response.robot;
4453
}
4554

55+
/// List the [RobotPart] of a specific [Robot] that the currently authenticated user has access to
4656
Future<List<RobotPart>> listRobotParts(Robot robot) async {
4757
final getRobotPartsRequest = GetRobotPartsRequest()..robotId = robot.id;
4858
final response = await _client.getRobotParts(getRobotPartsRequest);
4959
return response.parts;
5060
}
5161

62+
/// Get a specific [RobotPart] by ID
5263
Future<RobotPart> getRobotPart(String partId) async {
5364
final getRobotPartRequest = GetRobotPartRequest()..id = partId;
5465
final response = await _client.getRobotPart(getRobotPartRequest);
5566
return response.part;
5667
}
5768

69+
/// Get a stream of [LogEntry] for a specific [RobotPart]. Logs are sorted by descending time (newest first)
5870
Stream<List<LogEntry>> tailLogs(RobotPart part, {bool errorsOnly = false}) {
5971
final request = TailRobotPartLogsRequest()
6072
..id = part.id

lib/src/app/data.dart

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import 'package:viam_sdk/src/gen/google/protobuf/timestamp.pb.dart';
66
import '../gen/app/data/v1/data.pbgrpc.dart';
77

88
/// gRPC client for the [DataClient]. Used for retrieving stored data from app.viam.com.
9+
///
10+
/// All calls must be authenticated.
911
class DataClient {
1012
final DataServiceClient _client;
1113

@@ -106,11 +108,13 @@ class DataClient {
106108
}
107109

108110
extension FilterUtils on Filter {
111+
/// Return a [Filter] with a [CaptureInterval] created by the provided start and end [DateTime] objects
109112
Filter withDateTimeCaptureInterval({DateTime? start, DateTime? end}) {
110113
setDateTimeCaptureInterval(start: start, end: end);
111114
return this;
112115
}
113116

117+
/// Update the current [Filter] with a [CaptureInterval] created by the provided start and end [DateTime] objects
114118
void setDateTimeCaptureInterval({DateTime? start, DateTime? end}) {
115119
final interval = CaptureInterval();
116120
if (start != null) {

lib/src/errors.dart

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// Error thrown with connection is lost
12
class ConnectionLostError {
23
final String? message;
34

lib/src/media/image.dart

+15-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:typed_data';
33

44
import 'package:image/image.dart' as img;
55

6+
/// Mime types supported by Viam
67
class MimeType {
78
final String _type;
89
final String _name;
@@ -24,16 +25,27 @@ class MimeType {
2425

2526
const MimeType._(this._type, this._name);
2627

28+
/// Viam's custom RGBA encoding (image/vnd.viam.rgba)
2729
static MimeType get viamRgba => const MimeType._('viamRgba', 'image/vnd.viam.rgba');
30+
31+
/// JPEG encoding (image/jpeg)
2832
static MimeType get jpeg => const MimeType._('jpeg', 'image/jpeg');
33+
34+
/// PNG encoding (image/png)
2935
static MimeType get png => const MimeType._('png', 'image/png');
36+
37+
/// PointCloud Data encoding (pointcloud/pcd)
3038
static MimeType get pcd => const MimeType._('pcd', 'pointcloud/pcd');
3139

32-
/// An unsupported MimeType takes in the String representation of the mimetype that is not supported.
40+
/// An unsupported MimeType.
41+
/// Takes in the String representation of the mimetype that is not supported.
3342
const MimeType.unsupported(this._name) : _type = 'unsupported';
3443

44+
/// Create a [MimeType] from its string representation.
45+
/// Returns [MimeType.unsupported] if the provided string is not supported
3546
static MimeType fromString(String mimeType) => _map[mimeType] ?? MimeType.unsupported(mimeType);
3647

48+
/// Whether the provided String representation of a [MimeType] is supported
3749
static bool isSupported(String mimeType) {
3850
return _map.containsKey(mimeType);
3951
}
@@ -46,6 +58,7 @@ class MimeType {
4658
@override
4759
int get hashCode => Object.hash(_type, _name);
4860

61+
/// Decode the bytes into an [img.Image] using the appropriate decoder
4962
img.Image? decode(List<int> bytes) {
5063
img.Decoder? decoder;
5164
switch (_type) {
@@ -72,6 +85,7 @@ class MimeType {
7285
}
7386
}
7487

88+
/// A custom image type that contains the [MimeTYpe], raw image data, and lazily loads and caches an [img.Image].
7589
class ViamImage {
7690
/// The mimetype of the image
7791
final MimeType mimeType;

lib/src/media/stream/client.dart

+7
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class StreamManager {
5656
};
5757
}
5858

59+
/// Add a stream to internal state
5960
void _addStream(MediaStream stream) {
6061
_streams[stream.id] = stream;
6162
if (_clients.containsKey(stream.id)) {
@@ -84,6 +85,7 @@ class StreamManager {
8485
return client;
8586
}
8687

88+
/// Request that a stream get added to the WebRTC channel
8789
Future<void> _add(String name) async {
8890
final sanitizedName = _getValidSDPTrackName(name);
8991
await _client.addStream(AddStreamRequest()..name = sanitizedName);
@@ -113,6 +115,9 @@ class StreamManager {
113115
}
114116
}
115117

118+
/// A client to manage a camera's WebRTC stream.
119+
///
120+
/// Use the [getStream] method to obtain a stream of [MediaStream] that can be used to display WebRTC video.
116121
class StreamClient {
117122
final String name;
118123
final Future<void> Function(String name) _close;
@@ -131,6 +136,7 @@ class StreamClient {
131136
});
132137
}
133138

139+
/// Return a stream of [MediaStream], which can be used to display WebRTC video.
134140
Stream<MediaStream> getStream() {
135141
if (_stream != null) {
136142
Future.delayed(const Duration(milliseconds: 100), () {
@@ -140,6 +146,7 @@ class StreamClient {
140146
return _streamController.stream;
141147
}
142148

149+
/// Close the stream connection and release resources.
143150
Future<void> closeStream() async {
144151
await _streamController.close();
145152
await _internalStreamController.close();

lib/src/resource/base.dart

+18-1
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,35 @@ import 'package:grpc/grpc_connection_interface.dart';
33

44
import '../gen/common/v1/common.pb.dart';
55

6+
/// The standard namespace for Viam resources (rdk)
67
const String resourceNamespaceRDK = 'rdk';
8+
9+
/// The standard type for component resources (component)
710
const String resourceTypeComponent = 'component';
11+
12+
/// The standard type for service resources (service)
813
const String resourceTypeService = 'service';
914

15+
/// [Subtype] defines a triplet of strings that correspond to a resource's specific API definition.
1016
class Subtype {
11-
final String namespace, resourceType, resourceSubtype;
17+
/// The namespace of the subtype
18+
final String namespace;
19+
20+
/// The resource type (e.g. component, service)
21+
final String resourceType;
22+
23+
/// The resource subtype (e.g. arm, sensor, camera)
24+
final String resourceSubtype;
1225

1326
const Subtype(this.namespace, this.resourceType, this.resourceSubtype);
1427

28+
/// Create a new [Subtype] from a [ResourceName]
1529
Subtype.fromResourceName(ResourceName name)
1630
: namespace = name.namespace,
1731
resourceType = name.type,
1832
resourceSubtype = name.subtype;
1933

34+
/// Get a [ResourceName] from this [Subtype] and a provided [name]
2035
ResourceName getResourceName(String name) {
2136
return ResourceName()
2237
..namespace = namespace
@@ -36,6 +51,7 @@ class Subtype {
3651
namespace == other.namespace && resourceType == other.resourceType && resourceSubtype == other.resourceSubtype;
3752
}
3853

54+
/// Abstract class that defines the base functionality for all [Resource] types
3955
abstract class Resource {
4056
abstract String name;
4157

@@ -44,6 +60,7 @@ abstract class Resource {
4460
}
4561
}
4662

63+
/// Abstract class that defines the base functionality for all RPC clients for resources
4764
abstract class ResourceRPCClient<T extends Client> {
4865
abstract ClientChannelBase channel;
4966

lib/src/resource/manager.dart

+14-5
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,35 @@ import 'package:viam_sdk/src/gen/common/v1/common.pb.dart';
22

33
import 'base.dart';
44

5+
/// [ResourceManager] manages the state of all currently available resources of a robot
56
class ResourceManager {
7+
/// The available resources
68
Map<ResourceName, Resource> resources = {};
79
final Map<String, List<ResourceName>> _shortToLongName = {};
810

11+
/// Register a new [Resource] with the manager.
912
void register(ResourceName name, Resource resource) {
1013
if (resources.containsKey(name)) {
1114
throw Exception('Duplicate registration of resource in manager');
1215
}
1316
final shortName = name.name.split(':').last;
14-
if (!(_shortToLongName[shortName]?.contains(name) ?? true)) {
15-
final names = _shortToLongName[shortName] ?? [];
16-
names.add(name);
17-
_shortToLongName[shortName] = names;
18-
}
17+
final names = _shortToLongName[shortName] ?? [];
18+
names.add(name);
19+
_shortToLongName[shortName] = names;
1920
resources[name] = resource;
2021
}
2122

23+
/// Get a resource with the given [ResourceName]
2224
T getResource<T>(ResourceName name) {
2325
final resource = resources[name];
2426
if (resource == null) throw Exception('Resource not found in manager');
2527
return resource as T;
2628
}
29+
30+
/// Get a resource by its name only
31+
T getResourceByName<T>(String name) {
32+
final names = _shortToLongName[name] ?? [];
33+
if (names.isEmpty) throw Exception('Resource not found in manager');
34+
return getResource(names.first);
35+
}
2736
}

lib/src/resource/registry.dart

+19
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,29 @@ import '../components/servo/client.dart';
2020
import '../components/servo/servo.dart';
2121
import '../resource/base.dart';
2222

23+
/// An object representing a resource to be registered.
24+
///
25+
/// This object is generic over [Resource], and it includes various required functionality for the resource (e.g. creating an RPC client)
26+
/// If creating a custom [Resource], you must register the resource using [ResourceRegistration].
2327
class ResourceRegistration<T extends Resource> {
28+
/// The [Subtype] of the resource
2429
Subtype subtype;
30+
31+
/// A method to create a [ResourceRPCClient]
2532
Resource Function(String name, ClientChannelBase channel) rpcClientCreator;
2633

2734
ResourceRegistration(this.subtype, this.rpcClientCreator);
2835
}
2936

37+
/// The global registry of robot resources.
38+
///
39+
/// **NB** The [Registry] should almost never be used directly.
40+
///
41+
/// The [Registry] keeps track of the various [Subtype] that are available on robots using this SDK. All Viam-provided resources are
42+
/// pre-registered (e.g. [Arm], [Motor], [MovementSensor]).
43+
///
44+
/// If you create a new resource [Subtype] that is not an extension of any existing resources, you must register the resource using
45+
/// [registerSubtype]
3046
class Registry {
3147
static final Registry instance = Registry._();
3248
Registry._() {
@@ -42,15 +58,18 @@ class Registry {
4258
registerSubtype(ResourceRegistration(Servo.subtype, (name, channel) => ServoClient(name, channel)));
4359
}
4460

61+
/// The [Subtype] available in the SDK
4562
final Map<Subtype, ResourceRegistration> subtypes = {};
4663

64+
/// Register a new resource with the SDK
4765
void registerSubtype(ResourceRegistration registration) {
4866
if (subtypes.containsKey(registration.subtype)) {
4967
throw Exception('Duplicate registration of subtype in registry');
5068
}
5169
subtypes[registration.subtype] = registration;
5270
}
5371

72+
/// Retrieve a [Subtype]'s registration information
5473
ResourceRegistration lookupSubtype(Subtype subtype) {
5574
if (!subtypes.containsKey(subtype)) {
5675
throw Exception('Subtype not registered in registry');

lib/src/robot/client.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class RobotClient {
197197
_sessionsClient.stop();
198198
await _channel.shutdown();
199199
} catch (e) {
200-
_logger.w('Did not cleanly close RobotClient connection', e);
200+
_logger.w('Did not cleanly close RobotClient connection', error: e);
201201
}
202202
}
203203

lib/src/robot/sessions_client.dart

+6-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class SessionsClient implements ResourceRPCClient {
3939
metadata();
4040
}
4141

42+
/// Retrieve metadata associated with the session (e.g. whether sessions are supported, the current ID of the session)
4243
String metadata() {
4344
if (!_enabled) return '';
4445

@@ -64,26 +65,29 @@ class SessionsClient implements ResourceRPCClient {
6465
return _currentId;
6566
});
6667
} catch (e) {
67-
_logger.e('error starting session: $e');
68+
_logger.e('Error starting session: $e');
6869
reset();
6970
}
7071

7172
return '';
7273
}
7374

75+
/// Reset the current session and re-obtain metadata
7476
void reset() {
75-
_logger.d('resetting session');
77+
_logger.d('Resetting current session with ID: $_currentId');
7678
_currentId = '';
7779
_supported = false;
7880
metadata();
7981
}
8082

83+
/// Stop the session client and heartbeat tasks
8184
void stop() {
8285
_logger.d('Stopping SessionClient');
8386
_currentId = '';
8487
_supported = false;
8588
}
8689

90+
/// Start the session client
8791
void start() {
8892
reset();
8993
}

0 commit comments

Comments
 (0)