Files
waylume_server/lib/core/utils.dart

352 lines
11 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
class GeolocationData {
final String ip;
final String network;
final String version;
final String city;
final String region;
final String regionCode;
final String country;
final String countryName;
final String countryCode;
final String countryCodeIso3;
final String countryCapital;
final String countryTld;
final String continentCode;
final bool inEu;
final String postal;
final double latitude;
final double longitude;
final String timezone;
final String utcOffset;
final String countryCallingCode;
final String currency;
final String currencyName;
final String languages;
final double countryArea;
final int countryPopulation;
final String asn;
final String org;
GeolocationData({
required this.ip,
required this.network,
required this.version,
required this.city,
required this.region,
required this.regionCode,
required this.country,
required this.countryName,
required this.countryCode,
required this.countryCodeIso3,
required this.countryCapital,
required this.countryTld,
required this.continentCode,
required this.inEu,
required this.postal,
required this.latitude,
required this.longitude,
required this.timezone,
required this.utcOffset,
required this.countryCallingCode,
required this.currency,
required this.currencyName,
required this.languages,
required this.countryArea,
required this.countryPopulation,
required this.asn,
required this.org,
});
factory GeolocationData.fromJson(Map<String, dynamic> json) {
return GeolocationData(
ip: json['ip'],
network: json['network'],
version: json['version'],
city: json['city'],
region: json['region'],
regionCode: json['region_code'],
country: json['country'],
countryName: json['country_name'],
countryCode: json['country_code'],
countryCodeIso3: json['country_code_iso3'],
countryCapital: json['country_capital'],
countryTld: json['country_tld'],
continentCode: json['continent_code'],
inEu: json['in_eu'],
postal: json['postal'],
latitude: json['latitude'].toDouble(),
longitude: json['longitude'].toDouble(),
timezone: json['timezone'],
utcOffset: json['utc_offset'],
countryCallingCode: json['country_calling_code'],
currency: json['currency'],
currencyName: json['currency_name'],
languages: json['languages'],
countryArea: json['country_area'].toDouble(),
countryPopulation: json['country_population'],
asn: json['asn'],
org: json['org'],
);
}
Map<String, dynamic> toJson() {
return {
'ip': ip,
'network': network,
'version': version,
'city': city,
'region': region,
'region_code': regionCode,
'country': country,
'country_name': countryName,
'country_code': countryCode,
'country_code_iso3': countryCodeIso3,
'country_capital': countryCapital,
'country_tld': countryTld,
'continent_code': continentCode,
'in_eu': inEu,
'postal': postal,
'latitude': latitude,
'longitude': longitude,
'timezone': timezone,
'utc_offset': utcOffset,
'country_calling_code': countryCallingCode,
'currency': currency,
'currency_name': currencyName,
'languages': languages,
'country_area': countryArea,
'country_population': countryPopulation,
'asn': asn,
'org': org,
};
}
}
Future<GeolocationData> getGeolocationData() async {
// List of API configurations with their respective mappers
final apiConfigs = [
_ApiConfig(
url: 'https://ipapi.co/json/',
mapper: _mapIpapiCoResponse,
name: 'ipapi.co',
),
_ApiConfig(
url: 'http://ip-api.com/json/',
mapper: _mapIpApiResponse,
name: 'ip-api.com',
),
_ApiConfig(
url: 'https://freeipapi.com/api/json/',
mapper: _mapFreeIpApiResponse,
name: 'freeipapi.com',
),
_ApiConfig(
url: 'http://ipwhois.app/json/',
mapper: _mapIpWhoisResponse,
name: 'ipwhois.app',
),
];
Exception? lastException;
for (final config in apiConfigs) {
try {
print('Trying ${config.name}...');
final response = await http.get(
Uri.parse(config.url),
headers: {'User-Agent': 'Dart/3.0'},
).timeout(const Duration(seconds: 10));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// Check if the response indicates success (for APIs that include status)
if (data is Map<String, dynamic>) {
final status = data['status']?.toString().toLowerCase();
if (status != null && status != 'success' && status != 'ok') {
throw Exception('API returned error status: $status');
}
}
final geolocationData = config.mapper(data);
print('Successfully got data from ${config.name}');
return geolocationData;
} else {
throw Exception('HTTP ${response.statusCode}: ${response.reasonPhrase}');
}
} catch (e) {
print('Failed to get data from ${config.name}: $e');
lastException = Exception('${config.name}: $e');
// Add delay before trying next API to avoid hitting rate limits
if (config != apiConfigs.last) {
await Future.delayed(const Duration(milliseconds: 500));
}
}
}
throw lastException ?? Exception('All geolocation APIs failed');
}
class _ApiConfig {
final String url;
final GeolocationData Function(Map<String, dynamic>) mapper;
final String name;
_ApiConfig({
required this.url,
required this.mapper,
required this.name,
});
}
// Mapper for ipapi.co (primary API - has most complete data)
GeolocationData _mapIpapiCoResponse(Map<String, dynamic> json) {
return GeolocationData(
ip: json['ip'] ?? '',
network: json['network'] ?? '',
version: json['version'] ?? 'IPv4',
city: json['city'] ?? '',
region: json['region'] ?? '',
regionCode: json['region_code'] ?? '',
country: json['country'] ?? '',
countryName: json['country_name'] ?? '',
countryCode: json['country_code'] ?? '',
countryCodeIso3: json['country_code_iso3'] ?? '',
countryCapital: json['country_capital'] ?? '',
countryTld: json['country_tld'] ?? '',
continentCode: json['continent_code'] ?? '',
inEu: json['in_eu'] ?? false,
postal: json['postal'] ?? '',
latitude: (json['latitude'] ?? 0.0).toDouble(),
longitude: (json['longitude'] ?? 0.0).toDouble(),
timezone: json['timezone'] ?? '',
utcOffset: json['utc_offset'] ?? '',
countryCallingCode: json['country_calling_code'] ?? '',
currency: json['currency'] ?? '',
currencyName: json['currency_name'] ?? '',
languages: json['languages'] ?? '',
countryArea: (json['country_area'] ?? 0.0).toDouble(),
countryPopulation: json['country_population'] ?? 0,
asn: json['asn'] ?? '',
org: json['org'] ?? '',
);
}
// Mapper for ip-api.com
GeolocationData _mapIpApiResponse(Map<String, dynamic> json) {
return GeolocationData(
ip: json['query'] ?? '',
network: '', // Not provided by ip-api.com
version: json['query']?.toString().contains(':') == true ? 'IPv6' : 'IPv4',
city: json['city'] ?? '',
region: json['regionName'] ?? '',
regionCode: json['region'] ?? '',
country: json['country'] ?? '',
countryName: json['country'] ?? '',
countryCode: json['countryCode'] ?? '',
countryCodeIso3: '', // Not provided by ip-api.com
countryCapital: '', // Not provided by ip-api.com
countryTld: '', // Not provided by ip-api.com
continentCode: '', // Not provided by ip-api.com
inEu: false, // Not provided by ip-api.com
postal: json['zip'] ?? '',
latitude: (json['lat'] ?? 0.0).toDouble(),
longitude: (json['lon'] ?? 0.0).toDouble(),
timezone: json['timezone'] ?? '',
utcOffset: '', // Not provided by ip-api.com
countryCallingCode: '', // Not provided by ip-api.com
currency: '', // Not provided by ip-api.com
currencyName: '', // Not provided by ip-api.com
languages: '', // Not provided by ip-api.com
countryArea: 0.0, // Not provided by ip-api.com
countryPopulation: 0, // Not provided by ip-api.com
asn: json['as'] ?? '',
org: json['org'] ?? json['isp'] ?? '',
);
}
// Mapper for freeipapi.com
GeolocationData _mapFreeIpApiResponse(Map<String, dynamic> json) {
return GeolocationData(
ip: json['ipAddress'] ?? '',
network: '', // Not provided by freeipapi.com
version: json['ipVersion'] ?? 'IPv4',
city: json['cityName'] ?? '',
region: json['regionName'] ?? '',
regionCode: '', // Not provided by freeipapi.com
country: json['countryName'] ?? '',
countryName: json['countryName'] ?? '',
countryCode: json['countryCode'] ?? '',
countryCodeIso3: '', // Not provided by freeipapi.com
countryCapital: '', // Not provided by freeipapi.com
countryTld: '', // Not provided by freeipapi.com
continentCode: '', // Not provided by freeipapi.com
inEu: false, // Not provided by freeipapi.com
postal: json['zipCode'] ?? '',
latitude: (json['latitude'] ?? 0.0).toDouble(),
longitude: (json['longitude'] ?? 0.0).toDouble(),
timezone: json['timeZone'] ?? '',
utcOffset: '', // Not provided by freeipapi.com
countryCallingCode: '', // Not provided by freeipapi.com
currency: '', // Not provided by freeipapi.com
currencyName: '', // Not provided by freeipapi.com
languages: '', // Not provided by freeipapi.com
countryArea: 0.0, // Not provided by freeipapi.com
countryPopulation: 0, // Not provided by freeipapi.com
asn: '', // Not provided by freeipapi.com
org: json['isProxy'] == true ? 'Proxy Service' : '',
);
}
// Mapper for ipwhois.app
GeolocationData _mapIpWhoisResponse(Map<String, dynamic> json) {
return GeolocationData(
ip: json['ip'] ?? '',
network: '', // Not provided by ipwhois.app
version: json['type'] ?? 'IPv4',
city: json['city'] ?? '',
region: json['region'] ?? '',
regionCode: json['region_code'] ?? '',
country: json['country'] ?? '',
countryName: json['country'] ?? '',
countryCode: json['country_code'] ?? '',
countryCodeIso3: '', // Not provided by ipwhois.app
countryCapital: json['country_capital'] ?? '',
countryTld: '', // Not provided by ipwhois.app
continentCode: json['continent_code'] ?? '',
inEu: json['country_eu'] ?? false,
postal: '', // Not provided by ipwhois.app
latitude: (json['latitude'] ?? 0.0).toDouble(),
longitude: (json['longitude'] ?? 0.0).toDouble(),
timezone: json['timezone_name'] ?? '',
utcOffset: json['timezone_gmt'] ?? '',
countryCallingCode: json['country_phone'] ?? '',
currency: json['currency'] ?? '',
currencyName: json['currency_name'] ?? '',
languages: '', // Not provided by ipwhois.app
countryArea: 0.0, // Not provided by ipwhois.app
countryPopulation: 0, // Not provided by ipwhois.app
asn: json['asn'] ?? '',
org: json['org'] ?? json['isp'] ?? '',
);
}
/// Check if Wireguard is installed on the system.
Future<bool> isWireguardInstalled() async {
try {
var result = await Process.run('wg', ['--version']);
return result.exitCode == 0;
} catch (e) {
print('Error checking WireGuard installation: $e');
return false;
}
}
bool get kIsRunningInDocker => File('/.dockerenv').existsSync();