public override void Set(IniFile file) { try { var trackId = file["RACE"].GetNonEmpty("TRACK"); var configurationId = file["RACE"].GetNonEmpty("CONFIG_TRACK"); var track = TracksManager.Instance.GetLayoutById(trackId ?? string.Empty, configurationId); file["LIGHTING"].Remove("__TRACK_GEOTAG_LAT"); file["LIGHTING"].Remove("__TRACK_GEOTAG_LAT"); file["LIGHTING"].Remove("__TRACK_TIMEZONE_OFFSET"); if (track == null) { return; } var trackGeoTags = track.GeoTags; if (trackGeoTags == null || trackGeoTags.IsEmptyOrInvalid) { trackGeoTags = TracksLocator.TryToLocateAsync(track).Result; Logging.Write("Track geo tags: " + trackGeoTags); } file["LIGHTING"].Set("__TRACK_GEOTAG_LAT", trackGeoTags?.LatitudeValue); file["LIGHTING"].Set("__TRACK_GEOTAG_LONG", trackGeoTags?.LongitudeValue); var data = DataProvider.Instance.TrackParams[track.MainTrackObject.Id]; if (data.ContainsKey(@"TIMEZONE")) { var timeZone = TZConvert.GetTimeZoneInfo(data.GetNonEmpty("TIMEZONE")); if (timeZone != null) { var dateUnix = file["LIGHTING"].GetLong("__CM_DATE", 0); var date = dateUnix == 0 ? DateTime.Now : dateUnix.ToDateTime(); file["LIGHTING"].Set("__TRACK_TIMEZONE_BASE_OFFSET", timeZone.BaseUtcOffset.TotalSeconds); file["LIGHTING"].Set("__TRACK_TIMEZONE_OFFSET", timeZone.GetUtcOffset(date).TotalSeconds); file["LIGHTING"].Set("__TRACK_TIMEZONE_DTS", timeZone.IsDaylightSavingTime(date)); Logging.Write("Track time zone: " + timeZone + ", daylight saving time: " + timeZone.IsDaylightSavingTime(date) + ", date: " + date); return; } } if (trackGeoTags != null) { var timeZone = TimeZoneDeterminer.TryToDetermineAsync(trackGeoTags).Result; if (timeZone != null) { var dateUnix = file["LIGHTING"].GetLong("__CM_DATE", 0); var date = dateUnix == 0 ? DateTime.Now : dateUnix.ToDateTime(); file["LIGHTING"].Set("__TRACK_TIMEZONE_BASE_OFFSET", timeZone.BaseUtcOffset.TotalSeconds); file["LIGHTING"].Set("__TRACK_TIMEZONE_OFFSET", timeZone.GetUtcOffset(date).TotalSeconds); file["LIGHTING"].Set("__TRACK_TIMEZONE_DTS", timeZone.IsDaylightSavingTime(date)); Logging.Write("Track time zone: " + timeZone + ", daylight saving time: " + timeZone.IsDaylightSavingTime(date) + ", date: " + date); } } } catch (Exception e) { Logging.Error(e); } }
/// <summary> /// Complex method, but it’s the best I can think of for now. Due to async nature, /// all results will be returned in callbacks. There is no guarantee in which order callbacks /// will be called (and even if they will be called at all or not)! /// </summary> /// <param name="track">Track for which conditions will be loaded.</param> /// <param name="localWeather">Use local weather instead.</param> /// <param name="considerTimezones">Consider timezones while setting time. Be careful: you’ll get an unclamped time!</param> /// <param name="timeCallback">Set to null if you don’t need an automatic time.</param> /// <param name="weatherCallback">Set to null if you don’t need weather.</param> /// <param name="cancellation">Cancellation token.</param> /// <returns>Task.</returns> public static async Task UpdateConditions(TrackObjectBase track, bool localWeather, bool considerTimezones, [CanBeNull] Action <int> timeCallback, [CanBeNull] Action <WeatherDescription> weatherCallback, CancellationToken cancellation) { GeoTagsEntry trackGeoTags = null, localGeoTags = null; if (!localWeather || considerTimezones && timeCallback != null) { trackGeoTags = track.GeoTags; if (trackGeoTags == null || trackGeoTags.IsEmptyOrInvalid) { trackGeoTags = await TracksLocator.TryToLocateAsync(track); if (cancellation.IsCancellationRequested) { return; } } } if ((trackGeoTags == null || localWeather) && !string.IsNullOrWhiteSpace(SettingsHolder.Drive.LocalAddress)) { localGeoTags = await TracksLocator.TryToLocateAsync(SettingsHolder.Drive.LocalAddress); if (cancellation.IsCancellationRequested) { return; } } // Time var time = DateTime.Now.TimeOfDay.TotalSeconds.RoundToInt(); if (timeCallback != null) { if (trackGeoTags == null || !considerTimezones) { timeCallback.Invoke(time); } else { var timeZone = await TimeZoneDeterminer.TryToDetermineAsync(trackGeoTags); if (cancellation.IsCancellationRequested) { return; } timeCallback.Invoke((time + (int)(timeZone == null ? 0 : timeZone.BaseUtcOffset.TotalSeconds - TimeZoneInfo.Local.BaseUtcOffset.TotalSeconds) + SecondsPerDay) % SecondsPerDay); } } // Weather var tags = localWeather ? localGeoTags : trackGeoTags ?? localGeoTags; if (tags == null) { return; } var weather = await WeatherProvider.TryToGetWeatherAsync(tags); if (cancellation.IsCancellationRequested) { return; } if (weather != null) { weatherCallback?.Invoke(weather); } }
/// <summary> /// Complex method, but it’s the best I can think of for now. Due to async nature, /// all results will be returned in callbacks. There is no guarantee in which order callbacks /// will be called (and even if they will be called at all or not)! /// </summary> /// <param name="track">Track for which conditions will be loaded.</param> /// <param name="localWeather">Use local weather instead.</param> /// <param name="considerTimezones">Consider timezones while setting time. Be careful: you’ll get an unclamped time!</param> /// <param name="dateTimeCallback">Set to null if you don’t need an automatic time.</param> /// <param name="weatherCallback">Set to null if you don’t need weather.</param> /// <param name="cancellation">Cancellation token.</param> /// <returns>Task.</returns> public static async Task UpdateConditions(TrackObjectBase track, bool localWeather, bool considerTimezones, [CanBeNull] Action <DateTime> dateTimeCallback, [CanBeNull] Action <WeatherDescription> weatherCallback, CancellationToken cancellation) { GeoTagsEntry trackGeoTags = null, localGeoTags = null; if (!localWeather || considerTimezones && dateTimeCallback != null) { trackGeoTags = track.GeoTags; if (trackGeoTags == null || trackGeoTags.IsEmptyOrInvalid) { trackGeoTags = await TracksLocator.TryToLocateAsync(track); if (cancellation.IsCancellationRequested) { return; } } } if ((trackGeoTags == null || localWeather) && !string.IsNullOrWhiteSpace(SettingsHolder.Drive.LocalAddress)) { localGeoTags = await TracksLocator.TryToLocateAsync(SettingsHolder.Drive.LocalAddress); if (cancellation.IsCancellationRequested) { return; } } // Time var now = DateTime.Now; if (dateTimeCallback != null) { if (trackGeoTags == null || !considerTimezones) { dateTimeCallback.Invoke(now); } else { var data = DataProvider.Instance.TrackParams[track.MainTrackObject.Id]; var timeZone = data.ContainsKey(@"TIMEZONE") ? TZConvert.GetTimeZoneInfo(data.GetNonEmpty("TIMEZONE")) : await TimeZoneDeterminer.TryToDetermineAsync(trackGeoTags); if (cancellation.IsCancellationRequested) { return; } var offsetInSeconds = (int)(timeZone == null ? 0 : timeZone.BaseUtcOffset.TotalSeconds - TimeZoneInfo.Local.BaseUtcOffset.TotalSeconds); dateTimeCallback.Invoke(now + TimeSpan.FromSeconds(offsetInSeconds)); } } // Weather var tags = localWeather ? localGeoTags : trackGeoTags ?? localGeoTags; if (tags == null) { return; } var weather = await WeatherProvider.TryToGetWeatherAsync(tags); if (cancellation.IsCancellationRequested) { return; } if (weather != null) { weatherCallback?.Invoke(weather); } }