Skip to content

Commit

Permalink
fix: use new endpoints for banners, only send one login status request
Browse files Browse the repository at this point in the history
  • Loading branch information
goaaats committed Nov 1, 2023
1 parent 5d52c5d commit 050c3c4
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 43 deletions.
50 changes: 46 additions & 4 deletions src/XIVLauncher.Common/Game/Headlines.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
Expand All @@ -18,9 +19,6 @@ public partial class Headlines

[JsonProperty("pinned")]
public News[] Pinned { get; set; }

[JsonProperty("banner")]
public Banner[] Banner { get; set; }
}

public class Banner
Expand All @@ -30,6 +28,18 @@ public class Banner

[JsonProperty("link")]
public Uri Link { get; set; }

[JsonProperty("order_priority")]
public int? OrderPriority { get; set; }

[JsonProperty("fix_order")]
public int? FixOrder { get; set; }
}

public class BannerRoot
{
[JsonProperty("banner")]
public List<Banner> Banner { get; set; }
}

public class News
Expand All @@ -52,7 +62,7 @@ public class News

public partial class Headlines
{
public static async Task<Headlines> Get(Launcher game, ClientLanguage language, bool forceNa = false)
public static async Task<Headlines> GetNews(Launcher game, ClientLanguage language, bool forceNa = false)
{
var unixTimestamp = ApiHelpers.GetUnixMillis();
var langCode = language.GetLangCode(forceNa);
Expand All @@ -62,6 +72,38 @@ public static async Task<Headlines> Get(Launcher game, ClientLanguage language,

return JsonConvert.DeserializeObject<Headlines>(json, Converter.SETTINGS);
}

public static async Task<IReadOnlyList<Banner>> GetBanners(Launcher game, ClientLanguage language, bool forceNa = false)
{
var unixTimestamp = ApiHelpers.GetUnixMillis();
var langCode = language.GetLangCode(forceNa);
var url = $"https://frontier.ffxiv.com/v2/topics/{langCode}/banner.json?lang={langCode}&media=pcapp&_={unixTimestamp}";

var json = Encoding.UTF8.GetString(await game.DownloadAsLauncher(url, language, "application/json, text/plain, */*").ConfigureAwait(false));

return JsonConvert.DeserializeObject<BannerRoot>(json, Converter.SETTINGS).Banner;
}

public static async Task<IReadOnlyCollection<Banner>> GetMessage(Launcher game, ClientLanguage language, bool forceNa = false)
{
var unixTimestamp = ApiHelpers.GetUnixMillis();
var langCode = language.GetLangCode(forceNa);
var url = $"https://frontier.ffxiv.com/v2/notice/{langCode}/message.json?_={unixTimestamp}";

var json = Encoding.UTF8.GetString(await game.DownloadAsLauncher(url, language, "application/json, text/plain, */*").ConfigureAwait(false));

return JsonConvert.DeserializeObject<BannerRoot>(json, Converter.SETTINGS).Banner;
}

public static async Task<IReadOnlyCollection<Banner>> GetWorlds(Launcher game, ClientLanguage language)
{
var unixTimestamp = ApiHelpers.GetUnixMillis();
var url = $"https://frontier.ffxiv.com/v2/world/status.json?_={unixTimestamp}";

var json = Encoding.UTF8.GetString(await game.DownloadAsLauncher(url, language, "application/json, text/plain, */*").ConfigureAwait(false));

return JsonConvert.DeserializeObject<BannerRoot>(json, Converter.SETTINGS).Banner;
}
}

internal static class Converter
Expand Down
22 changes: 11 additions & 11 deletions src/XIVLauncher.Common/Game/Launcher.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


#nullable enable

using System;
Expand Down Expand Up @@ -38,15 +36,16 @@ public class Launcher
private readonly HttpClient client;
private readonly string frontierUrlTemplate;

private const string FALLBACK_FRONTIER_URL_TEMPLATE = "https://launcher.finalfantasyxiv.com/v620/index.html?rc_lang={0}&time={1}";

public Launcher(ISteam? steam, IUniqueIdCache uniqueIdCache, ISettings settings, string? frontierUrl = null)
public Launcher(ISteam? steam, IUniqueIdCache uniqueIdCache, ISettings settings, string frontierUrl)
{
this.steam = steam;
this.uniqueIdCache = uniqueIdCache;
this.settings = settings;
this.frontierUrlTemplate =
string.IsNullOrWhiteSpace(frontierUrl) ? FALLBACK_FRONTIER_URL_TEMPLATE : frontierUrl;

if (this.frontierUrlTemplate == null)
throw new Exception("Frontier URL template is null, this is now required");

this.frontierUrlTemplate = frontierUrl;

ServicePointManager.Expect100Continue = false;

Expand All @@ -71,7 +70,7 @@ public Launcher(ISteam? steam, IUniqueIdCache uniqueIdCache, ISettings settings,
this.client = new HttpClient(handler);
}

public Launcher(byte[] steamTicket, IUniqueIdCache uniqueIdCache, ISettings settings, string? frontierUrl = null)
public Launcher(byte[] steamTicket, IUniqueIdCache uniqueIdCache, ISettings settings, string frontierUrl)
: this(steam: null, uniqueIdCache, settings, frontierUrl)
{
this.steamTicket = steamTicket;
Expand Down Expand Up @@ -625,19 +624,19 @@ await DownloadAsLauncher(
}
}

public async Task<bool> GetLoginStatus()
public async Task<GateStatus> GetLoginStatus()
{
try
{
var reply = Encoding.UTF8.GetString(
await DownloadAsLauncher(
$"https://frontier.ffxiv.com/worldStatus/login_status.json?_={ApiHelpers.GetUnixMillis()}", ClientLanguage.English).ConfigureAwait(true));

return Convert.ToBoolean(int.Parse(reply[10].ToString()));
return JsonConvert.DeserializeObject<GateStatus>(reply);
}
catch (Exception exc)
{
throw new Exception("Could not get gate status", exc);
throw new Exception("Could not get login status", exc);
}
}

Expand Down Expand Up @@ -675,6 +674,7 @@ public async Task<byte[]> DownloadAsLauncher(string url, ClientLanguage language
request.Headers.AddWithoutValidation("Origin", "https://launcher.finalfantasyxiv.com");

request.Headers.AddWithoutValidation("Referer", GenerateFrontierReferer(language));
request.Headers.AddWithoutValidation("Connection", "Keep-Alive");

var resp = await this.client.SendAsync(request);
return await resp.Content.ReadAsByteArrayAsync();
Expand Down
2 changes: 1 addition & 1 deletion src/XIVLauncher/Windows/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
<StackPanel Orientation="Vertical"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<materialDesign:PackIcon Kind="Earth" Height="Auto"
Width="Auto" x:Name="WorldStatusPackIcon" />
Width="Auto" Foreground="{Binding WorldStatusIconColor}"/>
</StackPanel>
</Button>

Expand Down
39 changes: 15 additions & 24 deletions src/XIVLauncher/Windows/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public partial class MainWindow : Window
{
private Timer _bannerChangeTimer;
private Headlines _headlines;
private IReadOnlyList<Banner> _banners;
private BitmapImage[] _bannerBitmaps;
private int _currentBannerIndex;
private bool _everShown = false;
Expand Down Expand Up @@ -121,14 +122,20 @@ private async Task SetupHeadlines()
{
_bannerChangeTimer?.Stop();

_headlines = await Headlines.Get(_launcher, App.Settings.Language.GetValueOrDefault(ClientLanguage.English), App.Settings.ForceNorthAmerica.GetValueOrDefault(false)).ConfigureAwait(false);
await Headlines.GetWorlds(_launcher, App.Settings.Language.GetValueOrDefault(ClientLanguage.English));
_banners = await Headlines.GetBanners(_launcher, App.Settings.Language.GetValueOrDefault(ClientLanguage.English), App.Settings.ForceNorthAmerica.GetValueOrDefault(false))
.ConfigureAwait(false);
await Headlines.GetMessage(_launcher, App.Settings.Language.GetValueOrDefault(ClientLanguage.English), App.Settings.ForceNorthAmerica.GetValueOrDefault(false))
.ConfigureAwait(false);
_headlines = await Headlines.GetNews(_launcher, App.Settings.Language.GetValueOrDefault(ClientLanguage.English), App.Settings.ForceNorthAmerica.GetValueOrDefault(false))
.ConfigureAwait(false);

_bannerBitmaps = new BitmapImage[_headlines.Banner.Length];
_bannerBitmaps = new BitmapImage[_banners.Count];
_bannerDotList = new();

for (var i = 0; i < _headlines.Banner.Length; i++)
for (var i = 0; i < _banners.Count; i++)
{
var imageBytes = await _launcher.DownloadAsLauncher(_headlines.Banner[i].LsbBanner.ToString(), App.Settings.Language.GetValueOrDefault(ClientLanguage.English));
var imageBytes = await _launcher.DownloadAsLauncher(_banners[i].LsbBanner.ToString(), App.Settings.Language.GetValueOrDefault(ClientLanguage.English));

using var stream = new MemoryStream(imageBytes);

Expand Down Expand Up @@ -157,7 +164,7 @@ private async Task SetupHeadlines()
{
_bannerDotList.ToList().ForEach(x => x.Active = false);

if (_currentBannerIndex + 1 > _headlines.Banner.Length - 1)
if (_currentBannerIndex + 1 > _banners.Count - 1)
_currentBannerIndex = 0;
else
_currentBannerIndex++;
Expand All @@ -176,8 +183,9 @@ private async Task SetupHeadlines()

Dispatcher.BeginInvoke(new Action(() => { NewsListView.ItemsSource = _headlines.News; }));
}
catch (Exception)
catch (Exception ex)
{
Log.Error(ex, "Could not get news");
Dispatcher.BeginInvoke(new Action(() =>
{
NewsListView.ItemsSource = new List<News> {new News {Title = Loc.Localize("NewsDlFailed", "Could not download news data."), Tag = "DlError"}};
Expand Down Expand Up @@ -272,23 +280,6 @@ public void Initialize()

this.SetDefaults();

var worldStatusBrushOk = WorldStatusPackIcon.Foreground;
// grey out world status icon while deferred check is running
WorldStatusPackIcon.Foreground = new SolidColorBrush(Color.FromRgb(38, 38, 38));

_launcher.GetGateStatus(App.Settings.Language.GetValueOrDefault(ClientLanguage.English)).ContinueWith((resultTask) =>
{
try
{
var brushToSet = resultTask.Result.Status ? worldStatusBrushOk : null;
Dispatcher.InvokeAsync(() => WorldStatusPackIcon.Foreground = brushToSet ?? new SolidColorBrush(Color.FromRgb(242, 24, 24)));
}
catch
{
// ignored
}
});

_accountManager = new AccountManager(App.Settings);

var savedAccount = _accountManager.CurrentAccount;
Expand Down Expand Up @@ -359,7 +350,7 @@ private void BannerCard_MouseUp(object sender, MouseButtonEventArgs e)
if (e.ChangedButton != MouseButton.Left)
return;

if (_headlines != null) Process.Start(_headlines.Banner[_currentBannerIndex].Link.ToString());
if (_headlines != null) Process.Start(_banners[_currentBannerIndex].Link.ToString());
}

private void NewsListView_OnMouseUp(object sender, MouseButtonEventArgs e)
Expand Down
58 changes: 55 additions & 3 deletions src/XIVLauncher/Windows/ViewModel/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using CheapLoc;
using Serilog;
Expand All @@ -36,6 +37,9 @@ internal class MainWindowViewModel : INotifyPropertyChanged
{
private readonly Window _window;

private readonly Task<GateStatus> loginStatusTask;
private bool refetchLoginStatus = false;

public bool IsLoggingIn;

public Launcher Launcher { get; private set; }
Expand Down Expand Up @@ -71,9 +75,36 @@ public MainWindowViewModel(Window window)
LoginNoThirdCommand = new SyncCommand(GetLoginFunc(AfterLoginAction.StartWithoutThird), () => !IsLoggingIn);
LoginRepairCommand = new SyncCommand(GetLoginFunc(AfterLoginAction.Repair), () => !IsLoggingIn);

var frontierUrl = Updates.UpdateLease?.FrontierUrl;
#if DEBUG || RELEASENOUPDATE
// FALLBACK
frontierUrl ??= "https://launcher.finalfantasyxiv.com/v650/index.html?rc_lang={0}&time={1}";
#endif

Launcher = App.GlobalSteamTicket == null
? new(App.Steam, App.UniqueIdCache, CommonSettings.Instance, Updates.UpdateLease?.FrontierUrl)
: new(App.GlobalSteamTicket, App.UniqueIdCache, CommonSettings.Instance, Updates.UpdateLease?.FrontierUrl);
? new(App.Steam, App.UniqueIdCache, CommonSettings.Instance, frontierUrl)
: new(App.GlobalSteamTicket, App.UniqueIdCache, CommonSettings.Instance, frontierUrl);

// Tried and failed to get this from the theme
var worldStatusBrushOk = new SolidColorBrush(Color.FromRgb(0x21, 0x96, 0xf3));
WorldStatusIconColor = worldStatusBrushOk;

// Grey out world status icon while deferred check is running
WorldStatusIconColor = new SolidColorBrush(Color.FromRgb(38, 38, 38));

this.loginStatusTask = Launcher.GetLoginStatus();
this.loginStatusTask.ContinueWith((resultTask) =>
{
try
{
var brushToSet = resultTask.Result.Status ? worldStatusBrushOk : null;
WorldStatusIconColor = brushToSet ?? new SolidColorBrush(Color.FromRgb(242, 24, 24));
}
catch
{
// ignored
}
});
}

private Action<object> GetLoginFunc(AfterLoginAction action)
Expand Down Expand Up @@ -338,7 +369,17 @@ private async Task<bool> CheckGateStatus()
#if !DEBUG
try
{
loginStatus = await Launcher.GetLoginStatus().ConfigureAwait(false);
if (refetchLoginStatus)
{
var response = await Launcher.GetLoginStatus().ConfigureAwait(false);
loginStatus = response.Status;
}
else
{
var response = await this.loginStatusTask;
loginStatus = response.Status;
refetchLoginStatus = true;
}
}
catch (Exception ex)
{
Expand Down Expand Up @@ -1485,6 +1526,17 @@ public string LoadingDialogMessage
}
}

private SolidColorBrush _worldStatusIconColor;
public SolidColorBrush WorldStatusIconColor
{
get => _worldStatusIconColor;
set
{
_worldStatusIconColor = value;
OnPropertyChanged(nameof(WorldStatusIconColor));
}
}

#endregion

#region Localization
Expand Down

0 comments on commit 050c3c4

Please sign in to comment.