Skip to content

Commit

Permalink
add generic component support (#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcvella authored Jan 4, 2024
1 parent 14af995 commit be3d245
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 0 deletions.
30 changes: 30 additions & 0 deletions lib/src/components/generic/client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:grpc/grpc_connection_interface.dart';

import '../../gen/common/v1/common.pb.dart';
import '../../gen/component/generic/v1/generic.pbgrpc.dart';
import '../../resource/base.dart';
import '../../utils.dart';
import 'generic.dart';

/// gRPC client for the [Generic] component.
class GenericClient extends Generic implements ResourceRPCClient {
@override
String name;

@override
ClientChannelBase channel;

@override
GenericServiceClient get client => GenericServiceClient(channel);

GenericClient(this.name, this.channel);

@override
Future<Map<String, dynamic>> doCommand(Map<String, dynamic> command) async {
final request = DoCommandRequest()
..name = name
..command = command.toStruct();
final response = await client.doCommand(request);
return response.result.toMap();
}
}
18 changes: 18 additions & 0 deletions lib/src/components/generic/generic.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import '../../gen/common/v1/common.pb.dart';
import '../../resource/base.dart';
import '../../robot/client.dart';

/// Generic represents a generic component that executes doCommand.
abstract class Generic extends Resource {
static const Subtype subtype = Subtype(resourceNamespaceRDK, resourceTypeComponent, 'generic');

/// Get the [ResourceName] for this [Generic] with the given [name]
static ResourceName getResourceName(String name) {
return Generic.subtype.getResourceName(name);
}

/// Get the [Generic] named [name] from the provided robot.
static Generic fromRobot(RobotClient robot, String name) {
return robot.getResource(Generic.getResourceName(name));
}
}
35 changes: 35 additions & 0 deletions lib/src/components/generic/service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:grpc/grpc.dart';

import '../../gen/common/v1/common.pb.dart';
import '../../gen/component/generic/v1/generic.pbgrpc.dart';
import '../../resource/manager.dart';
import '../../utils.dart';
import 'generic.dart';

/// gRPC Service for a generic [Generic]
class GenericService extends GenericServiceBase {
final ResourceManager _manager;

GenericService(this._manager);

Generic _fromManager(String name) {
try {
return _manager.getResource(Generic.getResourceName(name));
} catch (e) {
throw (GrpcError.notFound(e.toString()));
}
}

@override
Future<DoCommandResponse> doCommand(ServiceCall call, DoCommandRequest request) async {
final generic = _fromManager(request.name);
final result = await generic.doCommand(request.command.toMap());
return DoCommandResponse()..result = result.toStruct();
}

@override
Future<GetGeometriesResponse> getGeometries(ServiceCall call, GetGeometriesRequest request) {
// TODO: implement getGeometries
throw UnimplementedError();
}
}
3 changes: 3 additions & 0 deletions lib/src/resource/registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import '../components/camera/camera.dart';
import '../components/camera/client.dart';
import '../components/gantry/client.dart';
import '../components/gantry/gantry.dart';
import '../components/generic/client.dart';
import '../components/generic/generic.dart';
import '../components/gripper/client.dart';
import '../components/gripper/gripper.dart';
import '../components/motor/client.dart';
Expand Down Expand Up @@ -56,6 +58,7 @@ class Registry {
registerSubtype(ResourceRegistration(Base.subtype, (name, channel) => BaseClient(name, channel)));
registerSubtype(ResourceRegistration(Camera.subtype, (name, channel) => CameraClient(name, channel)));
registerSubtype(ResourceRegistration(Gantry.subtype, (name, channel) => GantryClient(name, channel)));
registerSubtype(ResourceRegistration(Generic.subtype, (name, channel) => GenericClient(name, channel)));
registerSubtype(ResourceRegistration(Gripper.subtype, (name, channel) => GripperClient(name, channel)));
registerSubtype(ResourceRegistration(Motor.subtype, (name, channel) => MotorClient(name, channel)));
registerSubtype(ResourceRegistration(MovementSensor.subtype, (name, channel) => MovementSensorClient(name, channel)));
Expand Down
2 changes: 2 additions & 0 deletions lib/viam_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export 'src/components/camera/camera.dart';
export 'src/components/camera/client.dart';
export 'src/components/gantry/client.dart';
export 'src/components/gantry/gantry.dart';
export 'src/components/generic/client.dart';
export 'src/components/generic/generic.dart';
export 'src/components/gripper/client.dart';
export 'src/components/gripper/gripper.dart';
export 'src/components/motor/client.dart';
Expand Down
81 changes: 81 additions & 0 deletions test/unit_test/components/generic_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:grpc/grpc.dart';
import 'package:viam_sdk/src/components/generic/service.dart';
import 'package:viam_sdk/src/gen/component/generic/v1/generic.pbgrpc.dart';
import 'package:viam_sdk/src/resource/manager.dart';
import 'package:viam_sdk/src/utils.dart';
import 'package:viam_sdk/viam_sdk.dart';

class FakeGeneric extends Generic {
@override
String name;

FakeGeneric(this.name);

@override
Future<Map<String, dynamic>> doCommand(Map<String, dynamic>? command) async {
return {'command': command};
}
}

void main() {
group('FakeGeneric Tests', () {
const String name = 'generic';
late FakeGeneric generic;

setUp(() {
generic = FakeGeneric(name);
});

test('doCommand', () async {
final cmd = {'foo': 'bar'};
final resp = await generic.doCommand(cmd);
expect(resp['command'], cmd);
});
});

group('Generic RPC Tests', () {
const String name = 'generic';
late FakeGeneric generic;
late ClientChannel channel;
late GenericService service;
late Server server;

setUp(() async {
final port = 50000 + (name.hashCode % 10000);
generic = FakeGeneric(name);
final ResourceManager manager = ResourceManager();
manager.register(Generic.getResourceName(name), generic);
service = GenericService(manager);
channel = ClientChannel('localhost', port: port, options: const ChannelOptions(credentials: ChannelCredentials.insecure()));
server = Server.create(services: [service]);
await server.serve(port: port);
});

tearDown(() async {
await channel.shutdown();
await server.shutdown();
});

group('Generic Service Tests', () {
test('doCommand', () async {
final cmd = {'foo': 'bar'};

final client = GenericServiceClient(channel);
final resp = await client.doCommand(DoCommandRequest()
..name = name
..command = cmd.toStruct());
expect(resp.result.toMap()['command'], cmd);
});
});

group('Generic Client Tests', () {
test('doCommand', () async {
final cmd = {'foo': 'bar'};
final client = GenericClient(name, channel);
final resp = await client.doCommand(cmd);
expect(resp['command'], cmd);
});
});
});
}

0 comments on commit be3d245

Please sign in to comment.