/*
* Copyright (c) 2023 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ProtonVPN.Update.Releases;
namespace ProtonVPN.Update.Updates
{
///
/// Represents app update state and an interface to update related operations.
/// Operations are performed by .
///
public class AppUpdate : IAppUpdate
{
private readonly InternalState _state;
public AppUpdate(AppUpdates appUpdates): this(
new InternalState
{
AppUpdates = appUpdates,
Releases = new List(),
NewRelease = Release.Empty
})
{
}
private AppUpdate(InternalState state)
{
_state = state;
}
public bool Available => !_state.NewRelease.IsEmpty();
public bool Ready => _state.Ready;
public string FilePath
{
get
{
if (_state.NewRelease.IsNew)
{
return _state.AppUpdates.FilePath(_state.NewRelease);
}
return string.Empty;
}
}
public string FileArguments
{
get
{
if (_state.NewRelease.IsNew)
{
return _state.NewRelease.File.Args;
}
return string.Empty;
}
}
public Version Version => _state.NewRelease.IsNew ? _state.NewRelease.Version : new Version();
public IReadOnlyList ReleaseHistory()
{
return _state.EarlyAccess ? GetAllReleases() : GetStableReleases();
}
public async Task Latest(bool earlyAccess)
{
IReadOnlyList releases = await _state.AppUpdates.ReleaseHistory(earlyAccess);
return WithReleases(releases, earlyAccess);
}
public IAppUpdate CachedLatest(bool earlyAccess)
{
return WithReleases(_state.Releases, earlyAccess);
}
public async Task Downloaded()
{
if (Available && !Ready)
{
await _state.AppUpdates.Download(_state.NewRelease);
}
return this;
}
public async Task Validated()
{
bool valid = await _state.AppUpdates.Valid(_state.NewRelease);
return WithReady(valid);
}
public async Task Started(bool auto)
{
await _state.AppUpdates.StartUpdate(_state.NewRelease);
return this;
}
private AppUpdate WithReleases(IReadOnlyList releases, bool earlyAccess)
{
Release newRelease = NewRelease(releases, earlyAccess);
bool releaseChanged = !Equals(newRelease, _state.NewRelease);
InternalState state = _state.Clone();
state.EarlyAccess = earlyAccess;
state.Releases = releases;
state.NewRelease = newRelease;
if (releaseChanged)
{
state.Ready = false;
}
return new AppUpdate(state);
}
private AppUpdate WithReady(bool ready)
{
InternalState state = _state.Clone();
state.Ready = ready;
return new AppUpdate(state);
}
private IReadOnlyList GetAllReleases()
{
return _state.Releases.ToList();
}
private IReadOnlyList GetStableReleases()
{
return _state.Releases
.SkipWhile(r => r.IsEarlyAccess && r.IsNew)
.ToList();
}
private static Release NewRelease(IEnumerable releases, bool earlyAccess)
{
return releases
.FirstOrDefault(r => r.IsNew && (!r.IsEarlyAccess || earlyAccess))
?? Release.Empty;
}
private static bool Equals(Release one, Release other)
{
return one.Version.Equals(other.Version) &&
(one.File == null && other.File == null ||
one.File != null && other.File != null && one.File.Equals(other.File));
}
}
}