veilid/veilid-flutter/lib/routing_context.dart

262 lines
6.9 KiB
Dart
Raw Permalink Normal View History

2023-05-29 19:24:57 +00:00
import 'dart:async';
import 'dart:typed_data';
import 'package:change_case/change_case.dart';
2023-07-06 15:41:38 +00:00
import 'package:equatable/equatable.dart';
2023-07-06 03:53:08 +00:00
import 'package:freezed_annotation/freezed_annotation.dart';
2023-05-29 19:24:57 +00:00
import 'veilid.dart';
2023-07-06 03:53:08 +00:00
part 'routing_context.freezed.dart';
part 'routing_context.g.dart';
2023-05-29 19:24:57 +00:00
//////////////////////////////////////
2023-07-06 15:41:38 +00:00
extension ValidateDFLT on DHTSchemaDFLT {
bool validate() {
if (oCnt > 65535) {
return false;
2023-05-29 19:24:57 +00:00
}
2023-07-06 15:41:38 +00:00
if (oCnt <= 0) {
return false;
}
return true;
2023-05-29 19:24:57 +00:00
}
}
2023-07-06 15:41:38 +00:00
extension ValidateSMPL on DHTSchemaSMPL {
bool validate() {
2023-07-26 18:20:17 +00:00
final totalsv = members.fold(0, (acc, v) => acc + v.mCnt) + oCnt;
2023-07-06 15:41:38 +00:00
if (totalsv > 65535) {
return false;
}
if (totalsv <= 0) {
return false;
2023-05-29 19:24:57 +00:00
}
2023-07-06 15:41:38 +00:00
return true;
2023-05-29 19:24:57 +00:00
}
2023-07-06 15:41:38 +00:00
}
2023-05-29 19:24:57 +00:00
2023-07-06 15:41:38 +00:00
//////////////////////////////////////
/// DHT Schema
@Freezed(unionKey: 'kind', unionValueCase: FreezedUnionCase.pascal)
sealed class DHTSchema with _$DHTSchema {
@FreezedUnionValue('DFLT')
const factory DHTSchema.dflt({required int oCnt}) = DHTSchemaDFLT;
@FreezedUnionValue('SMPL')
const factory DHTSchema.smpl(
{required int oCnt,
required List<DHTSchemaMember> members}) = DHTSchemaSMPL;
2023-07-25 05:04:22 +00:00
factory DHTSchema.fromJson(dynamic json) =>
_$DHTSchemaFromJson(json as Map<String, dynamic>);
2023-05-29 19:24:57 +00:00
}
2023-07-13 01:28:00 +00:00
const DHTSchema defaultDHTSchema = DHTSchema.dflt(oCnt: 1);
2023-07-06 03:53:08 +00:00
@freezed
class DHTSchemaMember with _$DHTSchemaMember {
2023-07-06 15:41:38 +00:00
@Assert('mCnt > 0 && mCnt <= 65535', 'value out of range')
2023-07-06 03:53:08 +00:00
const factory DHTSchemaMember({
required PublicKey mKey,
required int mCnt,
}) = _DHTSchemaMember;
2023-05-29 19:24:57 +00:00
2023-07-25 05:04:22 +00:00
factory DHTSchemaMember.fromJson(dynamic json) =>
_$DHTSchemaMemberFromJson(json as Map<String, dynamic>);
2023-05-29 19:24:57 +00:00
}
//////////////////////////////////////
/// DHTRecordDescriptor
2023-07-06 15:41:38 +00:00
@freezed
class DHTRecordDescriptor with _$DHTRecordDescriptor {
const factory DHTRecordDescriptor({
required TypedKey key,
required PublicKey owner,
2023-07-30 19:57:06 +00:00
required DHTSchema schema,
PublicKey? ownerSecret,
2023-07-06 15:41:38 +00:00
}) = _DHTRecordDescriptor;
2023-07-25 05:04:22 +00:00
factory DHTRecordDescriptor.fromJson(dynamic json) =>
_$DHTRecordDescriptorFromJson(json as Map<String, dynamic>);
2023-05-29 19:24:57 +00:00
}
2023-07-21 13:48:08 +00:00
extension DHTRecordDescriptorExt on DHTRecordDescriptor {
KeyPair? ownerKeyPair() {
if (ownerSecret == null) {
return null;
}
return KeyPair(key: owner, secret: ownerSecret!);
}
2023-07-21 18:30:10 +00:00
TypedKeyPair? ownerTypedKeyPair() {
if (ownerSecret == null) {
return null;
}
return TypedKeyPair(kind: key.kind, key: owner, secret: ownerSecret!);
}
2023-07-21 13:48:08 +00:00
}
2023-05-29 19:24:57 +00:00
//////////////////////////////////////
/// ValueSubkeyRange
2023-07-06 15:41:38 +00:00
@freezed
class ValueSubkeyRange with _$ValueSubkeyRange {
@Assert('low < 0 || low > high', 'low out of range')
@Assert('high < 0', 'high out of range')
const factory ValueSubkeyRange({
required int low,
required int high,
}) = _ValueSubkeyRange;
2023-07-25 05:04:22 +00:00
factory ValueSubkeyRange.fromJson(dynamic json) =>
_$ValueSubkeyRangeFromJson(json as Map<String, dynamic>);
2023-05-29 19:24:57 +00:00
}
//////////////////////////////////////
/// ValueData
2023-07-06 15:41:38 +00:00
@freezed
class ValueData with _$ValueData {
@Assert('seq >= 0', 'seq out of range')
const factory ValueData({
required int seq,
2023-10-15 00:18:37 +00:00
@Uint8ListJsonConverter.jsIsArray() required Uint8List data,
2023-07-06 15:41:38 +00:00
required PublicKey writer,
}) = _ValueData;
2023-07-25 05:04:22 +00:00
factory ValueData.fromJson(dynamic json) =>
_$ValueDataFromJson(json as Map<String, dynamic>);
2023-05-29 19:24:57 +00:00
}
//////////////////////////////////////
2023-05-29 19:24:57 +00:00
/// Stability
enum Stability {
lowLatency,
reliable;
2023-07-25 05:04:22 +00:00
factory Stability.fromJson(dynamic j) =>
Stability.values.byName((j as String).toCamelCase());
2023-07-30 19:57:06 +00:00
String toJson() => name.toPascalCase();
2023-05-29 19:24:57 +00:00
}
//////////////////////////////////////
/// Sequencing
enum Sequencing {
noPreference,
preferOrdered,
ensureOrdered;
2023-07-25 05:04:22 +00:00
factory Sequencing.fromJson(dynamic j) =>
Sequencing.values.byName((j as String).toCamelCase());
2023-07-30 19:57:06 +00:00
String toJson() => name.toPascalCase();
2023-05-29 19:24:57 +00:00
}
//////////////////////////////////////
/// SafetySelection
2023-07-06 15:41:38 +00:00
@immutable
2023-07-30 19:57:06 +00:00
abstract class SafetySelection {
2023-07-25 05:04:22 +00:00
factory SafetySelection.fromJson(dynamic jsond) {
final json = jsond as Map<String, dynamic>;
2023-07-26 18:20:17 +00:00
if (json.containsKey('Unsafe')) {
return SafetySelectionUnsafe(
2023-07-26 18:20:17 +00:00
sequencing: Sequencing.fromJson(json['Unsafe']));
} else if (json.containsKey('Safe')) {
return SafetySelectionSafe(safetySpec: SafetySpec.fromJson(json['Safe']));
} else {
2023-07-26 18:20:17 +00:00
throw const VeilidAPIExceptionInternal('Invalid SafetySelection');
}
}
Map<String, dynamic> toJson();
}
2023-07-06 15:41:38 +00:00
@immutable
2023-07-30 19:57:06 +00:00
class SafetySelectionUnsafe extends Equatable implements SafetySelection {
//
2023-07-06 15:41:38 +00:00
const SafetySelectionUnsafe({
required this.sequencing,
});
2023-07-26 18:20:17 +00:00
final Sequencing sequencing;
@override
List<Object> get props => [sequencing];
@override
bool? get stringify => null;
@override
2023-07-26 18:20:17 +00:00
Map<String, dynamic> toJson() => {'Unsafe': sequencing.toJson()};
}
2023-07-06 15:41:38 +00:00
@immutable
2023-07-30 19:57:06 +00:00
class SafetySelectionSafe extends Equatable implements SafetySelection {
//
2023-07-06 15:41:38 +00:00
const SafetySelectionSafe({
required this.safetySpec,
});
2023-07-26 18:20:17 +00:00
final SafetySpec safetySpec;
@override
List<Object> get props => [safetySpec];
@override
bool? get stringify => null;
@override
2023-07-26 18:20:17 +00:00
Map<String, dynamic> toJson() => {'Safe': safetySpec.toJson()};
}
/// Options for safety routes (sender privacy)
2023-07-06 15:41:38 +00:00
@freezed
class SafetySpec with _$SafetySpec {
const factory SafetySpec({
2023-07-30 19:57:06 +00:00
required int hopCount,
required Stability stability,
required Sequencing sequencing,
String? preferredRoute,
2023-07-06 15:41:38 +00:00
}) = _SafetySpec;
2023-07-25 05:04:22 +00:00
factory SafetySpec.fromJson(dynamic json) =>
_$SafetySpecFromJson(json as Map<String, dynamic>);
}
2023-05-29 19:24:57 +00:00
//////////////////////////////////////
/// RouteBlob
2023-07-06 15:41:38 +00:00
@freezed
class RouteBlob with _$RouteBlob {
const factory RouteBlob(
{required String routeId,
@Uint8ListJsonConverter() required Uint8List blob}) = _RouteBlob;
2023-07-25 05:04:22 +00:00
factory RouteBlob.fromJson(dynamic json) =>
_$RouteBlobFromJson(json as Map<String, dynamic>);
2023-05-29 19:24:57 +00:00
}
//////////////////////////////////////
/// VeilidRoutingContext
abstract class VeilidRoutingContext {
2023-07-19 14:07:51 +00:00
void close();
2023-05-29 19:24:57 +00:00
// Modifiers
VeilidRoutingContext withPrivacy();
VeilidRoutingContext withCustomPrivacy(SafetySelection safetySelection);
2023-05-29 19:24:57 +00:00
VeilidRoutingContext withSequencing(Sequencing sequencing);
// App call/message
Future<Uint8List> appCall(String target, Uint8List request);
Future<void> appMessage(String target, Uint8List message);
// DHT Operations
2023-07-09 02:50:44 +00:00
Future<DHTRecordDescriptor> createDHTRecord(DHTSchema schema,
{CryptoKind kind = 0});
2023-05-29 19:24:57 +00:00
Future<DHTRecordDescriptor> openDHTRecord(TypedKey key, KeyPair? writer);
Future<void> closeDHTRecord(TypedKey key);
Future<void> deleteDHTRecord(TypedKey key);
Future<ValueData?> getDHTValue(TypedKey key, int subkey, bool forceRefresh);
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data);
2023-06-27 22:26:53 +00:00
Future<Timestamp> watchDHTValues(TypedKey key, List<ValueSubkeyRange> subkeys,
Timestamp expiration, int count);
Future<bool> cancelDHTWatch(TypedKey key, List<ValueSubkeyRange> subkeys);
2023-05-29 19:24:57 +00:00
}