Ejemplo n.º 1
0
        public async Task Update(UpdateMode mode, bool background = false, bool fast = false)
        {
            if (_updating)
            {
                return;
            }
            _updating = true;
            _pingId++;

            var driversCount = -1;
            var resultStatus = ServerStatus.Ready;

            try {
                // If it’s a background update, don’t change anything in UI to avoid flashing
                if (!background)
                {
                    CurrentDrivers = null;
                    Status         = ServerStatus.Loading;
                    IsAvailable    = false;
                }

                // Reset some update-state values
                PrepareErrorsList();

                // Nothing loaded at all!
                var informationUpdated = false;
                if (!IsFullyLoaded)
                {
                    UpdateProgress = new AsyncProgressEntry(ToolsStrings.Online_LoadingActualInformation, 0.1);

                    ServerInformationComplete loaded;
                    try {
                        loaded = await GetInformationDirectly();
                    } catch (HttpRequestException e) {
                        if (e.InnerException is WebException webException)
                        {
                            _updateWebException = webException;
                        }
                        else
                        {
                            _updateException = e;
                        }
                        resultStatus = ServerStatus.Error;
                        return;
                    } catch (WebException e) {
                        _updateWebException = e;
                        resultStatus        = ServerStatus.Error;
                        return;
                    }

                    var update = UpdateValues(loaded, false, true);
                    if (update != null)
                    {
                        resultStatus = update.Value;
                        if (update != ServerStatus.MissingContent)
                        {
                            // Loaded data isn’t for this server (port by which it was loaded differs).
                            // Won’t even set drivers count in this case, whole data is obviously wrong.
                            return;
                        }
                    }

                    driversCount = loaded.Clients;

                    // Set this flag to True so we won’t use GetInformationDirectly() again later
                    informationUpdated = true;
                }

                // Extended mode for server wrapping thing
                var informationLoadedExtended         = false;
                ServerCarsInformation carsInformation = null;

                if (DetailsPort != null)
                {
                    try {
                        var extended = await GetExtendedInformationDirectly();

                        var update = UpdateValues(extended, false, true);

                        if (update != null)
                        {
                            resultStatus = update.Value;
                            if (update != ServerStatus.MissingContent)
                            {
                                UpdateValuesExtended(null);
                                return;
                            }
                        }

                        UpdateValuesExtended(extended);

                        driversCount              = extended.Clients;
                        carsInformation           = extended.Players;
                        informationLoadedExtended = true;
                    } catch (Exception e) {
                        Logging.Warning(e);
                        DetailsPort = null;
                        UpdateValuesExtended(null);
                        return;
                    }
                }
                else if (DetailsId != null)
                {
                    try {
                        var extended = await CmApiProvider.GetOnlineDataAsync(DetailsId);

                        if (extended != null)
                        {
                            Country   = extended.Country?.FirstOrDefault() ?? Country;
                            CountryId = extended.Country?.ArrayElementAtOrDefault(1) ?? CountryId;
                            Sessions?.ForEach((x, i) => x.Duration = extended.Durations?.ElementAtOrDefault(i) ?? x.Duration);
                        }
                        UpdateValuesExtended(extended);
                    } catch (Exception e) {
                        Logging.Warning(e);
                        UpdateValuesExtended(null);
                        return;
                    }
                }
                else
                {
                    UpdateValuesExtended(null);
                }

                // Update information
                if (!informationLoadedExtended && (mode != UpdateMode.Lite ||
                                                   !(Sessions?.Count > 0) // if there are no sessions (!), maybe information is damaged, let’s re-download
                                                   ))
                {
                    UpdateProgress = new AsyncProgressEntry(ToolsStrings.Online_LoadingActualInformation, 0.2);

                    ServerInformationComplete loaded;
                    try {
                        // If informationUpdated is True and settings set to update-information-directly mode, this method
                        // will return 0.
                        loaded = await GetInformation(informationUpdated);
                    } catch (WebException e) {
                        _updateWebException = e;
                        resultStatus        = ServerStatus.Error;
                        return;
                    }

                    if (loaded != null)
                    {
                        if (loaded.Ip == Ip && loaded.PortHttp == PortHttp || informationUpdated || loaded.LoadedDirectly)
                        {
                            // If loaded information is compatible with existing, use it immediately. Otherwise — apparently,
                            // server changed — we’ll try to load an actual data directly from it later, but only if it wasn’t
                            // loaded just before that and loaded information wasn’t loaded from it.
                            var update = UpdateValues(loaded, false, true);
                            if (update != null)
                            {
                                resultStatus = update.Value;
                                if (update != ServerStatus.MissingContent)
                                {
                                    return;
                                }
                            }
                            driversCount = loaded.Clients;
                        }
                        else
                        {
                            ServerInformation directlyLoaded;
                            try {
                                directlyLoaded = await GetInformationDirectly();
                            } catch (WebException e) {
                                _updateWebException = e;
                                resultStatus        = ServerStatus.Error;
                                return;
                            }

                            var update = UpdateValues(directlyLoaded, false, true);
                            if (update != null)
                            {
                                resultStatus = update.Value;
                                if (update != ServerStatus.MissingContent)
                                {
                                    return;
                                }
                            }
                            driversCount = loaded.Clients;
                        }
                    }
                }

                // Load players list
                if (carsInformation == null)
                {
                    UpdateProgress = new AsyncProgressEntry(ToolsStrings.Online_LoadingPlayersList, 0.4);

                    try {
                        carsInformation = await KunosApiProvider.GetCarsInformationAsync(Ip, PortHttp);
                    } catch (WebException e) {
                        _updateWebException = e;
                        resultStatus        = ServerStatus.Error;
                        return;
                    }
                }

                if (!BookingMode)
                {
                    CurrentDriversCount = carsInformation.Cars.Count(x => x.IsConnected);
                    driversCount        = -1;
                }

                var currentDrivers = (BookingMode ? carsInformation.Cars : carsInformation.Cars.Where(x => x.IsConnected))
                                     .Select(x => {
                    var driver = CurrentDrivers?.FirstOrDefault(y => y.SameAs(x)) ?? new CurrentDriver(x, RequiredCspVersion != 0);
                    return(driver);
                })
                                     .ToList();
                if (CurrentDrivers == null || !CurrentDrivers.SequenceEqual(currentDrivers))
                {
                    CurrentDrivers = currentDrivers;

                    var count  = 0;
                    var booked = false;
                    foreach (var x in currentDrivers)
                    {
                        if (x.IsConnected)
                        {
                            count++;
                        }
                        if (x.IsBookedForPlayer)
                        {
                            booked = true;
                            SetSelectedCarEntry(Cars?.GetByIdOrDefault(x.CarId, StringComparison.OrdinalIgnoreCase));
                        }
                    }

                    ConnectedDrivers  = count;
                    IsBookedForPlayer = booked;
                }

                if (Cars == null)
                {
                    Logging.Unexpected();
                    _updateDriversMissing = true;
                    resultStatus          = ServerStatus.Error;
                    return;
                }

                for (int i = 0, c = Cars.Count; i < c; i++)
                {
                    var entry = Cars[i];

                    var       wrapper = entry.CarWrapper;
                    CarObject car;

                    // Load car if not loaded
                    if (wrapper != null)
                    {
                        if (wrapper.IsLoaded)
                        {
                            car = (CarObject)wrapper.Value;
                        }
                        else
                        {
                            UpdateProgress = new AsyncProgressEntry(string.Format(ToolsStrings.Online_LoadingCars, wrapper.Id), 0.5 + 0.4 * i / c);
                            await Task.Delay(fast? 10 : 50);

                            car = (CarObject)await wrapper.LoadedAsync();
                        }

                        car.SubscribeWeak(OnContentNameChanged);
                    }
                    else
                    {
                        car = null;
                    }

                    // Load skin
                    if (car?.SkinsManager.IsLoaded == false)
                    {
                        UpdateProgress = new AsyncProgressEntry(string.Format(ToolsStrings.Online_LoadingSkins, car.DisplayName), 0.5 + 0.4 * (0.5 + i) / c);

                        await Task.Delay(fast? 10 : 50);

                        await car.SkinsManager.EnsureLoadedAsync();
                    }

                    // Set next available skin
                    if (CurrentSessionType == Game.SessionType.Booking)
                    {
                        entry.SetAvailableSkinId(car?.SelectedSkin?.Id, null);
                        entry.Total       = 0;
                        entry.Available   = 0;
                        entry.IsAvailable = true;
                    }
                    else
                    {
                        var cars = carsInformation.Cars.Where(x => x.IsEntryList &&
                                                              string.Equals(x.CarId, entry.Id, StringComparison.OrdinalIgnoreCase)).ToList();
                        ServerActualCarInformation availableSkin;

                        if (BookingMode)
                        {
                            availableSkin     = cars.FirstOrDefault(x => x.IsRequestedGuid);
                            entry.Total       = 0;
                            entry.Available   = 0;
                            entry.IsAvailable = true;
                        }
                        else
                        {
                            availableSkin     = cars.FirstOrDefault(y => !y.IsConnected);
                            entry.Total       = cars.Count;
                            entry.Available   = cars.Count(y => !y.IsConnected);
                            entry.IsAvailable = entry.Available > 0;
                        }

                        entry.SetAvailableSkinId(availableSkin?.CarSkinId, RequiredCspVersion == 0 ? null : availableSkin?.CspParams);
                    }
                }

                var missingContentUpdate = UpdateMissingContentExtended(resultStatus == ServerStatus.MissingContent);
                if (missingContentUpdate.HasValue)
                {
                    resultStatus = missingContentUpdate.Value;
                }

                if (IsBookedForPlayer)
                {
                    FixedCar = true;
                }
                else
                {
                    FixedCar = false;
                    LoadSelectedCar();
                }

                // Ping server
                if (Ping == null || mode == UpdateMode.Full || !SettingsHolder.Online.PingOnlyOnce)
                {
                    if (mode == UpdateMode.Lite)
                    {
                        await TryToPing();
                    }
                    else
                    {
                        TryToPing().Ignore();
                    }
                }
            } catch (Exception e) {
                _updateException = e;
                resultStatus     = ServerStatus.Error;
                Logging.Error(e);
            } finally {
                if (driversCount != -1)
                {
                    CurrentDriversCount = driversCount;
                }

                UpdateProgress = AsyncProgressEntry.Ready;
                Status         = !SettingsHolder.Online.LoadServersWithMissingContent && resultStatus == ServerStatus.MissingContent ?
                                 ServerStatus.Error : resultStatus;
                UpdateMissingContent();
                UpdateErrorsList();
                AvailableUpdate();
                _updating = false;
            }
        }
Ejemplo n.º 2
0
        public async Task Update(UpdateMode mode, bool background = false, bool fast = false)
        {
            if (_updating)
            {
                return;
            }
            _updating = true;

            var errors       = new List <string>(3);
            var driversCount = -1;

            try {
                if (!background)
                {
                    CurrentDrivers = null;
                    Status         = ServerStatus.Loading;
                    IsAvailable    = false;
                }

                var informationUpdated = false;
                if (!IsFullyLoaded)
                {
                    UpdateProgress = new AsyncProgressEntry("Loading actual server information…", 0.1);

                    ServerInformationComplete loaded;
                    try {
                        loaded = await GetInformationDirectly();
                    } catch (WebException e) {
                        errors.Add($"Can’t load any information: {GetFailedReason(e)}.");
                        return;
                    }

                    if (UpdateValues(loaded, errors, false) != null)
                    {
                        // Loaded data isn’t for this server (port by which it was loaded differs).
                        // Won’t even set drivers count in this case, whole data is obsviously wrong.
                        return;
                    }

                    driversCount       = loaded.Clients;
                    informationUpdated = true;
                }

                if (mode != UpdateMode.Lite)
                {
                    UpdateProgress = new AsyncProgressEntry("Loading actual server information…", 0.2);

                    ServerInformationComplete loaded;
                    try {
                        loaded = await GetInformation(informationUpdated);
                    } catch (WebException e) {
                        errors.Add($"Can’t load information: {GetFailedReason(e)}.");
                        return;
                    }

                    if (loaded != null)
                    {
                        if (loaded.Ip == Ip && loaded.PortHttp == PortHttp || informationUpdated || loaded.LoadedDirectly)
                        {
                            // If loaded information is compatible with existing, use it immediately. Otherwise — apparently,
                            // server changed — we’ll try to load an actual data directly from it later, but only if it wasn’t
                            // loaded just before that and loaded information wasn’t loaded from it.
                            if (UpdateValues(loaded, errors, false) != null)
                            {
                                return;
                            }
                            driversCount = loaded.Clients;
                        }
                        else
                        {
                            ServerInformation directlyLoaded;
                            try {
                                directlyLoaded = await GetInformationDirectly();
                            } catch (WebException e) {
                                errors.Add($"Can’t load new information: {GetFailedReason(e)}.");
                                return;
                            }

                            if (UpdateValues(directlyLoaded, errors, false) != null)
                            {
                                return;
                            }
                            driversCount = loaded.Clients;
                        }
                    }
                }

                if (Ping == null || mode == UpdateMode.Full || !SettingsHolder.Online.PingOnlyOnce)
                {
                    UpdateProgress = new AsyncProgressEntry("Pinging server…", 0.3);
                    var pair = SettingsHolder.Online.ThreadsPing
                            ? await Task.Run(() => KunosApiProvider.TryToPingServer(Ip, Port, SettingsHolder.Online.PingTimeout))
                            : await KunosApiProvider.TryToPingServerAsync(Ip, Port, SettingsHolder.Online.PingTimeout);

                    if (pair != null)
                    {
                        Ping = (long)pair.Item2.TotalMilliseconds;
                    }
                    else
                    {
                        Ping = null;
                        errors.Add(ToolsStrings.Online_Server_CannotPing);
                        return;
                    }
                }

                UpdateProgress = new AsyncProgressEntry("Loading players list…", 0.4);

                ServerCarsInformation information;
                try {
                    information = await KunosApiProvider.GetCarsInformationAsync(Ip, PortHttp);
                } catch (WebException e) {
                    errors.Add($"Can’t load drivers information: {GetFailedReason(e)}.");
                    return;
                }

                if (!BookingMode)
                {
                    CurrentDriversCount = information.Cars.Count(x => x.IsConnected);
                    driversCount        = -1;
                }

                var currentDrivers = (BookingMode ? information.Cars : information.Cars.Where(x => x.IsConnected))
                                     .Select(x => {
                    var driver = CurrentDrivers?.FirstOrDefault(y => y.Name == x.DriverName && y.Team == x.DriverTeam &&
                                                                y.CarId == x.CarId && y.CarSkinId == x.CarSkinId) ?? new CurrentDriver(x);
                    return(driver);
                })
                                     .ToList();
                if (CurrentDrivers == null || !CurrentDrivers.SequenceEqual(currentDrivers))
                {
                    CurrentDrivers = currentDrivers;

                    var count  = 0;
                    var booked = false;
                    foreach (var x in currentDrivers)
                    {
                        if (x.IsConnected)
                        {
                            count++;
                        }
                        if (x.IsBookedForPlayer)
                        {
                            booked = true;
                            SetSelectedCarEntry(Cars?.GetByIdOrDefault(x.CarId, StringComparison.OrdinalIgnoreCase));
                        }
                    }

                    ConnectedDrivers  = count;
                    IsBookedForPlayer = booked;
                }

                if (Cars == null)
                {
                    Logging.Unexpected();
                    errors.Add("Data is still missing");
                    return;
                }

                for (int i = 0, c = Cars.Count; i < c; i++)
                {
                    var entry = Cars[i];

                    var wrapper = entry.CarObjectWrapper;
                    if (wrapper == null)
                    {
                        continue;
                    }

                    /* load car if not loaded */
                    CarObject car;
                    if (wrapper.IsLoaded)
                    {
                        car = (CarObject)wrapper.Value;
                    }
                    else
                    {
                        UpdateProgress = new AsyncProgressEntry($"Loading cars ({wrapper.Id})…", 0.5 + 0.4 * i / c);
                        await Task.Delay(fast? 10 : 50);

                        car = (CarObject)await wrapper.LoadedAsync();
                    }

                    /* load skin */
                    if (!car.SkinsManager.IsLoaded)
                    {
                        UpdateProgress = new AsyncProgressEntry($"Loading {car.DisplayName} skins…", 0.5 + 0.4 * (0.5 + i) / c);

                        await Task.Delay(fast? 10 : 50);

                        await car.SkinsManager.EnsureLoadedAsync();
                    }

                    /* set next available skin */
                    if (CurrentSessionType == Game.SessionType.Booking)
                    {
                        entry.AvailableSkin = car.SelectedSkin;
                        entry.Total         = 0;
                        entry.Available     = 0;
                        entry.IsAvailable   = true;
                    }
                    else
                    {
                        var    cars = information.Cars.Where(x => x.IsEntryList && string.Equals(x.CarId, entry.Id, StringComparison.OrdinalIgnoreCase)).ToList();
                        string availableSkinId;

                        if (BookingMode)
                        {
                            availableSkinId   = cars.FirstOrDefault(x => x.IsRequestedGuid)?.CarSkinId;
                            entry.Total       = 0;
                            entry.Available   = 0;
                            entry.IsAvailable = true;
                        }
                        else
                        {
                            availableSkinId   = cars.FirstOrDefault(y => !y.IsConnected)?.CarSkinId;
                            entry.Total       = cars.Count;
                            entry.Available   = cars.Count(y => !y.IsConnected);
                            entry.IsAvailable = entry.Available > 0;
                        }

                        entry.AvailableSkin = availableSkinId == null
                                ? null : availableSkinId == string.Empty ? car.GetFirstSkinOrNull() : car.GetSkinById(availableSkinId);
                    }

                    // TODO: Revert back `errors.Add(ToolsStrings.Online_Server_CarsDoNotMatch);` (?)
                }

                if (IsBookedForPlayer)
                {
                    FixedCar = true;
                }
                else
                {
                    FixedCar = false;
                    LoadSelectedCar();
                }
            } catch (InformativeException e) {
                errors.Add($@"{e.Message}.");
            } catch (Exception e) {
                errors.Add(string.Format(ToolsStrings.Online_Server_UnhandledError, e.Message));
                Logging.Error(e);
            } finally {
                if (driversCount != -1)
                {
                    CurrentDriversCount = driversCount;
                }

                UpdateProgress = AsyncProgressEntry.Ready;
                Errors         = errors;
                Status         = errors.Any() ? ServerStatus.Error : ServerStatus.Ready;
                AvailableUpdate();
                _updating = false;
            }
        }