Skip to content

Commit 18d033e

Browse files
committed
Nvidia: Fix plugin crash on startup if database file is corrupted #594.
- Some cleanup
1 parent 706bfc7 commit 18d033e

File tree

1 file changed

+88
-74
lines changed

1 file changed

+88
-74
lines changed

source/Library/NVIDIAGeForceNowLibrary/NVIDIAGeForceNowEnabler.cs

Lines changed: 88 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,31 @@ namespace NVIDIAGeForceNowEnabler
2626
{
2727
public class NVIDIAGeForceNowEnabler : LibraryPlugin
2828
{
29-
private static readonly ILogger logger = LogManager.GetLogger();
30-
private readonly string geforceNowWorkingPath;
31-
public readonly string geforceNowExecutablePath;
32-
private readonly string gfnDatabasePath;
33-
private Dictionary<Guid, AppStore> pluginIdToAppStoreMapper;
34-
private readonly HashSet<AppStore> appStoresToMatchByName;
35-
private bool databaseUpdatedOnGetGames = false;
36-
private Dictionary<Tuple<AppStore, string>, GeforceNowItemVariant> detectionDictionary = new Dictionary<Tuple<AppStore, string>, GeforceNowItemVariant>();
37-
38-
private NVIDIAGeForceNowEnablerSettingsViewModel settings { get; set; }
29+
private static readonly ILogger _logger = LogManager.GetLogger();
30+
31+
private readonly string _geforceNowWorkingPath;
32+
private readonly string _gfnDatabasePath;
33+
public readonly string _geforceNowExecutablePath;
34+
35+
private readonly NVIDIAGeForceNowEnablerSettingsViewModel _settings;
36+
private readonly HashSet<AppStore> _appStoresToMatchByName;
37+
38+
private Dictionary<Guid, AppStore> _pluginIdToAppStoreMapper;
39+
private Dictionary<Tuple<AppStore, string>, GeforceNowItemVariant> _detectionDictionary = new Dictionary<Tuple<AppStore, string>, GeforceNowItemVariant>();
40+
41+
private bool _databaseUpdatedOnGetGames = false;
42+
3943
public override LibraryClient Client { get; } = new NVIDIAGeForceNowClient();
4044
public override Guid Id { get; } = Guid.Parse("5f2dfd12-5f13-46fe-bcdd-64eb53ace26a");
4145
public override string Name => "NVIDIA GeForce NOW";
4246
public override string LibraryIcon { get; }
47+
4348
public NVIDIAGeForceNowEnabler(IPlayniteAPI api) : base(api)
4449
{
45-
settings = new NVIDIAGeForceNowEnablerSettingsViewModel(this);
46-
geforceNowWorkingPath = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "NVIDIA Corporation", "GeForceNOW", "CEF");
47-
geforceNowExecutablePath = Path.Combine(geforceNowWorkingPath, "GeForceNOWStreamer.exe");
48-
gfnDatabasePath = Path.Combine(GetPluginUserDataPath(), "gfnDatabase.json");
49-
Properties = new LibraryPluginProperties
50-
{
51-
HasSettings = true
52-
};
50+
_settings = new NVIDIAGeForceNowEnablerSettingsViewModel(this);
51+
_geforceNowWorkingPath = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "NVIDIA Corporation", "GeForceNOW", "CEF");
52+
_geforceNowExecutablePath = Path.Combine(_geforceNowWorkingPath, "GeForceNOWStreamer.exe");
53+
_gfnDatabasePath = Path.Combine(GetPluginUserDataPath(), "gfnDatabase.json");
5354

5455
// For some libraries, game names need to be used because the GameId provided by plugins
5556
// don't match with the StoreId used in the GeForce Now database
@@ -60,21 +61,14 @@ public NVIDIAGeForceNowEnabler(IPlayniteAPI api) : base(api)
6061

6162
// For Epic they don't share any similarity and remains to be investigated. Examples:
6263
// Epic: Pillars of Eternity - Definitive Edition, GameId: bcc75c246fe04e45b0c1f1c3fd52503a, StoreId: bc31288122a7443b818f4e77eed5ce25
63-
appStoresToMatchByName = new HashSet<AppStore>
64+
_appStoresToMatchByName = new HashSet<AppStore>
6465
{
6566
AppStore.Epic,
6667
AppStore.EA_APP,
6768
AppStore.Xbox
6869
};
6970

70-
LibraryIcon = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"icon.png");
71-
SetEnumsDictionary();
72-
LoadDatabaseFromFile();
73-
}
74-
75-
private void SetEnumsDictionary()
76-
{
77-
pluginIdToAppStoreMapper = new Dictionary<Guid, AppStore>
71+
_pluginIdToAppStoreMapper = new Dictionary<Guid, AppStore>
7872
{
7973
[Guid.Parse("e3c26a3d-d695-4cb7-a769-5ff7612c7edd")] = AppStore.Battlenet,
8074
[Guid.Parse("0e2e793e-e0dd-4447-835c-c44a1fd506ec")] = AppStore.Bethesda,
@@ -94,53 +88,73 @@ private void SetEnumsDictionary()
9488
[Guid.Parse("7e4fbb5e-2ae3-48d4-8ba0-6b30e7a4e287")] = AppStore.Xbox
9589
//[Guid.Parse("99999999-9999-9999-9999-999999999999")] = AppStore.Wargaming
9690
};
91+
92+
LibraryIcon = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"icon.png");
93+
94+
var cachedDatabase = LoadDatabaseFromFile(_gfnDatabasePath);
95+
SetDetectionDictionary(cachedDatabase);
96+
97+
Properties = new LibraryPluginProperties
98+
{
99+
HasSettings = true
100+
};
97101
}
98102

99-
private void LoadDatabaseFromFile()
103+
private static List<GeforceNowItem> LoadDatabaseFromFile(string filePath)
100104
{
101-
if (!FileSystem.FileExists(gfnDatabasePath))
105+
if (!FileSystem.FileExists(filePath))
102106
{
103-
logger.Debug($"Database in {gfnDatabasePath} not found on startup");
104-
return;
107+
_logger.Debug($"File not found at path '{filePath}'. Returning an empty list.");
108+
return new List<GeforceNowItem>();
105109
}
106110

107-
var supportedList = Serialization.FromJsonFile<List<GeforceNowItem>>(gfnDatabasePath);
108-
logger.Debug($"Deserialized database in {gfnDatabasePath} with {supportedList.Count} entries on startup");
109-
SetDetectionDictionary(supportedList);
111+
try
112+
{
113+
_logger.Debug($"Loading data from file at '{filePath}'.");
114+
return Serialization.FromJsonFile<List<GeforceNowItem>>(filePath);
115+
}
116+
catch (Exception e)
117+
{
118+
_logger.Error(e, $"Failed to deserialize file at '{filePath}'. File will be deleted.");
119+
FileSystem.DeleteFileSafe(filePath);
120+
}
121+
122+
return new List<GeforceNowItem>();
110123
}
111124

125+
112126
public override void OnApplicationStarted(OnApplicationStartedEventArgs args)
113127
{
114-
if (settings.Settings.ExecuteOnStartup)
128+
if (_settings.Settings.ExecuteOnStartup)
115129
{
116130
UpdateDatabaseAndGamesStatus(false);
117131
}
118132
}
119133

120134
public override void OnLibraryUpdated(OnLibraryUpdatedEventArgs args)
121135
{
122-
if (settings.Settings.ExecuteOnLibraryUpdate)
136+
if (_settings.Settings.ExecuteOnLibraryUpdate)
123137
{
124-
var updateDatabase = !databaseUpdatedOnGetGames;
138+
var updateDatabase = !_databaseUpdatedOnGetGames;
125139
UpdateDatabaseAndGamesStatus(false, !updateDatabase);
126140
}
127141

128-
databaseUpdatedOnGetGames = false;
142+
_databaseUpdatedOnGetGames = false;
129143
}
130144

131145
public override IEnumerable<GameMetadata> GetGames(LibraryGetGamesArgs args)
132146
{
133147
// To prevent downloading the database again during OnLibraryUpdated event
134-
databaseUpdatedOnGetGames = false;
148+
_databaseUpdatedOnGetGames = false;
135149
var games = new List<GameMetadata>();
136-
if(!settings.Settings.ImportDatabaseAsLibrary)
150+
if(!_settings.Settings.ImportDatabaseAsLibrary)
137151
{
138152

139153
return games;
140154
}
141155

142-
databaseUpdatedOnGetGames = DownloadAndRefreshGameList(false);
143-
if (!detectionDictionary.HasItems())
156+
_databaseUpdatedOnGetGames = DownloadAndRefreshGameList(false);
157+
if (!_detectionDictionary.HasItems())
144158
{
145159
return games;
146160
}
@@ -170,7 +184,7 @@ public override IEnumerable<GameMetadata> GetGames(LibraryGetGamesArgs args)
170184

171185
public override ISettings GetSettings(bool firstRunSettings)
172186
{
173-
return settings;
187+
return _settings;
174188
}
175189

176190
public override UserControl GetSettingsView(bool firstRunSettings)
@@ -215,7 +229,7 @@ private void OpenEditorWindow()
215229
window.Title = ResourceProvider.GetString("LOCNgfn_Enabler_DatabaseBrowserWindowTitle");
216230

217231
window.Content = new GfnDatabaseBrowserView();
218-
window.DataContext = new GfnDatabaseBrowserViewModel(PlayniteApi, detectionDictionary.Select(x => x.Value).ToList());
232+
window.DataContext = new GfnDatabaseBrowserViewModel(PlayniteApi, _detectionDictionary.Select(x => x.Value).ToList());
219233
window.Owner = PlayniteApi.Dialogs.GetCurrentAppWindow();
220234
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
221235

@@ -232,14 +246,14 @@ public bool DownloadAndRefreshGameList(bool showDialogs)
232246
var downloadedDatabase = GeforceNowService.GetGeforceNowDatabase();
233247
if (downloadedDatabase.Count > 0)
234248
{
235-
FileSystem.WriteStringToFile(gfnDatabasePath, Serialization.ToJson(downloadedDatabase));
249+
FileSystem.WriteStringToFile(_gfnDatabasePath, Serialization.ToJson(downloadedDatabase), true);
236250
SetDetectionDictionary(downloadedDatabase);
237251
databaseUpdated = true;
238252
}
239253
}
240254
catch (Exception e)
241255
{
242-
logger.Error(e, $"Error downloading database.");
256+
_logger.Error(e, $"Error downloading database.");
243257
if (showDialogs)
244258
{
245259
PlayniteApi.Dialogs.ShowErrorMessage(e.Message, "NVIDIA GeForce NOW Enabler");
@@ -252,7 +266,7 @@ public bool DownloadAndRefreshGameList(bool showDialogs)
252266

253267
private void SetDetectionDictionary(List<GeforceNowItem> geforceList)
254268
{
255-
detectionDictionary = new Dictionary<Tuple<AppStore, string>, GeforceNowItemVariant>();
269+
_detectionDictionary = new Dictionary<Tuple<AppStore, string>, GeforceNowItemVariant>();
256270
foreach (var geforceNowItem in geforceList)
257271
{
258272
if (geforceNowItem.Type != AppType.Game)
@@ -267,15 +281,15 @@ private void SetDetectionDictionary(List<GeforceNowItem> geforceList)
267281
continue;
268282
}
269283

270-
if (appStoresToMatchByName.Contains(itemVariant.AppStore))
284+
if (_appStoresToMatchByName.Contains(itemVariant.AppStore))
271285
{
272286
var key = Tuple.Create(itemVariant.AppStore, SatinizeGameName(itemVariant.Title));
273-
detectionDictionary[key] = itemVariant;
287+
_detectionDictionary[key] = itemVariant;
274288
}
275289
else
276290
{
277291
var key = Tuple.Create(itemVariant.AppStore, itemVariant.StoreId);
278-
detectionDictionary[key] = itemVariant;
292+
_detectionDictionary[key] = itemVariant;
279293
}
280294
}
281295
}
@@ -302,11 +316,11 @@ public void UpdateDatabaseAndGamesStatus(bool showDialogs, bool updateDatabase =
302316
{
303317
DownloadAndRefreshGameList(showDialogs);
304318
}
305-
if (!detectionDictionary.HasItems())
319+
if (!_detectionDictionary.HasItems())
306320
{
307321
// In case download failed.
308322
// Also sometimes there are issues with the api and it doesn't return any games in the response
309-
logger.Debug($"Supported games were 0 so execution was stopped");
323+
_logger.Debug($"Supported games were 0 so execution was stopped");
310324
return;
311325
}
312326

@@ -326,7 +340,7 @@ public void UpdateDatabaseAndGamesStatus(bool showDialogs, bool updateDatabase =
326340
if (PlayniteUtilities.RemoveFeatureFromGame(PlayniteApi, game, feature))
327341
{
328342
featureRemovedCount++;
329-
logger.Info(string.Format("Feature removed from \"{0}\"", game.Name));
343+
_logger.Info(string.Format("Feature removed from \"{0}\"", game.Name));
330344
}
331345
}
332346
else
@@ -335,26 +349,26 @@ public void UpdateDatabaseAndGamesStatus(bool showDialogs, bool updateDatabase =
335349
if (PlayniteUtilities.AddFeatureToGame(PlayniteApi, game, feature))
336350
{
337351
featureAddedCount++;
338-
logger.Info(string.Format("Feature added to \"{0}\"", game.Name));
352+
_logger.Info(string.Format("Feature added to \"{0}\"", game.Name));
339353
}
340354

341-
if (settings.Settings.ShowPlayActionsOnLaunch && !game.IsInstalled)
355+
if (_settings.Settings.ShowPlayActionsOnLaunch && !game.IsInstalled)
342356
{
343357
game.IsInstalled = true;
344358
setAsInstalledCount++;
345359
PlayniteApi.Database.Games.Update(game);
346-
logger.Info(string.Format("Set \"{0}\" as installed", game.Name));
360+
_logger.Info(string.Format("Set \"{0}\" as installed", game.Name));
347361
}
348362
}
349363
}
350364
}, new GlobalProgressOptions(ResourceProvider.GetString("LOCNgfn_Enabler_UpdatingProgressMessage")));
351365

352-
logger.Info($"Found {enabledGamesCount} enabled games. Added feature to {featureAddedCount} games and removed it from {featureRemovedCount} games. Set {setAsInstalledCount} as installed.");
366+
_logger.Info($"Found {enabledGamesCount} enabled games. Added feature to {featureAddedCount} games and removed it from {featureRemovedCount} games. Set {setAsInstalledCount} as installed.");
353367
if (showDialogs)
354368
{
355369
var results = string.Format(ResourceProvider.GetString("LOCNgfn_Enabler_UpdateResults1Message"),
356370
enabledGamesCount, featureName, featureAddedCount, featureName, featureRemovedCount);
357-
if (settings.Settings.ShowPlayActionsOnLaunch)
371+
if (_settings.Settings.ShowPlayActionsOnLaunch)
358372
{
359373
results += string.Format(ResourceProvider.GetString("LOCNgfn_Enabler_UpdateResults3Message"), setAsInstalledCount);
360374
}
@@ -370,20 +384,20 @@ public void UpdateDatabaseAndGamesStatus(bool showDialogs, bool updateDatabase =
370384

371385
private GeforceNowItemVariant GetDatabaseMatchingEntryForGame(Game game)
372386
{
373-
if (pluginIdToAppStoreMapper.TryGetValue(game.PluginId, out var appStore))
387+
if (_pluginIdToAppStoreMapper.TryGetValue(game.PluginId, out var appStore))
374388
{
375-
if (appStoresToMatchByName.Contains(appStore))
389+
if (_appStoresToMatchByName.Contains(appStore))
376390
{
377391
var key = Tuple.Create(appStore, SatinizeGameName(game.Name));
378-
if (detectionDictionary.TryGetValue(key, out var itemVariant))
392+
if (_detectionDictionary.TryGetValue(key, out var itemVariant))
379393
{
380394
return itemVariant;
381395
}
382396
}
383397
else
384398
{
385399
var key = Tuple.Create(appStore, game.GameId);
386-
if (detectionDictionary.TryGetValue(key, out var itemVariant))
400+
if (_detectionDictionary.TryGetValue(key, out var itemVariant))
387401
{
388402
return itemVariant;
389403
}
@@ -400,11 +414,11 @@ public override IEnumerable<PlayController> GetPlayActions(GetPlayActionsArgs ar
400414
{
401415
return new List<PlayController>()
402416
{
403-
new NVIDIAGeForceNowEnablerPlayController(game, game.GameId, geforceNowExecutablePath, geforceNowWorkingPath)
417+
new NVIDIAGeForceNowEnablerPlayController(game, game.GameId, _geforceNowExecutablePath, _geforceNowWorkingPath)
404418
};
405419
}
406420

407-
if (!settings.Settings.ShowPlayActionsOnLaunch)
421+
if (!_settings.Settings.ShowPlayActionsOnLaunch)
408422
{
409423
return null;
410424
}
@@ -418,42 +432,42 @@ public override IEnumerable<PlayController> GetPlayActions(GetPlayActionsArgs ar
418432
// Library plugins set the game installation directory when they are
419433
// detected as installed. This is used to detect this and not show the Play
420434
// Action if it is detected as installed by the game library plugin.
421-
if (settings.Settings.OnlyShowActionsForNotLibInstalledGames && !game.InstallDirectory.IsNullOrEmpty())
435+
if (_settings.Settings.OnlyShowActionsForNotLibInstalledGames && !game.InstallDirectory.IsNullOrEmpty())
422436
{
423-
logger.Debug("Game install dir was not empty and was skipped");
437+
_logger.Debug("Game install dir was not empty and was skipped");
424438
return null;
425439
}
426440

427-
if (!FileSystem.FileExists(geforceNowExecutablePath))
441+
if (!FileSystem.FileExists(_geforceNowExecutablePath))
428442
{
429-
logger.Debug("Geforce Now Executable was not detected");
443+
_logger.Debug("Geforce Now Executable was not detected");
430444
PlayniteApi.Notifications.Add(new NotificationMessage(
431445
"gfnExeNotFound",
432-
string.Format(ResourceProvider.GetString("LOCNgfn_Enabler_NotificationMessage"), geforceNowExecutablePath),
446+
string.Format(ResourceProvider.GetString("LOCNgfn_Enabler_NotificationMessage"), _geforceNowExecutablePath),
433447
NotificationType.Error,
434448
() => ProcessStarter.StartUrl(@"https://github.com/darklinkpower/PlayniteExtensionsCollection/wiki/NVIDIA-GeForce-NOW-Enabler#nvidia-geforce-now-executable-not-found-error-notification")
435449
));
436450
return null;
437451
}
438452

439-
if (!detectionDictionary.HasItems())
453+
if (!_detectionDictionary.HasItems())
440454
{
441-
logger.Debug("Supported list was not set");
455+
_logger.Debug("Supported list was not set");
442456
return null;
443457
}
444458

445459
var supportedGame = GetDatabaseMatchingEntryForGame(game);
446460
if (supportedGame != null)
447461
{
448-
logger.Debug($"Database entry with id {supportedGame.Id} found on startup for game {game.Name}");
462+
_logger.Debug($"Database entry with id {supportedGame.Id} found on startup for game {game.Name}");
449463
return new List<PlayController>()
450464
{
451-
new NVIDIAGeForceNowEnablerPlayController(game, supportedGame.Id.ToString(), geforceNowExecutablePath, geforceNowWorkingPath)
465+
new NVIDIAGeForceNowEnablerPlayController(game, supportedGame.Id.ToString(), _geforceNowExecutablePath, _geforceNowWorkingPath)
452466
};
453467
}
454468
else
455469
{
456-
logger.Debug($"Database entry with for {game.Name} with pluginId {game.PluginId} not found");
470+
_logger.Debug($"Database entry with for {game.Name} with pluginId {game.PluginId} not found");
457471
}
458472

459473
return null;

0 commit comments

Comments
 (0)