fix deadlock with singleton NexusAPI client. We can look into this in the future, but it's still causing problems so removing the singleton for now

This commit is contained in:
Timothy Baldridge 2019-09-28 18:18:42 -06:00
parent 43b227a865
commit c9d12c7904
6 changed files with 72 additions and 79 deletions

View File

@ -131,6 +131,7 @@ namespace VFS
{
}
_isDirty = false;
CleanDB();
}
@ -257,6 +258,7 @@ namespace VFS
_isDirty = true;
_files.Remove(f.FullPath);
});
SyncToDisk();
}
}
@ -335,8 +337,12 @@ namespace VFS
lv.Analyze();
Add(lv);
if (lv.IsArchive) UpdateArchive(lv);
// Upsert after extraction incase extraction fails
if (lv.IsArchive)
{
UpdateArchive(lv);
// Upsert after extraction incase extraction fails
lv.FinishedIndexing = true;
}
}
if (lv.IsOutdated)

View File

@ -91,6 +91,7 @@
<Compile Include="Consts.cs" />
<Compile Include="DynamicIniData.cs" />
<Compile Include="FileExtractor.cs" />
<Compile Include="GameMetaData.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SplittingStream.cs" />
<Compile Include="Utils.cs" />

View File

@ -74,17 +74,6 @@ namespace Wabbajack
public ConcurrentBag<Directive> ExtraFiles { get; private set; }
public Dictionary<string, dynamic> ModInis { get; private set; }
private NexusApiClient _nexusApiClient;
private NexusApiClient NexusApiClient {
get
{
if (_nexusApiClient == null)
_nexusApiClient = new NexusApiClient();
return _nexusApiClient;
}
}
public VirtualFileSystem VFS => VirtualFileSystem.VFS;
public List<IndexedArchive> IndexedArchives { get; private set; }
@ -238,7 +227,8 @@ namespace Wabbajack
if (IndexedArchives.Any(a => a.IniData?.General?.gameName != null))
{
var nexusClient = new NexusApiClient();
if (!nexusClient.IsPremium) Info($"User {nexusClient.Username} is not a premium Nexus user, cannot continue");
var status = nexusClient.GetUserStatus();
if (!status.is_premium) Info($"User {status.user_id} is not a premium Nexus user, cannot continue");
}
@ -493,7 +483,7 @@ namespace Wabbajack
ModID = general.modID,
Version = general.version ?? "0.0.0.0"
};
var info = NexusApiClient.GetModInfo(nm);
var info = new NexusApiClient().GetModInfo(nm);
nm.Author = info.author;
nm.UploadedBy = info.uploaded_by;
nm.UploaderProfile = info.uploaded_users_profile_url;
@ -528,7 +518,6 @@ namespace Wabbajack
Info($"Checking link for {found.Name}");
var installer = new Installer(null, "");
installer.NexusClient = NexusApiClient;
if (!installer.DownloadArchive(result, false))
Error(

View File

@ -25,20 +25,6 @@ namespace Wabbajack
public class Installer
{
private string _downloadsFolder;
private NexusApiClient _nexusClient;
public NexusApiClient NexusClient
{
get
{
if (_nexusClient == null)
_nexusClient = new NexusApiClient();
return _nexusClient;
}
set => _nexusClient = value;
}
public string NexusAPIKey { get; set; }
public Installer(ModList mod_list, string output_folder)
{
@ -173,7 +159,7 @@ namespace Wabbajack
mods.PMap(mod =>
{
var er = NexusClient.EndorseMod(mod);
var er = new NexusApiClient().EndorseMod(mod);
Utils.Log($"Endorsed {mod.GameName} - {mod.ModID} - Result: {er.message}");
});
Info("Done! You may now exit the application!");
@ -416,19 +402,19 @@ namespace Wabbajack
Info("Getting Nexus API Key, if a browser appears, please accept");
if (ModList.Archives.OfType<NexusMod>().Any())
{
NexusClient = new NexusApiClient();
if (!NexusClient.IsAuthenticated)
var client = new NexusApiClient();
var status = client.GetUserStatus();
if (!client.IsAuthenticated)
{
Error(
$"Authenticating for the Nexus failed. A nexus account is required to automatically download mods.");
return;
}
if (!NexusClient.IsPremium)
if (!status.is_premium)
{
Error(
$"Automated installs with Wabbajack requires a premium nexus account. {NexusClient.Username} is not a premium account.");
$"Automated installs with Wabbajack requires a premium nexus account. {client.Username} is not a premium account.");
return;
}
}
@ -461,7 +447,7 @@ namespace Wabbajack
string url;
try
{
url = NexusClient.GetNexusDownloadLink(a, !download);
url = new NexusApiClient().GetNexusDownloadLink(a, !download);
if (!download) return true;
}
catch (Exception ex)

View File

@ -34,48 +34,62 @@ namespace Wabbajack.NexusApi
private UserStatus _userStatus;
public bool IsPremium => IsAuthenticated && _userStatus.is_premium;
public string Username => _userStatus?.name;
private static string GetApiKey()
public UserStatus UserStatus
{
// check if there exists a cached api key
var fi = new FileInfo(API_KEY_CACHE_FILE);
if (fi.Exists && fi.LastWriteTime > DateTime.Now.AddHours(-72))
get
{
return File.ReadAllText(API_KEY_CACHE_FILE);
if (_userStatus == null)
_userStatus = GetUserStatus();
return _userStatus;
}
// open a web socket to receive the api key
var guid = Guid.NewGuid();
var _websocket = new WebSocket("wss://sso.nexusmods.com")
{
SslConfiguration =
{
EnabledSslProtocols = SslProtocols.Tls12
}
};
var api_key = new TaskCompletionSource<string>();
_websocket.OnMessage += (sender, msg) => { api_key.SetResult(msg.Data); };
_websocket.Connect();
_websocket.Send("{\"id\": \"" + guid + "\", \"appid\": \"" + Consts.AppName + "\"}");
// open a web browser to get user permission
Process.Start($"https://www.nexusmods.com/sso?id={guid}&application=" + Consts.AppName);
// get the api key from the socket and cache it
api_key.Task.Wait();
var result = api_key.Task.Result;
File.WriteAllText(API_KEY_CACHE_FILE, result);
return result;
}
private UserStatus GetUserStatus()
public bool IsPremium => IsAuthenticated && UserStatus.is_premium;
public string Username => UserStatus?.name;
private static object _getAPIKeyLock = new object();
private static string GetApiKey()
{
lock (_getAPIKeyLock)
{
// check if there exists a cached api key
var fi = new FileInfo(API_KEY_CACHE_FILE);
if (fi.Exists && fi.LastWriteTime > DateTime.Now.AddHours(-72))
{
return File.ReadAllText(API_KEY_CACHE_FILE);
}
// open a web socket to receive the api key
var guid = Guid.NewGuid();
var _websocket = new WebSocket("wss://sso.nexusmods.com")
{
SslConfiguration =
{
EnabledSslProtocols = SslProtocols.Tls12
}
};
var api_key = new TaskCompletionSource<string>();
_websocket.OnMessage += (sender, msg) => { api_key.SetResult(msg.Data); };
_websocket.Connect();
_websocket.Send("{\"id\": \"" + guid + "\", \"appid\": \"" + Consts.AppName + "\"}");
// open a web browser to get user permission
Process.Start($"https://www.nexusmods.com/sso?id={guid}&application=" + Consts.AppName);
// get the api key from the socket and cache it
api_key.Task.Wait();
var result = api_key.Task.Result;
File.WriteAllText(API_KEY_CACHE_FILE, result);
return result;
}
}
public UserStatus GetUserStatus()
{
var url = "https://api.nexusmods.com/v1/users/validate.json";
return Get<UserStatus>(url);
@ -142,8 +156,6 @@ namespace Wabbajack.NexusApi
headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
headers.Add("Application-Name", Consts.AppName);
headers.Add("Application-Version", $"{Assembly.GetEntryAssembly().GetName().Version}");
_userStatus = GetUserStatus();
}
private T Get<T>(string url)

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common;
namespace Wabbajack.NexusApi
{
@ -10,9 +11,7 @@ namespace Wabbajack.NexusApi
{
public static string ConvertGameName(string gameName)
{
if (gameName == "SkyrimSE") return "skyrimspecialedition";
if (gameName == "FalloutNV") return "newvegas";
return gameName.ToLower();
return GameRegistry.GetByMO2ArchiveName(gameName)?.NexusName ?? gameName.ToLower();
}
public static string GetModURL(string argGameName, string argModId)