mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-23 17:21:06 +10:00
Refactor data handling of contacts (#267)
* Refactor data handling in MeshCoreConnector and BufferReader for improved readability and efficiency * Update lib/connector/meshcore_connector.dart Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix pointer tracking in BufferReader's readCString method --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -3820,40 +3820,40 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
|
|
||||||
void _handleRxData(Uint8List frame) {
|
void _handleRxData(Uint8List frame) {
|
||||||
final packet = BufferReader(frame);
|
final packet = BufferReader(frame);
|
||||||
double snr = 0.0;
|
|
||||||
int routeType = 0;
|
|
||||||
int payloadType = 0;
|
|
||||||
Uint8List pathBytes = Uint8List(0);
|
|
||||||
Uint8List payload = Uint8List(0);
|
|
||||||
try {
|
try {
|
||||||
packet.skipBytes(1); // Skip frame type byte
|
packet.skipBytes(1); // Skip frame type byte
|
||||||
snr = packet.readInt8() / 4.0;
|
final snr = packet.readInt8() / 4.0;
|
||||||
packet.skipBytes(1); // Skip RSSI byte
|
packet.skipBytes(1); // Skip RSSI byte
|
||||||
//final rssi = packet.readByte();
|
//final rssi = packet.readByte();
|
||||||
final header = packet.readByte();
|
final header = packet.readByte();
|
||||||
routeType = header & 0x03;
|
final routeType = header & 0x03;
|
||||||
payloadType = (header >> 2) & 0x0F;
|
final payloadType = (header >> 2) & 0x0F;
|
||||||
|
if (routeType == _routeTransportFlood ||
|
||||||
|
routeType == _routeTransportDirect) {
|
||||||
|
packet.skipBytes(4); // Skip transport-specific bytes
|
||||||
|
}
|
||||||
//final payloadVer = (header >> 6) & 0x03;
|
//final payloadVer = (header >> 6) & 0x03;
|
||||||
final pathLen = packet.readByte();
|
final pathLen = packet.readByte();
|
||||||
pathBytes = packet.readBytes(pathLen);
|
final pathBytes = packet.readBytes(pathLen);
|
||||||
payload = packet.readBytes(packet.remaining);
|
final payload = packet.readBytes(packet.remaining);
|
||||||
|
|
||||||
|
final rawPacket = frame.sublist(3);
|
||||||
|
switch (payloadType) {
|
||||||
|
case payloadTypeADVERT:
|
||||||
|
_handlePayloadAdvertReceived(
|
||||||
|
rawPacket,
|
||||||
|
payload,
|
||||||
|
pathBytes,
|
||||||
|
routeType,
|
||||||
|
snr,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
appLogger.warn('Malformed RX frame: $e', tag: 'Connector');
|
appLogger.warn('Malformed RX frame: $e', tag: 'Connector');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final rawPacket = frame.sublist(3);
|
|
||||||
switch (payloadType) {
|
|
||||||
case payloadTypeADVERT:
|
|
||||||
_handlePayloadAdvertReceived(
|
|
||||||
rawPacket,
|
|
||||||
payload,
|
|
||||||
pathBytes,
|
|
||||||
routeType,
|
|
||||||
snr,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void importContact(Uint8List frame) {
|
void importContact(Uint8List frame) {
|
||||||
@@ -3865,7 +3865,12 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
packet.skipBytes(1); // Skip SNR byte
|
packet.skipBytes(1); // Skip SNR byte
|
||||||
packet.skipBytes(1); // Skip RSSI byte
|
packet.skipBytes(1); // Skip RSSI byte
|
||||||
final header = packet.readByte();
|
final header = packet.readByte();
|
||||||
|
final routeType = header & 0x03;
|
||||||
payloadType = (header >> 2) & 0x0F;
|
payloadType = (header >> 2) & 0x0F;
|
||||||
|
if (routeType == _routeTransportFlood ||
|
||||||
|
routeType == _routeTransportDirect) {
|
||||||
|
packet.skipBytes(4); // Skip transport-specific bytes
|
||||||
|
}
|
||||||
//final payloadVer = (header >> 6) & 0x03;
|
//final payloadVer = (header >> 6) & 0x03;
|
||||||
final pathLen = packet.readByte();
|
final pathLen = packet.readByte();
|
||||||
pathBytes = packet.readBytes(pathLen);
|
pathBytes = packet.readBytes(pathLen);
|
||||||
@@ -3915,7 +3920,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
publicKey: publicKey,
|
publicKey: publicKey,
|
||||||
name: name,
|
name: name,
|
||||||
type: type,
|
type: type,
|
||||||
pathLength: pathBytes.length,
|
pathLength: pathBytes.isEmpty ? -1 : pathBytes.length,
|
||||||
path: Uint8List.fromList(
|
path: Uint8List.fromList(
|
||||||
pathBytes.reversed.toList(),
|
pathBytes.reversed.toList(),
|
||||||
), // Store path in reverse for easier use in outgoing messages
|
), // Store path in reverse for easier use in outgoing messages
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'dart:typed_data';
|
|||||||
// Buffer Reader - sequential binary data reader with pointer tracking
|
// Buffer Reader - sequential binary data reader with pointer tracking
|
||||||
class BufferReader {
|
class BufferReader {
|
||||||
int _pointer = 0;
|
int _pointer = 0;
|
||||||
|
int _lastPointer = 0;
|
||||||
final Uint8List _buffer;
|
final Uint8List _buffer;
|
||||||
|
|
||||||
BufferReader(Uint8List data) : _buffer = Uint8List.fromList(data);
|
BufferReader(Uint8List data) : _buffer = Uint8List.fromList(data);
|
||||||
@@ -13,6 +14,7 @@ class BufferReader {
|
|||||||
int readByte() => readBytes(1)[0];
|
int readByte() => readBytes(1)[0];
|
||||||
|
|
||||||
Uint8List readBytes(int count) {
|
Uint8List readBytes(int count) {
|
||||||
|
_lastPointer = _pointer;
|
||||||
if (_pointer + count > _buffer.length) {
|
if (_pointer + count > _buffer.length) {
|
||||||
throw RangeError(
|
throw RangeError(
|
||||||
'Attempted to read $count bytes at offset $_pointer, but only $remaining bytes remaining in buffer of length ${_buffer.length}',
|
'Attempted to read $count bytes at offset $_pointer, but only $remaining bytes remaining in buffer of length ${_buffer.length}',
|
||||||
@@ -24,6 +26,7 @@ class BufferReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void skipBytes(int count) {
|
void skipBytes(int count) {
|
||||||
|
_lastPointer = _pointer;
|
||||||
if (_pointer + count > _buffer.length) {
|
if (_pointer + count > _buffer.length) {
|
||||||
throw RangeError(
|
throw RangeError(
|
||||||
'Attempted to skip $count bytes at offset $_pointer, but only $remaining bytes remaining in buffer of length ${_buffer.length}',
|
'Attempted to skip $count bytes at offset $_pointer, but only $remaining bytes remaining in buffer of length ${_buffer.length}',
|
||||||
@@ -35,6 +38,7 @@ class BufferReader {
|
|||||||
Uint8List readRemainingBytes() => readBytes(remaining);
|
Uint8List readRemainingBytes() => readBytes(remaining);
|
||||||
|
|
||||||
String readString() {
|
String readString() {
|
||||||
|
_lastPointer = _pointer;
|
||||||
final value = readRemainingBytes();
|
final value = readRemainingBytes();
|
||||||
try {
|
try {
|
||||||
return utf8.decode(Uint8List.fromList(value), allowMalformed: true);
|
return utf8.decode(Uint8List.fromList(value), allowMalformed: true);
|
||||||
@@ -43,7 +47,8 @@ class BufferReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String readCString(int maxLength) {
|
String readCStringGreedy(int maxLength) {
|
||||||
|
_lastPointer = _pointer;
|
||||||
final value = <int>[];
|
final value = <int>[];
|
||||||
final bytes = readBytes(maxLength);
|
final bytes = readBytes(maxLength);
|
||||||
for (final byte in bytes) {
|
for (final byte in bytes) {
|
||||||
@@ -57,6 +62,24 @@ class BufferReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String readCString(int maxLength) {
|
||||||
|
final backupPointer = _pointer;
|
||||||
|
final value = <int>[];
|
||||||
|
int counter = 0;
|
||||||
|
while (counter < maxLength) {
|
||||||
|
final byte = readByte();
|
||||||
|
if (byte == 0) break;
|
||||||
|
value.add(byte);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
_lastPointer = backupPointer;
|
||||||
|
try {
|
||||||
|
return utf8.decode(Uint8List.fromList(value), allowMalformed: true);
|
||||||
|
} catch (e) {
|
||||||
|
return String.fromCharCodes(value); // Latin-1 fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int readUInt8() => readBytes(1).buffer.asByteData().getUint8(0);
|
int readUInt8() => readBytes(1).buffer.asByteData().getUint8(0);
|
||||||
int readInt8() => readBytes(1).buffer.asByteData().getInt8(0);
|
int readInt8() => readBytes(1).buffer.asByteData().getInt8(0);
|
||||||
int readUInt16LE() =>
|
int readUInt16LE() =>
|
||||||
@@ -78,6 +101,9 @@ class BufferReader {
|
|||||||
if ((value & 0x800000) != 0) value -= 0x1000000;
|
if ((value & 0x800000) != 0) value -= 0x1000000;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetPointer() => _pointer = 0;
|
||||||
|
void rewind() => _pointer = _lastPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer Writer - accumulating binary data builder
|
// Buffer Writer - accumulating binary data builder
|
||||||
|
|||||||
+20
-19
@@ -1,4 +1,6 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
import 'package:meshcore_open/utils/app_logger.dart';
|
||||||
|
|
||||||
import '../connector/meshcore_protocol.dart';
|
import '../connector/meshcore_protocol.dart';
|
||||||
|
|
||||||
class Contact {
|
class Contact {
|
||||||
@@ -166,28 +168,27 @@ class Contact {
|
|||||||
|
|
||||||
static Contact? fromFrame(Uint8List data) {
|
static Contact? fromFrame(Uint8List data) {
|
||||||
if (data.isEmpty) return null;
|
if (data.isEmpty) return null;
|
||||||
if (data[0] != respCodeContact) return null;
|
final reader = BufferReader(data);
|
||||||
try {
|
try {
|
||||||
final pubKey = Uint8List.fromList(
|
final respCode = reader.readByte();
|
||||||
data.sublist(contactPubKeyOffset, contactPubKeyOffset + pubKeySize),
|
if (respCode != respCodeContact && respCode != pushCodeNewAdvert) {
|
||||||
);
|
return null;
|
||||||
final type = data[contactTypeOffset];
|
}
|
||||||
final flags = data[contactFlagsOffset];
|
final pubKey = reader.readBytes(pubKeySize);
|
||||||
final pathLen = data[contactPathLenOffset].toSigned(8);
|
final type = reader.readByte();
|
||||||
|
final flags = reader.readByte();
|
||||||
|
final pathLen = reader.readByte();
|
||||||
final safePathLen = pathLen > 0
|
final safePathLen = pathLen > 0
|
||||||
? (pathLen > maxPathSize ? maxPathSize : pathLen)
|
? (pathLen > maxPathSize ? maxPathSize : pathLen)
|
||||||
: 0;
|
: 0;
|
||||||
final pathBytes = safePathLen > 0
|
final pathBytes = reader.readBytes(maxPathSize).sublist(0, safePathLen);
|
||||||
? Uint8List.fromList(
|
final name = reader.readCStringGreedy(maxNameSize);
|
||||||
data.sublist(contactPathOffset, contactPathOffset + safePathLen),
|
|
||||||
)
|
final lastMod = reader.readUInt32LE();
|
||||||
: Uint8List(0);
|
|
||||||
final name = readCString(data, contactNameOffset, maxNameSize);
|
|
||||||
final lastmod = readUint32LE(data, contactLastModOffset);
|
|
||||||
|
|
||||||
double? lat, lon;
|
double? lat, lon;
|
||||||
final latRaw = readInt32LE(data, contactLatOffset);
|
final latRaw = reader.readInt32LE();
|
||||||
final lonRaw = readInt32LE(data, contactLonOffset);
|
final lonRaw = reader.readInt32LE();
|
||||||
if (latRaw != 0 || lonRaw != 0) {
|
if (latRaw != 0 || lonRaw != 0) {
|
||||||
lat = latRaw / 1e6;
|
lat = latRaw / 1e6;
|
||||||
lon = lonRaw / 1e6;
|
lon = lonRaw / 1e6;
|
||||||
@@ -198,14 +199,14 @@ class Contact {
|
|||||||
name: name.isEmpty ? 'Unknown' : name,
|
name: name.isEmpty ? 'Unknown' : name,
|
||||||
type: type,
|
type: type,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
pathLength: pathLen,
|
pathLength: pathLen > 0 ? (pathLen > maxPathSize ? -1 : pathLen) : -1,
|
||||||
path: pathBytes,
|
path: pathBytes,
|
||||||
latitude: lat,
|
latitude: lat,
|
||||||
longitude: lon,
|
longitude: lon,
|
||||||
lastSeen: DateTime.fromMillisecondsSinceEpoch(lastmod * 1000),
|
lastSeen: DateTime.fromMillisecondsSinceEpoch(lastMod * 1000),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// If parsing fails, return null
|
appLogger.error('Failed to parse contact frame: $e');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user