Skip to content

Instantly share code, notes, and snippets.

@Levi-Lesches
Last active September 9, 2022 01:37
Show Gist options
  • Save Levi-Lesches/90492ba63797092e4ce84f89d79d84af to your computer and use it in GitHub Desktop.
Save Levi-Lesches/90492ba63797092e4ce84f89d79d84af to your computer and use it in GitHub Desktop.
BURT's `MessageReceiver`
/// Something generated by Protobuf
abstract class Message { }
class ElectricalMessage extends Message {
final int voltage;
ElectricalMessage.fromBuffer(List data) :
voltage = data[0]; // parses raw data
}
class ScienceMessage extends Message {
final int methane;
ScienceMessage.fromBuffer(List data) :
methane = data[0]; // parses raw data
}
/// The aforementioned wrapper message
class WrappedMessage extends Message {
final String name;
final List data;
// data is sent as ["name", <data>]
WrappedMessage.fromBuffer(List data) :
name = data[0],
data = data.sublist(1);
}
/// Parses a list of bytes into a Message
typedef MessageDecoder<T extends Message> = T Function(List);
/// Does something with a Message
typedef MessageHandler<T extends Message> = void Function(T);
/// Does something with raw data.
///
/// The "something" is 1) convert to a Message (with [MessageDecoder]) and 2) do something with the message (with MessageHandler).
typedef RawDataHandler = void Function(List);
class Receiver {
Stream<List> messages; // the incoming data
Map<String, RawDataHandler> handlers = {}; // handles incoming raw data
Receiver(this.messages) { messages.listen(_listener); }
/// Decodes the data into a [WrappedMessage] and chooses a handler to call.
void _listener(List data) {
final wrapper = WrappedMessage.fromBuffer(data);
final RawDataHandler? handler = handlers[wrapper.name];
if (handler == null) throw "No handler for this message";
handler(wrapper.data);
}
/// For all messages with a given [name], decode the message and handle it.
///
/// The [decoder] and [handler] functions have to be provided later.
void registerHandler<T extends Message>({
required String name,
required MessageDecoder<T> decoder,
required MessageHandler<T> handler,
}) => handlers[name] = (data) {
// decode and handle
final T message = decoder(data);
handler(message);
};
}
/// Prints the voltage of the battery.
void readVoltage(ElectricalMessage message) =>
print("The battery has ${message.voltage} volts");
/// Prints the methane levels of the science chamber.
void readMethane(ScienceMessage message) =>
print("The dirt sample has ${message.methane} ppm of methane");
// Pretend this is code on the rover sending messages over
Stream<List> getMessages() async* {
yield ["Electrical", 0];
yield ["Science", 1];
yield ["WCRL", 2];
}
void main() => Receiver(getMessages()) // connect our [Receiver] to the "rover"
..registerHandler<ElectricalMessage>(
name: "Electrical", // for all Electrical messages...
decoder: ElectricalMessage.fromBuffer, // ... use ElectricalMessage.fromBuffer to decode
handler: readVoltage, // ... then call [readVoltage] with the result
)
..registerHandler<ScienceMessage>(
name: "Science", // for all "Science" messages...
decoder: ScienceMessage.fromBuffer, // ... use [ScienceMessage.fromBuffer] to decode
handler: readMethane, // ... then call [readMethane] with the result
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment