Buckets:

immErfanrajabee/bd / Core /Services /GeolocationService.cs
imerfanrajabee's picture
download
raw
18.6 kB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Extensions.Logging;
using static BlockchainNetworkAnalyzer.App;
namespace BlockchainNetworkAnalyzer.Core.Services
{
/// <summary>
/// Comprehensive geolocation service using multiple technologies and data sources
/// </summary>
public class GeolocationService
{
private readonly ILogger<GeolocationService> _logger;
private readonly HttpClient _httpClient;
private readonly List<IGeolocationProvider> _providers;
public GeolocationService()
{
_logger = App.LoggerFactory.CreateLogger<GeolocationService>();
_httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(30)
};
_httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0");
// Initialize multiple providers for accuracy
_providers = new List<IGeolocationProvider>
{
new IPGeolocationProvider(_httpClient),
new MaxMindProvider(_httpClient),
new IPAPIProvider(_httpClient),
new IPInfoProvider(_httpClient),
new OpenCageProvider(_httpClient)
};
}
public async Task<GeolocationResult> GetLocationAsync(string ipAddress)
{
var result = new GeolocationResult
{
IPAddress = ipAddress,
Sources = new List<GeolocationSource>()
};
try
{
// Query multiple providers in parallel for accuracy
var tasks = _providers.Select(p => p.GetLocationAsync(ipAddress)).ToList();
var results = await Task.WhenAll(tasks);
// Aggregate results from multiple sources
foreach (var providerResult in results.Where(r => r != null && r.Success))
{
result.Sources.Add(new GeolocationSource
{
Provider = providerResult.ProviderName,
Latitude = providerResult.Latitude,
Longitude = providerResult.Longitude,
Accuracy = providerResult.Accuracy,
Confidence = providerResult.Confidence
});
}
// Calculate weighted average for best accuracy
result = CalculateWeightedAverage(result);
_logger.LogInformation($"Retrieved location for {ipAddress}: {result.Latitude}, {result.Longitude}");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error getting location for {ipAddress}");
}
return result;
}
private GeolocationResult CalculateWeightedAverage(GeolocationResult result)
{
if (result.Sources.Count == 0)
return result;
// Weight sources by accuracy and confidence
double totalWeight = 0;
double weightedLat = 0;
double weightedLng = 0;
foreach (var source in result.Sources)
{
var weight = source.Accuracy * source.Confidence;
weightedLat += source.Latitude * weight;
weightedLng += source.Longitude * weight;
totalWeight += weight;
}
if (totalWeight > 0)
{
result.Latitude = weightedLat / totalWeight;
result.Longitude = weightedLng / totalWeight;
result.Confidence = result.Sources.Average(s => s.Confidence);
result.Accuracy = result.Sources.Average(s => s.Accuracy);
}
else
{
result.Latitude = result.Sources.Average(s => s.Latitude);
result.Longitude = result.Sources.Average(s => s.Longitude);
}
return result;
}
public async Task<AddressInfo> GetAddressAsync(double latitude, double longitude)
{
var addressInfo = new AddressInfo
{
Latitude = latitude,
Longitude = longitude
};
try
{
// Reverse geocoding from multiple sources
var tasks = new List<Task<AddressInfo>>
{
GetAddressFromOpenCage(latitude, longitude),
GetAddressFromNominatim(latitude, longitude),
GetAddressFromGoogle(latitude, longitude)
};
var results = await Task.WhenAll(tasks);
// Use the most complete result
var bestResult = results
.Where(r => r != null && !string.IsNullOrEmpty(r.FullAddress))
.OrderByDescending(r => GetAddressCompleteness(r))
.FirstOrDefault();
if (bestResult != null)
{
addressInfo = bestResult;
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error getting address for {latitude}, {longitude}");
}
return addressInfo;
}
private async Task<AddressInfo> GetAddressFromOpenCage(double lat, double lng)
{
try
{
// OpenCage Geocoding API
var apiKey = App.Configuration["Geolocation:OpenCageAPIKey"] ?? "";
var url = $"https://api.opencagedata.com/geocode/v1/json?q={lat}+{lng}&key={apiKey}&language=fa";
var response = await _httpClient.GetStringAsync(url);
var data = JObject.Parse(response);
if (data["results"]?.First != null)
{
var result = data["results"][0];
var components = result["components"];
return new AddressInfo
{
Latitude = lat,
Longitude = lng,
FullAddress = result["formatted"]?.ToString(),
Street = components?["road"]?.ToString(),
HouseNumber = components?["house_number"]?.ToString(),
City = components?["city"]?.ToString() ?? components?["town"]?.ToString(),
Province = components?["state"]?.ToString(),
PostalCode = components?["postcode"]?.ToString(),
Country = components?["country"]?.ToString(),
Source = "OpenCage"
};
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to get address from OpenCage");
}
return null;
}
private async Task<AddressInfo> GetAddressFromNominatim(double lat, double lng)
{
try
{
// OpenStreetMap Nominatim (free, no API key required)
var url = $"https://nominatim.openstreetmap.org/reverse?format=json&lat={lat}&lon={lng}&addressdetails=1&accept-language=fa";
_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Add("User-Agent", "BlockchainNetworkAnalyzer/1.0");
var response = await _httpClient.GetStringAsync(url);
var data = JObject.Parse(response);
var address = data["address"];
if (address != null)
{
return new AddressInfo
{
Latitude = lat,
Longitude = lng,
FullAddress = data["display_name"]?.ToString(),
Street = address["road"]?.ToString(),
HouseNumber = address["house_number"]?.ToString(),
City = address["city"]?.ToString() ?? address["town"]?.ToString(),
Province = address["state"]?.ToString(),
PostalCode = address["postcode"]?.ToString(),
Country = address["country"]?.ToString(),
Source = "Nominatim"
};
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to get address from Nominatim");
}
return null;
}
private async Task<AddressInfo> GetAddressFromGoogle(double lat, double lng)
{
try
{
var apiKey = App.Configuration["Geolocation:GoogleMapsAPIKey"] ?? "";
if (string.IsNullOrEmpty(apiKey))
return null;
var url = $"https://maps.googleapis.com/maps/api/geocode/json?latlng={lat},{lng}&key={apiKey}&language=fa";
var response = await _httpClient.GetStringAsync(url);
var data = JObject.Parse(response);
if (data["results"]?.First != null)
{
var result = data["results"][0];
var addressComponents = result["address_components"];
var addressInfo = new AddressInfo
{
Latitude = lat,
Longitude = lng,
FullAddress = result["formatted_address"]?.ToString(),
Source = "Google Maps"
};
foreach (var component in addressComponents)
{
var types = component["types"].ToObject<List<string>>();
var longName = component["long_name"]?.ToString();
var shortName = component["short_name"]?.ToString();
if (types.Contains("street_number"))
addressInfo.HouseNumber = longName;
else if (types.Contains("route"))
addressInfo.Street = longName;
else if (types.Contains("locality") || types.Contains("sublocality"))
addressInfo.City = longName;
else if (types.Contains("administrative_area_level_1"))
addressInfo.Province = longName;
else if (types.Contains("postal_code"))
addressInfo.PostalCode = longName;
else if (types.Contains("country"))
addressInfo.Country = longName;
}
return addressInfo;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to get address from Google");
}
return null;
}
private int GetAddressCompleteness(AddressInfo address)
{
int score = 0;
if (!string.IsNullOrEmpty(address.FullAddress)) score += 3;
if (!string.IsNullOrEmpty(address.Street)) score += 2;
if (!string.IsNullOrEmpty(address.HouseNumber)) score += 1;
if (!string.IsNullOrEmpty(address.City)) score += 1;
if (!string.IsNullOrEmpty(address.Province)) score += 1;
if (!string.IsNullOrEmpty(address.PostalCode)) score += 1;
return score;
}
}
// Interface for geolocation providers
public interface IGeolocationProvider
{
string ProviderName { get; }
Task<GeolocationProviderResult> GetLocationAsync(string ipAddress);
}
// Provider implementations
public class IPGeolocationProvider : IGeolocationProvider
{
private readonly HttpClient _httpClient;
public string ProviderName => "IPGeolocation.io";
public IPGeolocationProvider(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<GeolocationProviderResult> GetLocationAsync(string ipAddress)
{
try
{
var apiKey = App.Configuration["Geolocation:IPGeolocationAPIKey"] ?? "";
var url = $"https://api.ipgeolocation.io/ipgeo?ip={ipAddress}&apiKey={apiKey}";
var response = await _httpClient.GetStringAsync(url);
var data = JObject.Parse(response);
return new GeolocationProviderResult
{
Success = true,
ProviderName = ProviderName,
Latitude = double.Parse(data["latitude"]?.ToString() ?? "0"),
Longitude = double.Parse(data["longitude"]?.ToString() ?? "0"),
Accuracy = 100, // meters
Confidence = 0.85
};
}
catch
{
return new GeolocationProviderResult { Success = false };
}
}
}
public class MaxMindProvider : IGeolocationProvider
{
private readonly HttpClient _httpClient;
public string ProviderName => "MaxMind GeoIP2";
public MaxMindProvider(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<GeolocationProviderResult> GetLocationAsync(string ipAddress)
{
// MaxMind implementation would go here
await Task.CompletedTask;
return new GeolocationProviderResult { Success = false };
}
}
public class IPAPIProvider : IGeolocationProvider
{
private readonly HttpClient _httpClient;
public string ProviderName => "IP-API";
public IPAPIProvider(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<GeolocationProviderResult> GetLocationAsync(string ipAddress)
{
try
{
var url = $"http://ip-api.com/json/{ipAddress}?fields=status,lat,lon";
var response = await _httpClient.GetStringAsync(url);
var data = JObject.Parse(response);
if (data["status"]?.ToString() == "success")
{
return new GeolocationProviderResult
{
Success = true,
ProviderName = ProviderName,
Latitude = double.Parse(data["lat"]?.ToString() ?? "0"),
Longitude = double.Parse(data["lon"]?.ToString() ?? "0"),
Accuracy = 500,
Confidence = 0.80
};
}
}
catch { }
return new GeolocationProviderResult { Success = false };
}
}
public class IPInfoProvider : IGeolocationProvider
{
private readonly HttpClient _httpClient;
public string ProviderName => "IPInfo.io";
public IPInfoProvider(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<GeolocationProviderResult> GetLocationAsync(string ipAddress)
{
try
{
var token = App.Configuration["Geolocation:IPInfoToken"] ?? "";
var url = $"https://ipinfo.io/{ipAddress}/json?token={token}";
var response = await _httpClient.GetStringAsync(url);
var data = JObject.Parse(response);
if (data["loc"] != null)
{
var loc = data["loc"].ToString().Split(',');
return new GeolocationProviderResult
{
Success = true,
ProviderName = ProviderName,
Latitude = double.Parse(loc[0]),
Longitude = double.Parse(loc[1]),
Accuracy = 1000,
Confidence = 0.75
};
}
}
catch { }
return new GeolocationProviderResult { Success = false };
}
}
public class OpenCageProvider : IGeolocationProvider
{
private readonly HttpClient _httpClient;
public string ProviderName => "OpenCage";
public OpenCageProvider(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<GeolocationProviderResult> GetLocationAsync(string ipAddress)
{
// Implementation using OpenCage
await Task.CompletedTask;
return new GeolocationProviderResult { Success = false };
}
}
// Result models
public class GeolocationResult
{
public string IPAddress { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Accuracy { get; set; } // in meters
public double Confidence { get; set; } // 0-1
public List<GeolocationSource> Sources { get; set; } = new List<GeolocationSource>();
public DateTime RetrievedAt { get; set; } = DateTime.Now;
}
public class GeolocationSource
{
public string Provider { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Accuracy { get; set; }
public double Confidence { get; set; }
}
public class GeolocationProviderResult
{
public bool Success { get; set; }
public string ProviderName { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Accuracy { get; set; }
public double Confidence { get; set; }
}
public class AddressInfo
{
public double Latitude { get; set; }
public double Longitude { get; set; }
public string FullAddress { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
public string City { get; set; }
public string Province { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Source { get; set; }
}
}

Xet Storage Details

Size:
18.6 kB
·
Xet hash:
6deab48d599661dfd903b2bd37e273db483b31f6b01e25c84c0dd5b9dae9280e

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.