@@ -303,29 +303,93 @@ class TfApiClient {
303303 }
304304 }
305305
306- Future <String > getBaseUrl () async {
307- if (_cachedBaseUrl != null ) return _cachedBaseUrl! ;
306+ Future <bool > _canReachUrl (
307+ String url, {
308+ Duration timeout = _probeTimeout,
309+ }) async {
310+ try {
311+ final response = await _http.get (Uri .parse (url)).timeout (timeout);
312+ return response.statusCode == 200 ;
313+ } catch (_) {
314+ return false ;
315+ }
316+ }
317+
318+ /// probe!
319+ Future <bool > probeServer (ServerInfo ? server) async {
320+ try {
321+ final baseUrl = await _resolveBaseUrlFor (server);
322+ return await _canReachUrl ('$baseUrl /info' );
323+ } catch (_) {
324+ return false ;
325+ }
326+ }
327+
328+ Future <bool > probeConnection () async {
329+ try {
330+ final baseUrl = await getBaseUrl ();
331+ return await _canReachUrl ('$baseUrl /info' );
332+ } catch (_) {
333+ return false ;
334+ }
335+ }
336+
337+ Future <ServerInfo ?> _loadSelectedServer () async {
308338 final prefs = await SharedPreferences .getInstance ();
309339 final serversJson = prefs.getStringList ('serversV2' );
310340 final selectedIndex = prefs.getInt ('selectedServerIndex' ) ?? 0 ;
311-
312341 if (serversJson != null && serversJson.isNotEmpty) {
313342 final idx = selectedIndex.clamp (0 , serversJson.length - 1 );
314- final serverInfo = ServerInfo .fromJson (jsonDecode (serversJson[idx]));
315- final port = serverInfo.apiPort.isNotEmpty
316- ? serverInfo.apiPort
317- : AppConstants .defaultApiPort.toString ();
318- final scheme = serverInfo.useHttps ? 'https' : 'http' ;
319- _cachedBaseUrl = '$scheme ://${serverInfo .address }:$port ' ;
320- return _cachedBaseUrl! ;
343+ return ServerInfo .fromJson (jsonDecode (serversJson[idx]));
321344 }
322- final defaultScheme =
323- AppConstants .defaultUseHttps ? 'https' : 'http' ;
324- _cachedBaseUrl =
325- '$defaultScheme ://${AppConstants .defaultServerAddress }:${AppConstants .defaultApiPort }' ;
345+ return null ;
346+ }
347+
348+ Future <String > _resolveBaseUrlFor (ServerInfo ? server) async {
349+ final address = (server != null && server.address.isNotEmpty)
350+ ? server.address
351+ : AppConstants .defaultServerAddress;
352+ final port = (server != null && server.apiPort.isNotEmpty)
353+ ? server.apiPort
354+ : AppConstants .defaultApiPort.toString ();
355+ final useHttps = server? .useHttps ?? AppConstants .defaultUseHttps;
356+
357+ if (useHttps) {
358+ final httpsUrl = 'https://$address :$port ' ;
359+ if (await _canReachUrl ('$httpsUrl /info' )) {
360+ return httpsUrl;
361+ }
362+ return 'http://$address :$port ' ;
363+ }
364+
365+ return 'http://$address :$port ' ;
366+ }
367+
368+ Future <String > getBaseUrl () async {
369+ if (_cachedBaseUrl != null ) return _cachedBaseUrl! ;
370+ final serverInfo = await _loadSelectedServer ();
371+ _cachedBaseUrl = await _resolveBaseUrlFor (serverInfo);
326372 return _cachedBaseUrl! ;
327373 }
328374
375+
376+ Future <int > resolveTcpPort () async {
377+ final serverInfo = await _loadSelectedServer ();
378+ final autoDetect =
379+ serverInfo? .autoDetectTcpPort ?? AppConstants .defaultAutoDetectTcpPort;
380+ if (autoDetect) {
381+ final config = await fetchServerInfo ();
382+ if (config != null ) return config.portTcp;
383+ }
384+ final raw = serverInfo? .tcpPort ?? '' ;
385+ return int .tryParse (raw) ?? AppConstants .defaultTcpPort;
386+ }
387+
388+ Future <bool > shouldTryWss () async {
389+ final serverInfo = await _loadSelectedServer ();
390+ return serverInfo? .tryWss ?? AppConstants .defaultTryWss;
391+ }
392+
329393 void invalidateCache () {
330394 _cachedPubKey = null ;
331395 _cachedBaseUrl = null ;
0 commit comments