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

Refactor and split functionality into more layers #4

Merged
merged 4 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion Protobuf
Submodule Protobuf updated 1 files
+9 −0 drive.proto
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ linter:
cascade_invocations: false # sometimes, multi-line code is more readable

# Temporarily disabled until we are ready to document
# public_member_api_docs: false
public_member_api_docs: false
7 changes: 5 additions & 2 deletions bin/logs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import "package:burt_network/burt_network.dart";
import "package:burt_network/logging.dart";

// 1. Define a new socket on port 8001 that doesn't do anything
class LogsServer extends ServerSocket {
class LogsServer extends RoverServer {
LogsServer() : super(port: 8001, device: Device.SUBSYSTEMS);

@override
void onMessage(_) { }
void onMessage(_) { }

@override
void restart() { }
}

// 2. Create that socket and make a logger that uses it.
Expand Down
31 changes: 11 additions & 20 deletions example/client.dart
Original file line number Diff line number Diff line change
@@ -1,36 +1,27 @@
import "dart:io";
import "package:burt_network/burt_network.dart";
import "package:burt_network/logging.dart";

final destination = SocketInfo(
address: InternetAddress("192.168.47.223"),
// address: InternetAddress("192.168.47.223"),
address: InternetAddress.loopbackIPv4,
port: 8001,
);

final logger = BurtLogger();

class BasicServer extends ProtoSocket {
BasicServer({required super.port, required super.device}) : super(
destination: destination,
heartbeatInterval: const Duration(seconds: 1),
);

@override
void onMessage(WrappedMessage wrapper) => logger.info("Received ${wrapper.name} message: ${wrapper.data}");

@override
void onHeartbeat(Connect heartbeat, SocketInfo source) { }

@override
Future<void> checkHeartbeats() async { }
BasicServer({required super.port, required super.device});

@override
void updateSettings(UpdateSetting setting) { }
@override
void onWrapper(WrappedMessage wrapper, SocketInfo source) =>
logger.info("Received ${wrapper.name} message: ${wrapper.data}");
}

void main() async {
final client = BasicServer(port: 8000, device: Device.DASHBOARD);
await client.init();
client.destination = destination;
final message = ScienceData(methane: 1, co2: 2);
client.sendMessage(message);
while (true) {
client.sendMessage(message);
await Future<void>.delayed(const Duration(seconds: 1));
}
}
7 changes: 5 additions & 2 deletions example/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import "package:burt_network/logging.dart";

final logger = BurtLogger();

class BasicServer extends ServerSocket {
class BasicServer extends ProtoSocket {
BasicServer({required super.port, required super.device});

@override
void onMessage(WrappedMessage wrapper) => logger.info("Received ${wrapper.name} message: ${wrapper.data}");
void onWrapper(WrappedMessage wrapper, SocketInfo source) {
final message = ScienceData.fromBuffer(wrapper.data);
logger.info("Received ${wrapper.name} message: ${message.co2} & ${message.methane}");
}
}

void main() async {
Expand Down
17 changes: 13 additions & 4 deletions lib/burt_network.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,28 @@
///
/// - [UdpSocket] is a raw UDP socket that allows sending and receiving lists of bytes.
/// - [ProtoSocket] is a layer on top of [UdpSocket] that translates bytes to Protobuf messages.
/// - [ServerSocket] is a [ProtoSocket] that can respond to heartbeats and monitors its connection.
/// - [BurtUdpProtocol] extends [ProtoSocket] to handle special messages like heartbeats.
/// - [RoverHeartbeats] extends [BurtUdpProtocol] to respond to the dashboard's heartbeats.
/// - [RoverLogger] extends [BurtUdpProtocol] by buffering logs until the dashboard connects.
/// - [RoverServer] combines [RoverHeartbeats] and [RoverLogger] to handle all on-rover needs.
///
/// On the rover, use [ServerSocket]. On the dashboard, use [ProtoSocket]. To use these classes,
/// On the rover, use [RoverServer]. On the dashboard, extend [BurtUdpProtocol]. To use these classes,
/// extend them and override the suggested methods in their respective documentation. You should
/// not have to use [UdpSocket] directly as it has no Protobuf support.
library;

// For doc comments:
import "src/burt_protocol.dart";
import "src/proto_socket.dart";
import "src/server_socket.dart";
import "src/rover_heartbeats.dart";
import "src/rover_logger.dart";
import "src/rover_server.dart";
import "src/udp_socket.dart";

export "src/proto_socket.dart";
export "src/server_socket.dart";
export "src/rover_server.dart";
export "src/burt_protocol.dart";
export "src/rover_heartbeats.dart";
export "src/socket_info.dart";
export "src/udp_socket.dart";

Expand Down
3 changes: 1 addition & 2 deletions lib/logging.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ class BurtLogger {

/// The device that's sending these logs.
final Device? device;
/// The [ServerSocket] that will be used to send the log to the Dashboard.
final ServerSocket? socket;
final RoverServer? socket;
/// Creates a logger capable of sending network messages over the given socket.
BurtLogger({this.socket}) : device = socket?.device;

Expand Down
49 changes: 49 additions & 0 deletions lib/src/burt_protocol.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import "package:meta/meta.dart";

import "package:burt_network/generated.dart";
import "dart:async";

import "proto_socket.dart";
import "socket_info.dart";

abstract class BurtUdpProtocol extends ProtoSocket {
/// A timer to call [checkHeartbeats] every [heartbeatInterval].
Timer? heartbeatTimer;

/// How often to check for heartbeats.
Duration get heartbeatInterval;

BurtUdpProtocol({
required super.port,
required super.device,
super.quiet,
});

@override
Future<void> init() async {
await super.init();
heartbeatTimer = Timer.periodic(heartbeatInterval, (_) => checkHeartbeats());
}

@override
Future<void> dispose() async {
heartbeatTimer?.cancel();
await super.dispose();
}

@override
@mustCallSuper
void onWrapper(WrappedMessage wrapper, SocketInfo source) {
if (wrapper.name == Connect().messageName) {
final heartbeat = Connect.fromBuffer(wrapper.data);
onHeartbeat(heartbeat, source);
} else {
onMessage(wrapper);
}
}

bool get isConnected;
void checkHeartbeats();
void onHeartbeat(Connect heartbeat, SocketInfo source);
void onMessage(WrappedMessage wrapper);
}
18 changes: 18 additions & 0 deletions lib/src/generated/drive.pb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import 'dart:core' as $core;

import 'package:protobuf/protobuf.dart' as $pb;

import 'drive.pbenum.dart';

export 'drive.pbenum.dart';

class DriveCommand extends $pb.GeneratedMessage {
factory DriveCommand({
$core.double? throttle,
Expand All @@ -25,6 +29,7 @@ class DriveCommand extends $pb.GeneratedMessage {
$core.double? frontTilt,
$core.double? rearSwivel,
$core.double? rearTilt,
DriveDirection? direction,
}) {
final $result = create();
if (throttle != null) {
Expand Down Expand Up @@ -57,6 +62,9 @@ class DriveCommand extends $pb.GeneratedMessage {
if (rearTilt != null) {
$result.rearTilt = rearTilt;
}
if (direction != null) {
$result.direction = direction;
}
return $result;
}
DriveCommand._() : super();
Expand All @@ -74,6 +82,7 @@ class DriveCommand extends $pb.GeneratedMessage {
..a<$core.double>(8, _omitFieldNames ? '' : 'frontTilt', $pb.PbFieldType.OF)
..a<$core.double>(9, _omitFieldNames ? '' : 'rearSwivel', $pb.PbFieldType.OF)
..a<$core.double>(10, _omitFieldNames ? '' : 'rearTilt', $pb.PbFieldType.OF)
..e<DriveDirection>(11, _omitFieldNames ? '' : 'direction', $pb.PbFieldType.OE, defaultOrMaker: DriveDirection.DRIVE_DIRECTION_UNDEFINED, valueOf: DriveDirection.valueOf, enumValues: DriveDirection.values)
..hasRequiredFields = false
;

Expand Down Expand Up @@ -193,6 +202,15 @@ class DriveCommand extends $pb.GeneratedMessage {
$core.bool hasRearTilt() => $_has(9);
@$pb.TagNumber(10)
void clearRearTilt() => clearField(10);

@$pb.TagNumber(11)
DriveDirection get direction => $_getN(10);
@$pb.TagNumber(11)
set direction(DriveDirection v) { setField(11, v); }
@$pb.TagNumber(11)
$core.bool hasDirection() => $_has(10);
@$pb.TagNumber(11)
void clearDirection() => clearField(11);
}

class DriveData extends $pb.GeneratedMessage {
Expand Down
27 changes: 27 additions & 0 deletions lib/src/generated/drive.pbenum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,30 @@
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import

import 'dart:core' as $core;

import 'package:protobuf/protobuf.dart' as $pb;

class DriveDirection extends $pb.ProtobufEnum {
static const DriveDirection DRIVE_DIRECTION_UNDEFINED = DriveDirection._(0, _omitEnumNames ? '' : 'DRIVE_DIRECTION_UNDEFINED');
static const DriveDirection DRIVE_DIRECTION_FORWARD = DriveDirection._(1, _omitEnumNames ? '' : 'DRIVE_DIRECTION_FORWARD');
static const DriveDirection DRIVE_DIRECTION_LEFT = DriveDirection._(2, _omitEnumNames ? '' : 'DRIVE_DIRECTION_LEFT');
static const DriveDirection DRIVE_DIRECTION_RIGHT = DriveDirection._(3, _omitEnumNames ? '' : 'DRIVE_DIRECTION_RIGHT');
static const DriveDirection DRIVE_DIRECTION_STOP = DriveDirection._(4, _omitEnumNames ? '' : 'DRIVE_DIRECTION_STOP');

static const $core.List<DriveDirection> values = <DriveDirection> [
DRIVE_DIRECTION_UNDEFINED,
DRIVE_DIRECTION_FORWARD,
DRIVE_DIRECTION_LEFT,
DRIVE_DIRECTION_RIGHT,
DRIVE_DIRECTION_STOP,
];

static final $core.Map<$core.int, DriveDirection> _byValue = $pb.ProtobufEnum.initByValue(values);
static DriveDirection? valueOf($core.int value) => _byValue[value];

const DriveDirection._($core.int v, $core.String n) : super(v, n);
}


const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');
22 changes: 21 additions & 1 deletion lib/src/generated/drive.pbjson.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ import 'dart:convert' as $convert;
import 'dart:core' as $core;
import 'dart:typed_data' as $typed_data;

@$core.Deprecated('Use driveDirectionDescriptor instead')
const DriveDirection$json = {
'1': 'DriveDirection',
'2': [
{'1': 'DRIVE_DIRECTION_UNDEFINED', '2': 0},
{'1': 'DRIVE_DIRECTION_FORWARD', '2': 1},
{'1': 'DRIVE_DIRECTION_LEFT', '2': 2},
{'1': 'DRIVE_DIRECTION_RIGHT', '2': 3},
{'1': 'DRIVE_DIRECTION_STOP', '2': 4},
],
};

/// Descriptor for `DriveDirection`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List driveDirectionDescriptor = $convert.base64Decode(
'Cg5Ecml2ZURpcmVjdGlvbhIdChlEUklWRV9ESVJFQ1RJT05fVU5ERUZJTkVEEAASGwoXRFJJVk'
'VfRElSRUNUSU9OX0ZPUldBUkQQARIYChREUklWRV9ESVJFQ1RJT05fTEVGVBACEhkKFURSSVZF'
'X0RJUkVDVElPTl9SSUdIVBADEhgKFERSSVZFX0RJUkVDVElPTl9TVE9QEAQ=');

@$core.Deprecated('Use driveCommandDescriptor instead')
const DriveCommand$json = {
'1': 'DriveCommand',
Expand All @@ -27,6 +45,7 @@ const DriveCommand$json = {
{'1': 'front_tilt', '3': 8, '4': 1, '5': 2, '10': 'frontTilt'},
{'1': 'rear_swivel', '3': 9, '4': 1, '5': 2, '10': 'rearSwivel'},
{'1': 'rear_tilt', '3': 10, '4': 1, '5': 2, '10': 'rearTilt'},
{'1': 'direction', '3': 11, '4': 1, '5': 14, '6': '.DriveDirection', '10': 'direction'},
],
};

Expand All @@ -37,7 +56,8 @@ final $typed_data.Uint8List driveCommandDescriptor = $convert.base64Decode(
'EhsKCXNldF9yaWdodBgFIAEoCFIIc2V0UmlnaHQSIQoMc2V0X3Rocm90dGxlGAYgASgIUgtzZX'
'RUaHJvdHRsZRIhCgxmcm9udF9zd2l2ZWwYByABKAJSC2Zyb250U3dpdmVsEh0KCmZyb250X3Rp'
'bHQYCCABKAJSCWZyb250VGlsdBIfCgtyZWFyX3N3aXZlbBgJIAEoAlIKcmVhclN3aXZlbBIbCg'
'lyZWFyX3RpbHQYCiABKAJSCHJlYXJUaWx0');
'lyZWFyX3RpbHQYCiABKAJSCHJlYXJUaWx0Ei0KCWRpcmVjdGlvbhgLIAEoDjIPLkRyaXZlRGly'
'ZWN0aW9uUglkaXJlY3Rpb24=');

@$core.Deprecated('Use driveDataDescriptor instead')
const DriveData$json = {
Expand Down
Loading