Last active
September 9, 2022 01:37
-
-
Save Levi-Lesches/90492ba63797092e4ce84f89d79d84af to your computer and use it in GitHub Desktop.
BURT's `MessageReceiver`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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