86 lines
2.6 KiB
Dart
86 lines
2.6 KiB
Dart
/// Canonical HTTP(S) base endpoint for a Watch Together relay.
|
|
///
|
|
/// A base may include a reverse-proxy path prefix. The concrete health and
|
|
/// WebSocket routes are always appended as path segments.
|
|
final class WatchTogetherRelayEndpoint {
|
|
WatchTogetherRelayEndpoint._(this._baseUri);
|
|
|
|
static const String defaultBaseUrl = 'https://ice.plezy.app';
|
|
|
|
static final WatchTogetherRelayEndpoint defaultEndpoint = WatchTogetherRelayEndpoint._(Uri.parse(defaultBaseUrl));
|
|
|
|
final Uri _baseUri;
|
|
|
|
String get canonicalBaseUrl => _baseUri.toString();
|
|
|
|
Uri get healthUri => _appendPathSegment('health');
|
|
|
|
Uri get webSocketUri => _appendPathSegment('relay').replace(scheme: _baseUri.scheme == 'https' ? 'wss' : 'ws');
|
|
|
|
static WatchTogetherRelayEndpoint resolve(String? value) {
|
|
if (value == null || value.trim().isEmpty) return defaultEndpoint;
|
|
final endpoint = tryParseCustom(value);
|
|
if (endpoint == null) {
|
|
throw FormatException('Invalid Watch Together relay base URL');
|
|
}
|
|
return endpoint;
|
|
}
|
|
|
|
static WatchTogetherRelayEndpoint? tryParseCustom(String value) {
|
|
final trimmed = value.trim();
|
|
if (trimmed.isEmpty) return null;
|
|
|
|
final Uri uri;
|
|
try {
|
|
uri = Uri.parse(trimmed);
|
|
if (uri.hasPort && (uri.port < 1 || uri.port > 65535)) {
|
|
return null;
|
|
}
|
|
} on FormatException {
|
|
return null;
|
|
}
|
|
|
|
if ((uri.scheme != 'http' && uri.scheme != 'https') ||
|
|
!uri.isAbsolute ||
|
|
!uri.hasAuthority ||
|
|
uri.host.isEmpty ||
|
|
uri.userInfo.isNotEmpty ||
|
|
uri.hasQuery ||
|
|
uri.hasFragment) {
|
|
return null;
|
|
}
|
|
|
|
final normalized = uri.normalizePath();
|
|
var path = normalized.path;
|
|
while (path.endsWith('/')) {
|
|
path = path.substring(0, path.length - 1);
|
|
}
|
|
final hasDefaultPort =
|
|
normalized.hasPort &&
|
|
((normalized.scheme == 'http' && normalized.port == 80) ||
|
|
(normalized.scheme == 'https' && normalized.port == 443));
|
|
final canonical = Uri(
|
|
scheme: normalized.scheme,
|
|
host: normalized.host,
|
|
port: normalized.hasPort && !hasDefaultPort ? normalized.port : null,
|
|
path: path,
|
|
);
|
|
return WatchTogetherRelayEndpoint._(canonical);
|
|
}
|
|
|
|
Uri _appendPathSegment(String segment) {
|
|
final prefix = _baseUri.path;
|
|
return _baseUri.replace(path: '$prefix/$segment');
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
identical(this, other) || other is WatchTogetherRelayEndpoint && other.canonicalBaseUrl == canonicalBaseUrl;
|
|
|
|
@override
|
|
int get hashCode => canonicalBaseUrl.hashCode;
|
|
|
|
@override
|
|
String toString() => canonicalBaseUrl;
|
|
}
|