 7639066249
			
		
	
	7639066249
	
	
	
		
			
			some refactoring fix some stuff add http context accessor configure metrics as well commit 713d054ccb965f7adb8eafa6e3fb52853a1e6dd2 (partial, Docker only)
		
			
				
	
	
		
			139 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using MareSynchronosShared;
 | |
| using MareSynchronosShared.Services;
 | |
| using MareSynchronosShared.Utils.Configuration;
 | |
| using MaxMind.GeoIP2;
 | |
| 
 | |
| namespace MareSynchronosAuthService.Services;
 | |
| 
 | |
| public class GeoIPService : IHostedService
 | |
| {
 | |
|     private readonly ILogger<GeoIPService> _logger;
 | |
|     private readonly IConfigurationService<AuthServiceConfiguration> _mareConfiguration;
 | |
|     private bool _useGeoIP = false;
 | |
|     private string _cityFile = string.Empty;
 | |
|     private DatabaseReader? _dbReader;
 | |
|     private DateTime _dbLastWriteTime = DateTime.Now;
 | |
|     private CancellationTokenSource _fileWriteTimeCheckCts = new();
 | |
|     private bool _processingReload = false;
 | |
| 
 | |
|     public GeoIPService(ILogger<GeoIPService> logger,
 | |
|         IConfigurationService<AuthServiceConfiguration> mareConfiguration)
 | |
|     {
 | |
|         _logger = logger;
 | |
|         _mareConfiguration = mareConfiguration;
 | |
|     }
 | |
| 
 | |
|     public async Task<string> GetCountryFromIP(IHttpContextAccessor httpContextAccessor)
 | |
|     {
 | |
|         if (!_useGeoIP)
 | |
|         {
 | |
|             return "*";
 | |
|         }
 | |
| 
 | |
|         try
 | |
|         {
 | |
|             var ip = httpContextAccessor.GetIpAddress();
 | |
| 
 | |
|             using CancellationTokenSource waitCts = new();
 | |
|             waitCts.CancelAfter(TimeSpan.FromSeconds(5));
 | |
|             while (_processingReload) await Task.Delay(100, waitCts.Token).ConfigureAwait(false);
 | |
| 
 | |
|             if (_dbReader!.TryCity(ip, out var response))
 | |
|             {
 | |
|                 string? continent = response?.Continent.Code;
 | |
|                 if (!string.IsNullOrEmpty(continent) &&
 | |
|                     string.Equals(continent, "NA", StringComparison.Ordinal)
 | |
|                     && response?.Location.Longitude != null)
 | |
|                 {
 | |
|                     if (response.Location.Longitude < -102)
 | |
|                     {
 | |
|                         continent = "NA-W";
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         continent = "NA-E";
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 return continent ?? "*";
 | |
|             }
 | |
| 
 | |
|             return "*";
 | |
|         }
 | |
|         catch (Exception ex)
 | |
|         {
 | |
|             _logger.LogWarning(ex, "Error handling Geo IP country in request");
 | |
|             return "*";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public Task StartAsync(CancellationToken cancellationToken)
 | |
|     {
 | |
|         _logger.LogInformation("GeoIP module starting update task");
 | |
| 
 | |
|         var token = _fileWriteTimeCheckCts.Token;
 | |
|         _ = PeriodicReloadTask(token);
 | |
| 
 | |
|         return Task.CompletedTask;
 | |
|     }
 | |
| 
 | |
|     private async Task PeriodicReloadTask(CancellationToken token)
 | |
|     {
 | |
|         while (!token.IsCancellationRequested)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 _processingReload = true;
 | |
| 
 | |
|                 var useGeoIP = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.UseGeoIP), false);
 | |
|                 var cityFile = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.GeoIPDbCityFile), string.Empty);
 | |
|                 var lastWriteTime = new FileInfo(cityFile).LastWriteTimeUtc;
 | |
|                 if (useGeoIP && (!string.Equals(cityFile, _cityFile, StringComparison.OrdinalIgnoreCase) || lastWriteTime != _dbLastWriteTime))
 | |
|                 {
 | |
|                     _cityFile = cityFile;
 | |
|                     if (!File.Exists(_cityFile)) throw new FileNotFoundException($"Could not open GeoIP City Database, path does not exist: {_cityFile}");
 | |
|                     _dbReader?.Dispose();
 | |
|                     _dbReader = null;
 | |
|                     _dbReader = new DatabaseReader(_cityFile);
 | |
|                     _dbLastWriteTime = lastWriteTime;
 | |
| 
 | |
|                     _ = _dbReader.City("8.8.8.8").Continent;
 | |
| 
 | |
|                     _logger.LogInformation($"Loaded GeoIP city file from {_cityFile}");
 | |
| 
 | |
|                     if (_useGeoIP != useGeoIP)
 | |
|                     {
 | |
|                         _logger.LogInformation("GeoIP module is now enabled");
 | |
|                         _useGeoIP = useGeoIP;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (_useGeoIP != useGeoIP && !useGeoIP)
 | |
|                 {
 | |
|                     _logger.LogInformation("GeoIP module is now disabled");
 | |
|                     _useGeoIP = useGeoIP;
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception e)
 | |
|             {
 | |
|                 _logger.LogWarning(e, "Error during periodic GeoIP module reload task, disabling GeoIP");
 | |
|                 _useGeoIP = false;
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 _processingReload = false;
 | |
|             }
 | |
| 
 | |
|             await Task.Delay(TimeSpan.FromMinutes(1)).ConfigureAwait(false);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public Task StopAsync(CancellationToken cancellationToken)
 | |
|     {
 | |
|         _fileWriteTimeCheckCts.Cancel();
 | |
|         _fileWriteTimeCheckCts.Dispose();
 | |
|         _dbReader?.Dispose();
 | |
|         return Task.CompletedTask;
 | |
|     }
 | |
| }
 |