feat(train): routes planned through the instance's BRouter (ADR 0030, D44)

The routing endpoint plans a route through the waypoints for one of six
profiles, for the people signed in, at most 50 waypoints and 30 plans a
person a minute, nothing kept or logged; refused without BROUTER_URL.
BRouter's GeoJSON is read into points, elevations, climb and descent
above 3 m, turn hints and stretches by surface. Train's running profile
for BRouter, halkyon-run.brf, is a first guess not yet tried on BRouter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-28 23:37:47 +01:00
commit 781576726a
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
8 changed files with 2563 additions and 1 deletions

View file

@ -18,6 +18,12 @@ import 'package:halkyon_train_client/src/protocol/firmware/loop_firmware.dart'
as _ikc7xqe5;
import 'package:halkyon_train_client/src/protocol/map/map_source.dart'
as _iebj1x2g;
import 'package:halkyon_train_client/src/protocol/routing/planned_route.dart'
as _i0hhs3f4;
import 'package:halkyon_train_client/src/protocol/routing/route_point.dart'
as _iq1flhug;
import 'package:halkyon_train_client/src/protocol/routing/route_profile.dart'
as _isvxstnj;
import 'package:http/http.dart' as _i85jenna;
import 'package:serverpod_auth_core_client/serverpod_auth_core_client.dart'
as _iacc;
@ -96,6 +102,41 @@ class EndpointMap extends _isc.EndpointRef {
);
}
/// Routes planned by the instance's BRouter (ADR 0030, D11, D44), for those
/// signed in: BRouter has no sign-in of its own, so the server alone reaches
/// it. Neither the waypoints nor the route are kept or logged. Refusals are
/// `RouteRefused`.
/// {@category Endpoint}
class EndpointRouting extends _isc.EndpointRef {
EndpointRouting(_isc.EndpointCaller caller) : super(caller);
@override
String get name => 'routing';
/// Whether the instance plans routes.
_ida.Future<bool> offered() => caller.callServerEndpoint<bool>(
'routing',
'offered',
{},
);
/// The route through [waypoints], in order, for [profile]. Refused where
/// the instance has no BRouter or it fails, for fewer than two or more
/// than `Routing.maxWaypoints` waypoints, and beyond `Routing.perMinute`
/// plans a minute.
_ida.Future<_i0hhs3f4.PlannedRoute> plan(
List<_iq1flhug.RoutePoint> waypoints,
_isvxstnj.RouteProfile profile,
) => caller.callServerEndpoint<_i0hhs3f4.PlannedRoute>(
'routing',
'plan',
{
'waypoints': waypoints,
'profile': profile,
},
);
}
class Modules {
Modules(Client client) {
base = _ihk4p5t7.Caller(client);
@ -145,6 +186,7 @@ class Client extends _isc.ServerpodClientShared {
) {
firmware = EndpointFirmware(this);
map = EndpointMap(this);
routing = EndpointRouting(this);
modules = Modules(this);
}
@ -152,12 +194,15 @@ class Client extends _isc.ServerpodClientShared {
late final EndpointMap map;
late final EndpointRouting routing;
late final Modules modules;
@override
Map<String, _isc.EndpointRef> get endpointRefLookup => {
'firmware': firmware,
'map': map,
'routing': routing,
};
@override

View file

@ -13,6 +13,8 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:halkyon_base_client/halkyon_base_client.dart' as _ihk4p5t7;
import 'package:halkyon_oidc_client/halkyon_oidc_client.dart' as _ibkpwzgl;
import 'package:halkyon_train_client/src/protocol/routing/route_point.dart'
as _iq1flhug;
import 'package:serverpod_auth_core_client/serverpod_auth_core_client.dart'
as _iacc;
import 'package:serverpod_auth_idp_client/serverpod_auth_idp_client.dart'
@ -30,6 +32,12 @@ import 'map/map_source.dart' as _ikw0qg8x;
import 'plan/plan.dart' as _i45prw73;
import 'privacy/content_key.dart' as _imed3x5d;
import 'profile/profile.dart' as _ia5j8fch;
import 'routing/planned_route.dart' as _ikjgxraq;
import 'routing/route_hint.dart' as _if6974nb;
import 'routing/route_point.dart' as _isqtfus6;
import 'routing/route_profile.dart' as _ifl4j5ep;
import 'routing/route_refused.dart' as _ix4aepwk;
import 'routing/route_stretch.dart' as _ic7f85bc;
import 'workout/workout.dart' as _i5b9b17z;
import 'workout/workout_series.dart' as _i92mefto;
export 'day/day.dart';
@ -41,6 +49,12 @@ export 'map/map_source.dart';
export 'plan/plan.dart';
export 'privacy/content_key.dart';
export 'profile/profile.dart';
export 'routing/planned_route.dart';
export 'routing/route_hint.dart';
export 'routing/route_point.dart';
export 'routing/route_profile.dart';
export 'routing/route_refused.dart';
export 'routing/route_stretch.dart';
export 'workout/workout.dart';
export 'workout/workout_series.dart';
export 'client.dart';
@ -720,6 +734,24 @@ class Protocol extends _isd.DatabaseSerializationManager {
if (t == _ia5j8fch.Profile) {
return _ia5j8fch.Profile.fromJson(data) as T;
}
if (t == _ikjgxraq.PlannedRoute) {
return _ikjgxraq.PlannedRoute.fromJson(data) as T;
}
if (t == _if6974nb.RouteHint) {
return _if6974nb.RouteHint.fromJson(data) as T;
}
if (t == _isqtfus6.RoutePoint) {
return _isqtfus6.RoutePoint.fromJson(data) as T;
}
if (t == _ifl4j5ep.RouteProfile) {
return _ifl4j5ep.RouteProfile.fromJson(data) as T;
}
if (t == _ix4aepwk.RouteRefused) {
return _ix4aepwk.RouteRefused.fromJson(data) as T;
}
if (t == _ic7f85bc.RouteStretch) {
return _ic7f85bc.RouteStretch.fromJson(data) as T;
}
if (t == _i5b9b17z.Workout) {
return _i5b9b17z.Workout.fromJson(data) as T;
}
@ -756,6 +788,24 @@ class Protocol extends _isd.DatabaseSerializationManager {
if (t == _isc.getType<_ia5j8fch.Profile?>()) {
return (data != null ? _ia5j8fch.Profile.fromJson(data) : null) as T;
}
if (t == _isc.getType<_ikjgxraq.PlannedRoute?>()) {
return (data != null ? _ikjgxraq.PlannedRoute.fromJson(data) : null) as T;
}
if (t == _isc.getType<_if6974nb.RouteHint?>()) {
return (data != null ? _if6974nb.RouteHint.fromJson(data) : null) as T;
}
if (t == _isc.getType<_isqtfus6.RoutePoint?>()) {
return (data != null ? _isqtfus6.RoutePoint.fromJson(data) : null) as T;
}
if (t == _isc.getType<_ifl4j5ep.RouteProfile?>()) {
return (data != null ? _ifl4j5ep.RouteProfile.fromJson(data) : null) as T;
}
if (t == _isc.getType<_ix4aepwk.RouteRefused?>()) {
return (data != null ? _ix4aepwk.RouteRefused.fromJson(data) : null) as T;
}
if (t == _isc.getType<_ic7f85bc.RouteStretch?>()) {
return (data != null ? _ic7f85bc.RouteStretch.fromJson(data) : null) as T;
}
if (t == _isc.getType<_i5b9b17z.Workout?>()) {
return (data != null ? _i5b9b17z.Workout.fromJson(data) : null) as T;
}
@ -763,6 +813,33 @@ class Protocol extends _isd.DatabaseSerializationManager {
return (data != null ? _i92mefto.WorkoutSeries.fromJson(data) : null)
as T;
}
if (t == List<_isqtfus6.RoutePoint>) {
return (data as List)
.map((e) => deserialize<_isqtfus6.RoutePoint>(e))
.toList()
as T;
}
if (t == List<double>) {
return (data as List).map((e) => deserialize<double>(e)).toList() as T;
}
if (t == List<_if6974nb.RouteHint>) {
return (data as List)
.map((e) => deserialize<_if6974nb.RouteHint>(e))
.toList()
as T;
}
if (t == List<_ic7f85bc.RouteStretch>) {
return (data as List)
.map((e) => deserialize<_ic7f85bc.RouteStretch>(e))
.toList()
as T;
}
if (t == List<_iq1flhug.RoutePoint>) {
return (data as List)
.map((e) => deserialize<_iq1flhug.RoutePoint>(e))
.toList()
as T;
}
try {
return _ihk4p5t7.Protocol().deserialize<T>(data, t);
} on _isc.DeserializationTypeNotFoundException catch (_) {}
@ -792,6 +869,12 @@ class Protocol extends _isd.DatabaseSerializationManager {
_i45prw73.Plan => 'Plan',
_imed3x5d.ContentKey => 'ContentKey',
_ia5j8fch.Profile => 'Profile',
_ikjgxraq.PlannedRoute => 'PlannedRoute',
_if6974nb.RouteHint => 'RouteHint',
_isqtfus6.RoutePoint => 'RoutePoint',
_ifl4j5ep.RouteProfile => 'RouteProfile',
_ix4aepwk.RouteRefused => 'RouteRefused',
_ic7f85bc.RouteStretch => 'RouteStretch',
_i5b9b17z.Workout => 'Workout',
_i92mefto.WorkoutSeries => 'WorkoutSeries',
_ => null,
@ -829,6 +912,18 @@ class Protocol extends _isd.DatabaseSerializationManager {
return 'ContentKey';
case _ia5j8fch.Profile():
return 'Profile';
case _ikjgxraq.PlannedRoute():
return 'PlannedRoute';
case _if6974nb.RouteHint():
return 'RouteHint';
case _isqtfus6.RoutePoint():
return 'RoutePoint';
case _ifl4j5ep.RouteProfile():
return 'RouteProfile';
case _ix4aepwk.RouteRefused():
return 'RouteRefused';
case _ic7f85bc.RouteStretch():
return 'RouteStretch';
case _i5b9b17z.Workout():
return 'Workout';
case _i92mefto.WorkoutSeries():
@ -896,6 +991,24 @@ class Protocol extends _isd.DatabaseSerializationManager {
if (dataClassName == 'Profile') {
return deserialize<_ia5j8fch.Profile>(data['data']);
}
if (dataClassName == 'PlannedRoute') {
return deserialize<_ikjgxraq.PlannedRoute>(data['data']);
}
if (dataClassName == 'RouteHint') {
return deserialize<_if6974nb.RouteHint>(data['data']);
}
if (dataClassName == 'RoutePoint') {
return deserialize<_isqtfus6.RoutePoint>(data['data']);
}
if (dataClassName == 'RouteProfile') {
return deserialize<_ifl4j5ep.RouteProfile>(data['data']);
}
if (dataClassName == 'RouteRefused') {
return deserialize<_ix4aepwk.RouteRefused>(data['data']);
}
if (dataClassName == 'RouteStretch') {
return deserialize<_ic7f85bc.RouteStretch>(data['data']);
}
if (dataClassName == 'Workout') {
return deserialize<_i5b9b17z.Workout>(data['data']);
}

View file

@ -0,0 +1,169 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:halkyon_train_client/src/protocol/protocol.dart' as _ip4ob8rr;
import 'package:serverpod_client/serverpod_client.dart' as _isc;
import '../routing/route_hint.dart' as _iocqct4j;
import '../routing/route_point.dart' as _iafawe19;
import '../routing/route_stretch.dart' as _i8kofibb;
/// A route the instance's BRouter planned (ADR 0030, D44): its points in
/// order, their elevations in metres (empty where BRouter knows none; a point
/// without one takes the one before), its length, its climb and descent
/// (climbs above 3 m, as a workout's), its turns, and its stretches in order.
/// Nothing of it is kept on the instance: the app seals what it saves.
abstract class PlannedRoute
implements _isc.SerializableModel, _isc.ProtocolSerialization {
PlannedRoute._({
required this.points,
required this.elevations,
required this.distanceMetres,
required this.ascentMetres,
required this.descentMetres,
required this.hints,
required this.stretches,
});
factory PlannedRoute({
required List<_iafawe19.RoutePoint> points,
required List<double> elevations,
required int distanceMetres,
required int ascentMetres,
required int descentMetres,
required List<_iocqct4j.RouteHint> hints,
required List<_i8kofibb.RouteStretch> stretches,
}) = _PlannedRouteImpl;
factory PlannedRoute.fromJson(Map<String, dynamic> jsonSerialization) {
return PlannedRoute(
points: _ip4ob8rr.Protocol().deserialize<List<_iafawe19.RoutePoint>>(
jsonSerialization['points'],
),
elevations: _ip4ob8rr.Protocol().deserialize<List<double>>(
jsonSerialization['elevations'],
),
distanceMetres: jsonSerialization['distanceMetres'] as int,
ascentMetres: jsonSerialization['ascentMetres'] as int,
descentMetres: jsonSerialization['descentMetres'] as int,
hints: _ip4ob8rr.Protocol().deserialize<List<_iocqct4j.RouteHint>>(
jsonSerialization['hints'],
),
stretches: _ip4ob8rr.Protocol().deserialize<List<_i8kofibb.RouteStretch>>(
jsonSerialization['stretches'],
),
);
}
List<_iafawe19.RoutePoint> points;
List<double> elevations;
int distanceMetres;
int ascentMetres;
int descentMetres;
List<_iocqct4j.RouteHint> hints;
List<_i8kofibb.RouteStretch> stretches;
/// Returns a shallow copy of this [PlannedRoute]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
PlannedRoute copyWith({
List<_iafawe19.RoutePoint>? points,
List<double>? elevations,
int? distanceMetres,
int? ascentMetres,
int? descentMetres,
List<_iocqct4j.RouteHint>? hints,
List<_i8kofibb.RouteStretch>? stretches,
});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'PlannedRoute',
'points': points.toJson(valueToJson: (v) => v.toJson()),
'elevations': elevations.toJson(),
'distanceMetres': distanceMetres,
'ascentMetres': ascentMetres,
'descentMetres': descentMetres,
'hints': hints.toJson(valueToJson: (v) => v.toJson()),
'stretches': stretches.toJson(valueToJson: (v) => v.toJson()),
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'PlannedRoute',
'points': points.toJson(valueToJson: (v) => v.toJsonForProtocol()),
'elevations': elevations.toJson(),
'distanceMetres': distanceMetres,
'ascentMetres': ascentMetres,
'descentMetres': descentMetres,
'hints': hints.toJson(valueToJson: (v) => v.toJsonForProtocol()),
'stretches': stretches.toJson(valueToJson: (v) => v.toJsonForProtocol()),
};
}
@override
String toString() {
return _isc.SerializationManager.encode(this);
}
}
class _PlannedRouteImpl extends PlannedRoute {
_PlannedRouteImpl({
required List<_iafawe19.RoutePoint> points,
required List<double> elevations,
required int distanceMetres,
required int ascentMetres,
required int descentMetres,
required List<_iocqct4j.RouteHint> hints,
required List<_i8kofibb.RouteStretch> stretches,
}) : super._(
points: points,
elevations: elevations,
distanceMetres: distanceMetres,
ascentMetres: ascentMetres,
descentMetres: descentMetres,
hints: hints,
stretches: stretches,
);
/// Returns a shallow copy of this [PlannedRoute]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
PlannedRoute copyWith({
List<_iafawe19.RoutePoint>? points,
List<double>? elevations,
int? distanceMetres,
int? ascentMetres,
int? descentMetres,
List<_iocqct4j.RouteHint>? hints,
List<_i8kofibb.RouteStretch>? stretches,
}) {
return PlannedRoute(
points: points ?? this.points.map((e0) => e0.copyWith()).toList(),
elevations: elevations ?? this.elevations.map((e0) => e0).toList(),
distanceMetres: distanceMetres ?? this.distanceMetres,
ascentMetres: ascentMetres ?? this.ascentMetres,
descentMetres: descentMetres ?? this.descentMetres,
hints: hints ?? this.hints.map((e0) => e0.copyWith()).toList(),
stretches:
stretches ?? this.stretches.map((e0) => e0.copyWith()).toList(),
);
}
}

View file

@ -0,0 +1,133 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:serverpod_client/serverpod_client.dart' as _isc;
/// A turn of a route planned, as BRouter hints it (ADR 0030, D45): at the
/// point [index] of the route, BRouter's command (1 straight on, 2 left, 3
/// slightly left, 4 sharply left, 5 right, 6 slightly right, 7 sharply
/// right, 8 keep left, 9 keep right, 10 and 11 U-turns, 13 and 14
/// roundabouts, 15 a 180° turn, 17 and 18 exits, 16 a beeline), the exit of
/// a roundabout, the metres to the next hint and the turn's angle.
abstract class RouteHint
implements _isc.SerializableModel, _isc.ProtocolSerialization {
RouteHint._({
required this.index,
required this.command,
required this.exit,
required this.metres,
required this.angle,
});
factory RouteHint({
required int index,
required int command,
required int exit,
required int metres,
required int angle,
}) = _RouteHintImpl;
factory RouteHint.fromJson(Map<String, dynamic> jsonSerialization) {
return RouteHint(
index: jsonSerialization['index'] as int,
command: jsonSerialization['command'] as int,
exit: jsonSerialization['exit'] as int,
metres: jsonSerialization['metres'] as int,
angle: jsonSerialization['angle'] as int,
);
}
int index;
int command;
int exit;
int metres;
int angle;
/// Returns a shallow copy of this [RouteHint]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
RouteHint copyWith({
int? index,
int? command,
int? exit,
int? metres,
int? angle,
});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'RouteHint',
'index': index,
'command': command,
'exit': exit,
'metres': metres,
'angle': angle,
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'RouteHint',
'index': index,
'command': command,
'exit': exit,
'metres': metres,
'angle': angle,
};
}
@override
String toString() {
return _isc.SerializationManager.encode(this);
}
}
class _RouteHintImpl extends RouteHint {
_RouteHintImpl({
required int index,
required int command,
required int exit,
required int metres,
required int angle,
}) : super._(
index: index,
command: command,
exit: exit,
metres: metres,
angle: angle,
);
/// Returns a shallow copy of this [RouteHint]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
RouteHint copyWith({
int? index,
int? command,
int? exit,
int? metres,
int? angle,
}) {
return RouteHint(
index: index ?? this.index,
command: command ?? this.command,
exit: exit ?? this.exit,
metres: metres ?? this.metres,
angle: angle ?? this.angle,
);
}
}

View file

@ -0,0 +1,93 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:serverpod_client/serverpod_client.dart' as _isc;
/// A point on the earth, in degrees (WGS 84): a waypoint asked for, or a
/// point of a route planned (ADR 0030, D44).
abstract class RoutePoint
implements _isc.SerializableModel, _isc.ProtocolSerialization {
RoutePoint._({
required this.lat,
required this.lon,
});
factory RoutePoint({
required double lat,
required double lon,
}) = _RoutePointImpl;
factory RoutePoint.fromJson(Map<String, dynamic> jsonSerialization) {
return RoutePoint(
lat: (jsonSerialization['lat'] as num).toDouble(),
lon: (jsonSerialization['lon'] as num).toDouble(),
);
}
double lat;
double lon;
/// Returns a shallow copy of this [RoutePoint]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
RoutePoint copyWith({
double? lat,
double? lon,
});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'RoutePoint',
'lat': lat,
'lon': lon,
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'RoutePoint',
'lat': lat,
'lon': lon,
};
}
@override
String toString() {
return _isc.SerializationManager.encode(this);
}
}
class _RoutePointImpl extends RoutePoint {
_RoutePointImpl({
required double lat,
required double lon,
}) : super._(
lat: lat,
lon: lon,
);
/// Returns a shallow copy of this [RoutePoint]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
RoutePoint copyWith({
double? lat,
double? lon,
}) {
return RoutePoint(
lat: lat ?? this.lat,
lon: lon ?? this.lon,
);
}
}

View file

@ -0,0 +1,52 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:serverpod_client/serverpod_client.dart' as _isc;
/// How a route is planned (ADR 0030, D44): running on Train's own BRouter
/// profile, hiking (`hiking-mountain`), a road bike (`fastbike`), a trekking
/// bike (`trekking`), gravel (`gravel`) or a mountain bike (`mtb`).
enum RouteProfile implements _isc.SerializableModel {
run,
hike,
roadBike,
trekkingBike,
gravel,
mtb;
static RouteProfile fromJson(String name) {
switch (name) {
case 'run':
return RouteProfile.run;
case 'hike':
return RouteProfile.hike;
case 'roadBike':
return RouteProfile.roadBike;
case 'trekkingBike':
return RouteProfile.trekkingBike;
case 'gravel':
return RouteProfile.gravel;
case 'mtb':
return RouteProfile.mtb;
default:
throw ArgumentError(
'Value "$name" cannot be converted to "RouteProfile"',
);
}
}
@override
String toJson() => name;
@override
String toString() => name;
}

View file

@ -0,0 +1,72 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:serverpod_client/serverpod_client.dart' as _isc;
/// Why the instance plans no route (ADR 0030, D44): `off` where it has no
/// BRouter, `invalid` for waypoints it doesn't take (fewer than two, more
/// than `Routing.maxWaypoints`, off the earth), `tooOften` beyond
/// `Routing.perMinute` plans a minute, `noRoute` where BRouter found none
/// (outside the region it holds, or no way between), `unreachable` where it
/// didn't answer.
abstract class RouteRefused
implements
_isc.SerializableException,
_isc.SerializableModel,
_isc.ProtocolSerialization {
RouteRefused._({required this.reason});
factory RouteRefused({required String reason}) = _RouteRefusedImpl;
factory RouteRefused.fromJson(Map<String, dynamic> jsonSerialization) {
return RouteRefused(reason: jsonSerialization['reason'] as String);
}
String reason;
/// Returns a shallow copy of this [RouteRefused]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
RouteRefused copyWith({String? reason});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'RouteRefused',
'reason': reason,
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'RouteRefused',
'reason': reason,
};
}
@override
String toString() {
return 'RouteRefused(reason: $reason)';
}
}
class _RouteRefusedImpl extends RouteRefused {
_RouteRefusedImpl({required String reason}) : super._(reason: reason);
/// Returns a shallow copy of this [RouteRefused]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
RouteRefused copyWith({String? reason}) {
return RouteRefused(reason: reason ?? this.reason);
}
}

View file

@ -0,0 +1,107 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:serverpod_client/serverpod_client.dart' as _isc;
/// A stretch of a route planned with what it runs on (ADR 0030, D44): its
/// length, its OpenStreetMap `surface` and `highway` where tagged.
abstract class RouteStretch
implements _isc.SerializableModel, _isc.ProtocolSerialization {
RouteStretch._({
required this.metres,
this.surface,
this.highway,
});
factory RouteStretch({
required int metres,
String? surface,
String? highway,
}) = _RouteStretchImpl;
factory RouteStretch.fromJson(Map<String, dynamic> jsonSerialization) {
return RouteStretch(
metres: jsonSerialization['metres'] as int,
surface: jsonSerialization['surface'] as String?,
highway: jsonSerialization['highway'] as String?,
);
}
int metres;
String? surface;
String? highway;
/// Returns a shallow copy of this [RouteStretch]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
RouteStretch copyWith({
int? metres,
String? surface,
String? highway,
});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'RouteStretch',
'metres': metres,
if (surface != null) 'surface': surface,
if (highway != null) 'highway': highway,
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'RouteStretch',
'metres': metres,
if (surface != null) 'surface': surface,
if (highway != null) 'highway': highway,
};
}
@override
String toString() {
return _isc.SerializationManager.encode(this);
}
}
class _Undefined {}
class _RouteStretchImpl extends RouteStretch {
_RouteStretchImpl({
required int metres,
String? surface,
String? highway,
}) : super._(
metres: metres,
surface: surface,
highway: highway,
);
/// Returns a shallow copy of this [RouteStretch]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
RouteStretch copyWith({
int? metres,
Object? surface = _Undefined,
Object? highway = _Undefined,
}) {
return RouteStretch(
metres: metres ?? this.metres,
surface: surface is String? ? surface : this.surface,
highway: highway is String? ? highway : this.highway,
);
}
}