Compare commits
154 Commits
Author | SHA1 | Date |
---|---|---|
Pat Hartl | 5ef16fc4cc | |
Pat Hartl | db8d3e4bf6 | |
Pat Hartl | f2462c0d20 | |
Pat Hartl | b87fe92c63 | |
Pat Hartl | c735556281 | |
Pat Hartl | d4bcde9d28 | |
Pat Hartl | 920b6b26f7 | |
Pat Hartl | d31fccc9f3 | |
Pat Hartl | c48d5b5d59 | |
Pat Hartl | dfb9f51acd | |
Pat Hartl | 03b0d9da93 | |
Pat Hartl | e2883322e6 | |
Pat Hartl | 50eff6784f | |
Pat Hartl | 171f82df3e | |
Pat Hartl | 8b7be9157e | |
Pat Hartl | 96c6d58486 | |
Pat Hartl | fd6e3e56a4 | |
Pat Hartl | d4fe8db48d | |
Pat Hartl | 281353b86c | |
Pat Hartl | ba46970406 | |
Pat Hartl | 6fb77adb63 | |
Pat Hartl | b38f2b6cef | |
Pat Hartl | 7568688c97 | |
Pat Hartl | a8c62151f3 | |
Pat Hartl | 32e135de7b | |
Pat Hartl | c37095d4c4 | |
Pat Hartl | a716bafc4d | |
Pat Hartl | e4531321b1 | |
Pat Hartl | 78168e94a5 | |
Pat Hartl | 82779bcc72 | |
Pat Hartl | 7b625b2f60 | |
Pat Hartl | 74d8790ee2 | |
Pat Hartl | 745cf0cce6 | |
Pat Hartl | 7c22aaa139 | |
Pat Hartl | eb73885991 | |
Pat Hartl | ce80dfa51f | |
Pat Hartl | 349001d8f6 | |
Pat Hartl | d705b34f84 | |
Pat Hartl | 0246ee017c | |
Pat Hartl | 818160d658 | |
Pat Hartl | 035c98cd18 | |
Pat Hartl | d3e13aee9e | |
Pat Hartl | ce402cf5c1 | |
Pat Hartl | 3dbee36886 | |
Pat Hartl | 7793c9a1e8 | |
Pat Hartl | c4c25ad85b | |
Pat Hartl | 1d2f82fdef | |
Pat Hartl | a533e9ad8c | |
Pat Hartl | c3a5edbe46 | |
Pat Hartl | 8cc97f9bdb | |
Pat Hartl | 875b7b7caa | |
Pat Hartl | 6cc947b47e | |
Pat Hartl | a450ac4a18 | |
Pat Hartl | ffa24dbecc | |
Pat Hartl | d0d6701380 | |
Pat Hartl | ab67092c2f | |
Pat Hartl | d97e1f48b3 | |
Pat Hartl | 50badc981b | |
Pat Hartl | b863080842 | |
Pat Hartl | 8b3f2c6cde | |
Pat Hartl | 70674f900e | |
Pat Hartl | f21bf4801e | |
Pat Hartl | ead2c9c3f1 | |
Pat Hartl | fe0bdf31f6 | |
Pat Hartl | 282a1f7c36 | |
Pat Hartl | 5e3384b4fd | |
Pat Hartl | bc30cc911a | |
Pat Hartl | 737f2bec84 | |
Pat Hartl | a47b77cc5c | |
Pat Hartl | f19ef09ff8 | |
Pat Hartl | 8a408f3a18 | |
Pat Hartl | 96fd12a72f | |
Pat Hartl | 1f870366a4 | |
Pat Hartl | 2a80964fe1 | |
Pat Hartl | 6a3c55f669 | |
Pat Hartl | 1f03860360 | |
Pat Hartl | 314a785fee | |
Pat Hartl | 09d23bcb78 | |
Pat Hartl | 6b005eb384 | |
Pat Hartl | 39dd24e0ba | |
Pat Hartl | 5324723cee | |
Pat Hartl | aff2e991ed | |
Pat Hartl | 14600f5d70 | |
Pat Hartl | 35fbdd008a | |
Pat Hartl | aed9935b16 | |
Pat Hartl | 2cb7013120 | |
Pat Hartl | 7649e63195 | |
Pat Hartl | e723a5345b | |
Pat Hartl | 982227cf1f | |
Pat Hartl | 8abc2fa15e | |
Pat Hartl | ed1b4973d3 | |
Pat Hartl | 196feedded | |
Pat Hartl | 2282d9b013 | |
Pat Hartl | 1b72d9002a | |
Pat Hartl | a9f3b7a39d | |
Pat Hartl | 986fb87db1 | |
Pat Hartl | f7fa7aa9f3 | |
Pat Hartl | 49c4b10cf9 | |
Pat Hartl | 8bd422249e | |
Pat Hartl | 26f03f61fc | |
Pat Hartl | 839e9b4935 | |
Pat Hartl | c71cf9fedd | |
Pat Hartl | 86211a7500 | |
Pat Hartl | 35f6dadf9c | |
Pat Hartl | 03828bea60 | |
Pat Hartl | 8d85aca0a7 | |
Pat Hartl | 16dc60b90a | |
Pat Hartl | eb05364542 | |
Pat Hartl | 97f459eaff | |
Pat Hartl | cb9f31a00a | |
Pat Hartl | bf2c9ea45a | |
Pat Hartl | 29dcebb70f | |
Pat Hartl | baa2b9b206 | |
Pat Hartl | dc2eff4972 | |
Pat Hartl | ae23f621c2 | |
Pat Hartl | ee62bdf2a1 | |
Pat Hartl | 5fb4fadfb4 | |
Pat Hartl | 1a0cff3914 | |
Pat Hartl | 227411a558 | |
Pat Hartl | 7c97a3db57 | |
Pat Hartl | 6f7c17493c | |
Pat Hartl | 81e4848407 | |
Pat Hartl | 1ede37c031 | |
Pat Hartl | bb980cc063 | |
Pat Hartl | 47bb054fd1 | |
Pat Hartl | ea337dfea1 | |
Pat Hartl | 52a5f5866f | |
Pat Hartl | b77e7f6e53 | |
Pat Hartl | 20de9d6cae | |
Pat Hartl | 5237e88612 | |
Pat Hartl | 73b542856a | |
Pat Hartl | 39f2d4b212 | |
Pat Hartl | e53709334c | |
Pat Hartl | a679fae0cb | |
Pat Hartl | ff6f9997f5 | |
Pat Hartl | 5d5e137e18 | |
Pat Hartl | 81f8d55694 | |
Pat Hartl | c4793daf07 | |
Pat Hartl | 5c4f81cf80 | |
Pat Hartl | d111be9828 | |
Pat Hartl | 63ae3a4f2a | |
Pat Hartl | 4b40445bac | |
Pat Hartl | 25de79eeed | |
Pat Hartl | 16ba48ed6c | |
Pat Hartl | 508f5c18fb | |
Pat Hartl | 53276542e8 | |
Pat Hartl | aec4342188 | |
Pat Hartl | 2d86ff2518 | |
Pat Hartl | 4393c8fdff | |
Pat Hartl | bd15ceaa5b | |
Pat Hartl | 03626a75d0 | |
Pat Hartl | 78fb812a74 | |
Pat Hartl | 4fb11c1dd7 | |
Pat Hartl | d6eff92835 |
|
@ -1,17 +1,14 @@
|
||||||
using LANCommander.PlaynitePlugin.Helpers;
|
using LANCommander.SDK;
|
||||||
using LANCommander.SDK.Enums;
|
using LANCommander.SDK.Helpers;
|
||||||
using LANCommander.SDK.Extensions;
|
|
||||||
using LANCommander.SDK.Models;
|
using LANCommander.SDK.Models;
|
||||||
|
using LANCommander.SDK.PowerShell;
|
||||||
using Playnite.SDK;
|
using Playnite.SDK;
|
||||||
using Playnite.SDK.Models;
|
using Playnite.SDK.Models;
|
||||||
using Playnite.SDK.Plugins;
|
using Playnite.SDK.Plugins;
|
||||||
using SharpCompress.Common;
|
|
||||||
using SharpCompress.Readers;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using YamlDotNet.Serialization;
|
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin
|
namespace LANCommander.PlaynitePlugin
|
||||||
{
|
{
|
||||||
|
@ -20,15 +17,11 @@ namespace LANCommander.PlaynitePlugin
|
||||||
public static readonly ILogger Logger = LogManager.GetLogger();
|
public static readonly ILogger Logger = LogManager.GetLogger();
|
||||||
|
|
||||||
private LANCommanderLibraryPlugin Plugin;
|
private LANCommanderLibraryPlugin Plugin;
|
||||||
private PowerShellRuntime PowerShellRuntime;
|
|
||||||
private Playnite.SDK.Models.Game PlayniteGame;
|
|
||||||
|
|
||||||
public LANCommanderInstallController(LANCommanderLibraryPlugin plugin, Playnite.SDK.Models.Game game) : base(game)
|
public LANCommanderInstallController(LANCommanderLibraryPlugin plugin, Playnite.SDK.Models.Game game) : base(game)
|
||||||
{
|
{
|
||||||
Name = "Install using LANCommander";
|
Name = "Install using LANCommander";
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
PlayniteGame = game;
|
|
||||||
PowerShellRuntime = new PowerShellRuntime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Install(InstallActionArgs args)
|
public override void Install(InstallActionArgs args)
|
||||||
|
@ -43,450 +36,176 @@ namespace LANCommander.PlaynitePlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
var gameId = Guid.Parse(Game.GameId);
|
var gameId = Guid.Parse(Game.GameId);
|
||||||
var game = Plugin.LANCommander.GetGame(gameId);
|
|
||||||
|
|
||||||
Logger.Trace($"Installing game {game.Title} ({game.Id})...");
|
string installDirectory = null;
|
||||||
|
|
||||||
var result = RetryHelper.RetryOnException<ExtractionResult>(10, TimeSpan.FromMilliseconds(500), new ExtractionResult(), () =>
|
var result = Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
||||||
{
|
{
|
||||||
Logger.Trace("Attempting to download and extract game...");
|
var gameManager = new GameManager(Plugin.LANCommanderClient, Plugin.Settings.InstallDirectory);
|
||||||
return DownloadAndExtractGame(game);
|
|
||||||
|
Stopwatch stopwatch = new Stopwatch();
|
||||||
|
|
||||||
|
stopwatch.Start();
|
||||||
|
|
||||||
|
var lastTotalSize = 0d;
|
||||||
|
var speed = 0d;
|
||||||
|
|
||||||
|
gameManager.OnArchiveExtractionProgress += (long pos, long len) =>
|
||||||
|
{
|
||||||
|
if (stopwatch.ElapsedMilliseconds > 500)
|
||||||
|
{
|
||||||
|
var percent = Math.Ceiling((pos / (decimal)len) * 100);
|
||||||
|
|
||||||
|
progress.ProgressMaxValue = len;
|
||||||
|
progress.CurrentProgressValue = pos;
|
||||||
|
|
||||||
|
speed = (double)(progress.CurrentProgressValue - lastTotalSize) / (stopwatch.ElapsedMilliseconds / 1000d);
|
||||||
|
|
||||||
|
progress.Text = $"Downloading {Game.Name} ({percent}%) | {ByteSizeLib.ByteSize.FromBytes(speed).ToString("#.#")}/s";
|
||||||
|
|
||||||
|
lastTotalSize = pos;
|
||||||
|
|
||||||
|
stopwatch.Restart();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
gameManager.OnArchiveEntryExtractionProgress += (object sender, ArchiveEntryExtractionProgressArgs e) =>
|
||||||
|
{
|
||||||
|
if (progress.CancelToken != null && progress.CancelToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
gameManager.CancelInstall();
|
||||||
|
|
||||||
|
progress.IsIndeterminate = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
installDirectory = gameManager.Install(gameId);
|
||||||
|
|
||||||
|
stopwatch.Stop();
|
||||||
|
},
|
||||||
|
new GlobalProgressOptions($"Preparing to download {Game.Name}")
|
||||||
|
{
|
||||||
|
IsIndeterminate = false,
|
||||||
|
Cancelable = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.Success && !result.Canceled)
|
// Install any redistributables
|
||||||
throw new Exception("Could not extract the install archive. Retry the install or check your connection.");
|
var game = Plugin.LANCommanderClient.GetGame(gameId);
|
||||||
else if (result.Canceled)
|
|
||||||
throw new Exception("Install was canceled");
|
|
||||||
|
|
||||||
var installInfo = new GameInstallationData()
|
|
||||||
{
|
|
||||||
InstallDirectory = result.Directory
|
|
||||||
};
|
|
||||||
|
|
||||||
PlayniteGame.InstallDirectory = result.Directory;
|
|
||||||
|
|
||||||
SDK.GameManifest manifest = null;
|
|
||||||
|
|
||||||
var writeManifestSuccess = RetryHelper.RetryOnException(10, TimeSpan.FromSeconds(1), false, () =>
|
|
||||||
{
|
|
||||||
Logger.Trace("Attempting to get game manifest...");
|
|
||||||
|
|
||||||
manifest = Plugin.LANCommander.GetGameManifest(gameId);
|
|
||||||
|
|
||||||
WriteManifest(manifest, result.Directory);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!writeManifestSuccess)
|
|
||||||
throw new Exception("Could not get or write the manifest file. Retry the install or check your connection.");
|
|
||||||
|
|
||||||
Logger.Trace("Saving scripts...");
|
|
||||||
|
|
||||||
SaveScript(game, result.Directory, ScriptType.Install);
|
|
||||||
SaveScript(game, result.Directory, ScriptType.Uninstall);
|
|
||||||
SaveScript(game, result.Directory, ScriptType.NameChange);
|
|
||||||
SaveScript(game, result.Directory, ScriptType.KeyChange);
|
|
||||||
|
|
||||||
if (game.Redistributables != null && game.Redistributables.Count() > 0)
|
if (game.Redistributables != null && game.Redistributables.Count() > 0)
|
||||||
{
|
|
||||||
Logger.Trace("Installing required redistributables...");
|
|
||||||
InstallRedistributables(game);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PowerShellRuntime.RunScript(PlayniteGame, ScriptType.Install);
|
|
||||||
PowerShellRuntime.RunScript(PlayniteGame, ScriptType.NameChange, Plugin.Settings.PlayerName);
|
|
||||||
|
|
||||||
var key = Plugin.LANCommander.GetAllocatedKey(game.Id);
|
|
||||||
|
|
||||||
PowerShellRuntime.RunScript(PlayniteGame, ScriptType.KeyChange, $"\"{key}\"");
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
Plugin.UpdateGame(manifest, gameId);
|
|
||||||
|
|
||||||
Plugin.DownloadCache.Remove(gameId);
|
|
||||||
|
|
||||||
InvokeOnInstalled(new GameInstalledEventArgs(installInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ExtractionResult DownloadAndExtractGame(LANCommander.SDK.Models.Game game)
|
|
||||||
{
|
|
||||||
if (game == null)
|
|
||||||
{
|
|
||||||
Logger.Trace("Game failed to download! No game was specified!");
|
|
||||||
|
|
||||||
throw new Exception("Game failed to download!");
|
|
||||||
}
|
|
||||||
|
|
||||||
var destination = Path.Combine(Plugin.Settings.InstallDirectory, game.Title.SanitizeFilename());
|
|
||||||
|
|
||||||
Logger.Trace($"Downloading and extracting \"{game.Title}\" to path {destination}");
|
|
||||||
var result = Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(destination);
|
|
||||||
progress.ProgressMaxValue = 100;
|
|
||||||
progress.CurrentProgressValue = 0;
|
|
||||||
|
|
||||||
using (var gameStream = Plugin.LANCommander.StreamGame(game.Id))
|
|
||||||
using (var reader = ReaderFactory.Open(gameStream))
|
|
||||||
{
|
|
||||||
progress.ProgressMaxValue = gameStream.Length;
|
|
||||||
|
|
||||||
gameStream.OnProgress += (pos, len) =>
|
|
||||||
{
|
|
||||||
progress.CurrentProgressValue = pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.EntryExtractionProgress += (object sender, ReaderExtractionEventArgs<IEntry> e) =>
|
|
||||||
{
|
|
||||||
if (progress.CancelToken != null && progress.CancelToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
reader.Cancel();
|
|
||||||
progress.IsIndeterminate = true;
|
|
||||||
|
|
||||||
reader.Dispose();
|
|
||||||
gameStream.Dispose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.WriteAllToDirectory(destination, new ExtractionOptions()
|
|
||||||
{
|
|
||||||
ExtractFullPath = true,
|
|
||||||
Overwrite = true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (progress.CancelToken != null && progress.CancelToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
Logger.Trace("User cancelled the download");
|
|
||||||
|
|
||||||
if (Directory.Exists(destination))
|
|
||||||
{
|
|
||||||
Logger.Trace("Cleaning up orphaned install files after cancelled install...");
|
|
||||||
|
|
||||||
Directory.Delete(destination, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Error(ex, $"Could not extract to path {destination}");
|
|
||||||
|
|
||||||
if (Directory.Exists(destination))
|
|
||||||
{
|
|
||||||
Logger.Trace("Cleaning up orphaned install files after bad install...");
|
|
||||||
|
|
||||||
Directory.Delete(destination, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("The game archive could not be extracted. Please try again or fix the archive!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new GlobalProgressOptions($"Downloading {game.Title}...")
|
|
||||||
{
|
|
||||||
IsIndeterminate = false,
|
|
||||||
Cancelable = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
var extractionResult = new ExtractionResult
|
|
||||||
{
|
|
||||||
Canceled = result.Canceled
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!result.Canceled)
|
|
||||||
{
|
|
||||||
extractionResult.Success = true;
|
|
||||||
extractionResult.Directory = destination;
|
|
||||||
Logger.Trace($"Game successfully downloaded and extracted to {destination}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return extractionResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InstallRedistributables(LANCommander.SDK.Models.Game game)
|
|
||||||
{
|
|
||||||
foreach (var redistributable in game.Redistributables)
|
|
||||||
{
|
|
||||||
string installScriptTempFile = null;
|
|
||||||
string detectionScriptTempFile = null;
|
|
||||||
string extractTempPath = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var installScript = redistributable.Scripts.FirstOrDefault(s => s.Type == ScriptType.Install);
|
|
||||||
installScriptTempFile = SaveTempScript(installScript);
|
|
||||||
|
|
||||||
var detectionScript = redistributable.Scripts.FirstOrDefault(s => s.Type == ScriptType.DetectInstall);
|
|
||||||
detectionScriptTempFile = SaveTempScript(detectionScript);
|
|
||||||
|
|
||||||
var detectionResult = PowerShellRuntime.RunScript(detectionScriptTempFile, detectionScript.RequiresAdmin);
|
|
||||||
|
|
||||||
// Redistributable is not installed
|
|
||||||
if (detectionResult == 0)
|
|
||||||
{
|
|
||||||
if (redistributable.Archives.Count() > 0)
|
|
||||||
{
|
|
||||||
var extractionResult = DownloadAndExtractRedistributable(redistributable);
|
|
||||||
|
|
||||||
if (extractionResult.Success)
|
|
||||||
{
|
|
||||||
extractTempPath = extractionResult.Directory;
|
|
||||||
|
|
||||||
PowerShellRuntime.RunScript(installScriptTempFile, installScript.RequiresAdmin, null, extractTempPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PowerShellRuntime.RunScript(installScriptTempFile, installScript.RequiresAdmin, null, extractTempPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error(ex, $"Redistributable {redistributable.Name} failed to install");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (File.Exists(installScriptTempFile))
|
|
||||||
File.Delete(installScriptTempFile);
|
|
||||||
|
|
||||||
if (File.Exists(detectionScriptTempFile))
|
|
||||||
File.Delete(detectionScriptTempFile);
|
|
||||||
|
|
||||||
if (Directory.Exists(extractTempPath))
|
|
||||||
Directory.Delete(extractTempPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ExtractionResult DownloadAndExtractRedistributable(LANCommander.SDK.Models.Redistributable redistributable)
|
|
||||||
{
|
|
||||||
if (redistributable == null)
|
|
||||||
{
|
|
||||||
Logger.Trace("Redistributable failed to download! No redistributable was specified!");
|
|
||||||
|
|
||||||
throw new Exception("Redistributable failed to download!");
|
|
||||||
}
|
|
||||||
|
|
||||||
var destination = Path.Combine(Path.GetTempPath(), redistributable.Name.SanitizeFilename());
|
|
||||||
|
|
||||||
Logger.Trace($"Downloading and extracting \"{redistributable.Name}\" to path {destination}");
|
|
||||||
var result = Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(destination);
|
|
||||||
progress.ProgressMaxValue = 100;
|
|
||||||
progress.CurrentProgressValue = 0;
|
|
||||||
|
|
||||||
using (var redistributableStream = Plugin.LANCommander.StreamRedistributable(redistributable.Id))
|
|
||||||
using (var reader = ReaderFactory.Open(redistributableStream))
|
|
||||||
{
|
|
||||||
progress.ProgressMaxValue = redistributableStream.Length;
|
|
||||||
|
|
||||||
redistributableStream.OnProgress += (pos, len) =>
|
|
||||||
{
|
|
||||||
progress.CurrentProgressValue = pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.EntryExtractionProgress += (object sender, ReaderExtractionEventArgs<IEntry> e) =>
|
|
||||||
{
|
|
||||||
if (progress.CancelToken != null && progress.CancelToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
reader.Cancel();
|
|
||||||
progress.IsIndeterminate = true;
|
|
||||||
|
|
||||||
reader.Dispose();
|
|
||||||
redistributableStream.Dispose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.WriteAllToDirectory(destination, new ExtractionOptions()
|
|
||||||
{
|
|
||||||
ExtractFullPath = true,
|
|
||||||
Overwrite = true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (progress.CancelToken != null && progress.CancelToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
Logger.Trace("User cancelled the download");
|
|
||||||
|
|
||||||
if (Directory.Exists(destination))
|
|
||||||
{
|
|
||||||
Logger.Trace("Cleaning up orphaned install files after cancelled install...");
|
|
||||||
|
|
||||||
Directory.Delete(destination, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Error(ex, $"Could not extract to path {destination}");
|
|
||||||
|
|
||||||
if (Directory.Exists(destination))
|
|
||||||
{
|
|
||||||
Logger.Trace("Cleaning up orphaned install files after bad install...");
|
|
||||||
|
|
||||||
Directory.Delete(destination, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("The redistributable archive could not be extracted. Please try again or fix the archive!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new GlobalProgressOptions($"Downloading {redistributable.Name}...")
|
|
||||||
{
|
|
||||||
IsIndeterminate = false,
|
|
||||||
Cancelable = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
var extractionResult = new ExtractionResult
|
|
||||||
{
|
|
||||||
Canceled = result.Canceled
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!result.Canceled)
|
|
||||||
{
|
|
||||||
extractionResult.Success = true;
|
|
||||||
extractionResult.Directory = destination;
|
|
||||||
Logger.Trace($"Redistributable successfully downloaded and extracted to {destination}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return extractionResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Download(LANCommander.SDK.Models.Game game)
|
|
||||||
{
|
|
||||||
string tempFile = String.Empty;
|
|
||||||
|
|
||||||
if (game != null)
|
|
||||||
{
|
{
|
||||||
Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
||||||
{
|
{
|
||||||
progress.ProgressMaxValue = 100;
|
var redistributableManager = new RedistributableManager(Plugin.LANCommanderClient);
|
||||||
progress.CurrentProgressValue = 0;
|
|
||||||
|
|
||||||
var destination = Plugin.LANCommander.DownloadGame(game.Id, (changed) =>
|
redistributableManager.Install(game);
|
||||||
{
|
|
||||||
progress.CurrentProgressValue = changed.ProgressPercentage;
|
|
||||||
}, (complete) =>
|
|
||||||
{
|
|
||||||
progress.CurrentProgressValue = 100;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Lock the thread until download is done
|
|
||||||
while (progress.CurrentProgressValue != 100)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tempFile = destination;
|
|
||||||
},
|
},
|
||||||
new GlobalProgressOptions($"Downloading {game.Title}...")
|
new GlobalProgressOptions("Installing redistributables...")
|
||||||
{
|
{
|
||||||
IsIndeterminate = false,
|
IsIndeterminate = true,
|
||||||
Cancelable = false,
|
Cancelable = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return tempFile;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
throw new Exception("Game failed to download!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Extract(LANCommander.SDK.Models.Game game, string archivePath)
|
if (!result.Canceled && result.Error == null && !String.IsNullOrWhiteSpace(installDirectory))
|
||||||
{
|
|
||||||
var destination = Path.Combine(Plugin.Settings.InstallDirectory, game.Title.SanitizeFilename());
|
|
||||||
|
|
||||||
Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(destination);
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
|
||||||
using (var fs = File.OpenRead(archivePath))
|
Plugin.UpdateGame(manifest);
|
||||||
using (var ts = new TrackableStream(fs))
|
|
||||||
using (var reader = ReaderFactory.Open(ts))
|
var installInfo = new GameInstallationData
|
||||||
{
|
{
|
||||||
progress.ProgressMaxValue = ts.Length;
|
InstallDirectory = installDirectory,
|
||||||
ts.OnProgress += (pos, len) =>
|
};
|
||||||
{
|
|
||||||
progress.CurrentProgressValue = pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.WriteAllToDirectory(destination, new ExtractionOptions()
|
RunInstallScript(installDirectory);
|
||||||
{
|
RunNameChangeScript(installDirectory);
|
||||||
ExtractFullPath = true,
|
RunKeyChangeScript(installDirectory);
|
||||||
Overwrite = true
|
|
||||||
});
|
InvokeOnInstalled(new GameInstalledEventArgs(installInfo));
|
||||||
}
|
}
|
||||||
},
|
else if (result.Canceled)
|
||||||
new GlobalProgressOptions($"Extracting {game.Title}...")
|
|
||||||
{
|
{
|
||||||
IsIndeterminate = false,
|
var dbGame = Plugin.PlayniteApi.Database.Games.Get(Game.Id);
|
||||||
Cancelable = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
return destination;
|
dbGame.IsInstalling = false;
|
||||||
|
dbGame.IsInstalled = false;
|
||||||
|
|
||||||
|
Plugin.PlayniteApi.Database.Games.Update(dbGame);
|
||||||
|
}
|
||||||
|
else if (result.Error != null)
|
||||||
|
throw result.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteManifest(SDK.GameManifest manifest, string installDirectory)
|
private int RunInstallScript(string installDirectory)
|
||||||
{
|
{
|
||||||
var destination = Path.Combine(installDirectory, "_manifest.yml");
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install);
|
||||||
|
|
||||||
Logger.Trace($"Attempting to write manifest to path {destination}");
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
var serializer = new SerializerBuilder()
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
.WithNamingConvention(new PascalCaseNamingConvention())
|
script.AddVariable("GameManifest", manifest);
|
||||||
.Build();
|
script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress);
|
||||||
|
|
||||||
Logger.Trace("Serializing manifest...");
|
script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install));
|
||||||
var yaml = serializer.Serialize(manifest);
|
|
||||||
|
|
||||||
Logger.Trace("Writing manifest file...");
|
return script.Execute();
|
||||||
File.WriteAllText(destination, yaml);
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SaveTempScript(LANCommander.SDK.Models.Script script)
|
private int RunNameChangeScript(string installDirectory)
|
||||||
{
|
{
|
||||||
var tempPath = Path.GetTempFileName();
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange);
|
||||||
|
|
||||||
File.Move(tempPath, tempPath + ".ps1");
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
tempPath = tempPath + ".ps1";
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress);
|
||||||
|
script.AddVariable("OldPlayerAlias", "");
|
||||||
|
script.AddVariable("NewPlayerAlias", Plugin.Settings.PlayerName);
|
||||||
|
|
||||||
Logger.Trace($"Writing script {script.Name} to {tempPath}");
|
script.UseFile(path);
|
||||||
|
|
||||||
File.WriteAllText(tempPath, script.Contents);
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
return tempPath;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveScript(LANCommander.SDK.Models.Game game, string installationDirectory, ScriptType type)
|
private int RunKeyChangeScript(string installDirectory)
|
||||||
{
|
{
|
||||||
var script = game.Scripts.FirstOrDefault(s => s.Type == type);
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange);
|
||||||
|
|
||||||
if (script == null)
|
if (File.Exists(path))
|
||||||
return;
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
if (script.RequiresAdmin)
|
var key = Plugin.LANCommanderClient.GetAllocatedKey(manifest.Id);
|
||||||
script.Contents = "# Requires Admin" + "\r\n\r\n" + script.Contents;
|
|
||||||
|
|
||||||
var filename = PowerShellRuntime.GetScriptFilePath(PlayniteGame, type);
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress);
|
||||||
|
script.AddVariable("AllocatedKey", key);
|
||||||
|
|
||||||
if (File.Exists(filename))
|
script.UseFile(path);
|
||||||
File.Delete(filename);
|
|
||||||
|
|
||||||
Logger.Trace($"Writing {type} script to {filename}");
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
File.WriteAllText(filename, script.Contents);
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<Deterministic>true</Deterministic>
|
<Deterministic>true</Deterministic>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
@ -34,19 +35,28 @@
|
||||||
<Reference Include="BeaconLib, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="BeaconLib, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\rix0rrr.BeaconLib.1.0.2\lib\net40\BeaconLib.dll</HintPath>
|
<HintPath>..\packages\rix0rrr.BeaconLib.1.0.2\lib\net40\BeaconLib.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="ByteSize, Version=2.1.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
<HintPath>..\packages\ByteSize.2.1.1\lib\net45\ByteSize.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Playnite.SDK, Version=6.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\PlayniteSDK.6.9.0\lib\net462\Playnite.SDK.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Playnite.SDK, Version=6.10.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\PlayniteSDK.6.10.0\lib\net462\Playnite.SDK.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="PresentationCore" />
|
<Reference Include="PresentationCore" />
|
||||||
<Reference Include="PresentationFramework" />
|
<Reference Include="PresentationFramework" />
|
||||||
<Reference Include="RestSharp, Version=106.15.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
|
<Reference Include="RestSharp, Version=106.15.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\RestSharp.106.15.0\lib\net452\RestSharp.dll</HintPath>
|
<HintPath>..\packages\RestSharp.106.15.0\lib\net452\RestSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SharpCompress, Version=0.33.0.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
<Reference Include="SharpCompress, Version=0.34.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\SharpCompress.0.33.0\lib\net462\SharpCompress.dll</HintPath>
|
<HintPath>..\packages\SharpCompress.0.34.2\lib\net462\SharpCompress.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
@ -67,14 +77,14 @@
|
||||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Text.Encoding.CodePages, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="System.Text.Encoding.CodePages, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Text.Encoding.CodePages.7.0.0\lib\net462\System.Text.Encoding.CodePages.dll</HintPath>
|
<HintPath>..\packages\System.Text.Encoding.CodePages.8.0.0\lib\net462\System.Text.Encoding.CodePages.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Text.Encodings.Web, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Text.Encodings.Web.7.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
<HintPath>..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Text.Json, Version=7.0.0.3, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Text.Json.7.0.3\lib\net462\System.Text.Json.dll</HintPath>
|
<HintPath>..\packages\System.Text.Json.8.0.0\lib\net462\System.Text.Json.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||||
|
@ -93,18 +103,18 @@
|
||||||
<Reference Include="WindowsBase" />
|
<Reference Include="WindowsBase" />
|
||||||
<Reference Include="YamlDotNet, Version=5.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="YamlDotNet, Version=5.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\YamlDotNet.5.4.0\lib\net45\YamlDotNet.dll</HintPath>
|
<HintPath>..\packages\YamlDotNet.5.4.0\lib\net45\YamlDotNet.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ZstdSharp, Version=0.7.2.0, Culture=neutral, PublicKeyToken=8d151af33a4ad5cf, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ZstdSharp.Port.0.7.2\lib\net461\ZstdSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ExtractionResult.cs" />
|
|
||||||
<Compile Include="TrackableStream.cs" />
|
|
||||||
<Compile Include="Extensions\MultiplayerInfoExtensions.cs" />
|
<Compile Include="Extensions\MultiplayerInfoExtensions.cs" />
|
||||||
<Compile Include="Helpers\RetryHelper.cs" />
|
<Compile Include="PlayniteLogger.cs" />
|
||||||
<Compile Include="PowerShellRuntime.cs" />
|
<Compile Include="SaveController.cs" />
|
||||||
<Compile Include="Services\GameSaveService.cs" />
|
|
||||||
<Compile Include="UninstallController.cs" />
|
<Compile Include="UninstallController.cs" />
|
||||||
<Compile Include="InstallController.cs" />
|
<Compile Include="InstallController.cs" />
|
||||||
<Compile Include="LANCommanderClient.cs" />
|
|
||||||
<Compile Include="LANCommanderLibraryPlugin.cs" />
|
<Compile Include="LANCommanderLibraryPlugin.cs" />
|
||||||
<Compile Include="ViewModels\LANCommanderSettingsViewModel.cs" />
|
<Compile Include="ViewModels\LANCommanderSettingsViewModel.cs" />
|
||||||
<Compile Include="Views\LANCommanderSettingsView.xaml.cs">
|
<Compile Include="Views\LANCommanderSettingsView.xaml.cs">
|
||||||
|
@ -145,6 +155,10 @@
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LANCommander.PowerShell\LANCommander.PowerShell.csproj">
|
||||||
|
<Project>{807943bf-0c7d-4ed3-8393-cfee64e3138c}</Project>
|
||||||
|
<Name>LANCommander.PowerShell</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\LANCommander.SDK\LANCommander.SDK.csproj">
|
<ProjectReference Include="..\LANCommander.SDK\LANCommander.SDK.csproj">
|
||||||
<Project>{4c2a71fd-a30b-4d62-888a-4ef843d8e506}</Project>
|
<Project>{4c2a71fd-a30b-4d62-888a-4ef843d8e506}</Project>
|
||||||
<Name>LANCommander.SDK</Name>
|
<Name>LANCommander.SDK</Name>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using LANCommander.PlaynitePlugin.Extensions;
|
using LANCommander.PlaynitePlugin.Extensions;
|
||||||
using LANCommander.PlaynitePlugin.Services;
|
using LANCommander.SDK.Helpers;
|
||||||
|
using LANCommander.SDK.PowerShell;
|
||||||
using Playnite.SDK;
|
using Playnite.SDK;
|
||||||
using Playnite.SDK.Events;
|
using Playnite.SDK.Events;
|
||||||
using Playnite.SDK.Models;
|
using Playnite.SDK.Models;
|
||||||
|
@ -21,9 +22,8 @@ namespace LANCommander.PlaynitePlugin
|
||||||
{
|
{
|
||||||
public static readonly ILogger Logger = LogManager.GetLogger();
|
public static readonly ILogger Logger = LogManager.GetLogger();
|
||||||
internal LANCommanderSettingsViewModel Settings { get; set; }
|
internal LANCommanderSettingsViewModel Settings { get; set; }
|
||||||
internal LANCommanderClient LANCommander { get; set; }
|
internal LANCommander.SDK.Client LANCommanderClient { get; set; }
|
||||||
internal PowerShellRuntime PowerShellRuntime { get; set; }
|
internal LANCommanderSaveController SaveController { get; set; }
|
||||||
internal GameSaveService GameSaveService { get; set; }
|
|
||||||
|
|
||||||
public override Guid Id { get; } = Guid.Parse("48e1bac7-e0a0-45d7-ba83-36f5e9e959fc");
|
public override Guid Id { get; } = Guid.Parse("48e1bac7-e0a0-45d7-ba83-36f5e9e959fc");
|
||||||
public override string Name => "LANCommander";
|
public override string Name => "LANCommander";
|
||||||
|
@ -39,16 +39,14 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
Settings = new LANCommanderSettingsViewModel(this);
|
Settings = new LANCommanderSettingsViewModel(this);
|
||||||
|
|
||||||
LANCommander = new LANCommanderClient(Settings.ServerAddress);
|
LANCommanderClient = new SDK.Client(Settings.ServerAddress, new PlayniteLogger(Logger));
|
||||||
LANCommander.Token = new SDK.Models.AuthToken()
|
LANCommanderClient.UseToken(new SDK.Models.AuthToken()
|
||||||
{
|
{
|
||||||
AccessToken = Settings.AccessToken,
|
AccessToken = Settings.AccessToken,
|
||||||
RefreshToken = Settings.RefreshToken,
|
RefreshToken = Settings.RefreshToken,
|
||||||
};
|
});
|
||||||
|
|
||||||
PowerShellRuntime = new PowerShellRuntime();
|
// GameSaveService = new GameSaveService(LANCommander, PlayniteApi, PowerShellRuntime);
|
||||||
|
|
||||||
GameSaveService = new GameSaveService(LANCommander, PlayniteApi, PowerShellRuntime);
|
|
||||||
|
|
||||||
api.UriHandler.RegisterSource("lancommander", args =>
|
api.UriHandler.RegisterSource("lancommander", args =>
|
||||||
{
|
{
|
||||||
|
@ -91,7 +89,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
public bool ValidateConnection()
|
public bool ValidateConnection()
|
||||||
{
|
{
|
||||||
return LANCommander.ValidateToken(LANCommander.Token);
|
return LANCommanderClient.ValidateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<GameMetadata> GetGames(LibraryGetGamesArgs args)
|
public override IEnumerable<GameMetadata> GetGames(LibraryGetGamesArgs args)
|
||||||
|
@ -111,7 +109,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var games = LANCommander
|
var games = LANCommanderClient
|
||||||
.GetGames()
|
.GetGames()
|
||||||
.Where(g => g != null && g.Archives != null && g.Archives.Count() > 0);
|
.Where(g => g != null && g.Archives != null && g.Archives.Count() > 0);
|
||||||
|
|
||||||
|
@ -121,7 +119,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
{
|
{
|
||||||
Logger.Trace($"Importing/updating metadata for game \"{game.Title}\"...");
|
Logger.Trace($"Importing/updating metadata for game \"{game.Title}\"...");
|
||||||
|
|
||||||
var manifest = LANCommander.GetGameManifest(game.Id);
|
var manifest = LANCommanderClient.GetGameManifest(game.Id);
|
||||||
Logger.Trace("Successfully grabbed game manifest");
|
Logger.Trace("Successfully grabbed game manifest");
|
||||||
|
|
||||||
var existingGame = PlayniteApi.Database.Games.FirstOrDefault(g => g.GameId == game.Id.ToString() && g.PluginId == Id && g.IsInstalled);
|
var existingGame = PlayniteApi.Database.Games.FirstOrDefault(g => g.GameId == game.Id.ToString() && g.PluginId == Id && g.IsInstalled);
|
||||||
|
@ -130,7 +128,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
{
|
{
|
||||||
Logger.Trace("Game already exists in library, updating metadata...");
|
Logger.Trace("Game already exists in library, updating metadata...");
|
||||||
|
|
||||||
UpdateGame(manifest, game.Id);
|
UpdateGame(manifest);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -183,13 +181,13 @@ namespace LANCommander.PlaynitePlugin
|
||||||
metadata.Features.Add(new MetadataNameProperty($"Online Multiplayer {manifest.OnlineMultiplayer.GetPlayerCount()}".Trim()));
|
metadata.Features.Add(new MetadataNameProperty($"Online Multiplayer {manifest.OnlineMultiplayer.GetPlayerCount()}".Trim()));
|
||||||
|
|
||||||
if (game.Media.Any(m => m.Type == SDK.Enums.MediaType.Icon))
|
if (game.Media.Any(m => m.Type == SDK.Enums.MediaType.Icon))
|
||||||
metadata.Icon = new MetadataFile(LANCommander.GetMediaUrl(game.Media.First(m => m.Type == SDK.Enums.MediaType.Icon)));
|
metadata.Icon = new MetadataFile(LANCommanderClient.GetMediaUrl(game.Media.First(m => m.Type == SDK.Enums.MediaType.Icon)));
|
||||||
|
|
||||||
if (game.Media.Any(m => m.Type == SDK.Enums.MediaType.Cover))
|
if (game.Media.Any(m => m.Type == SDK.Enums.MediaType.Cover))
|
||||||
metadata.CoverImage = new MetadataFile(LANCommander.GetMediaUrl(game.Media.First(m => m.Type == SDK.Enums.MediaType.Cover)));
|
metadata.CoverImage = new MetadataFile(LANCommanderClient.GetMediaUrl(game.Media.First(m => m.Type == SDK.Enums.MediaType.Cover)));
|
||||||
|
|
||||||
if (game.Media.Any(m => m.Type == SDK.Enums.MediaType.Background))
|
if (game.Media.Any(m => m.Type == SDK.Enums.MediaType.Background))
|
||||||
metadata.BackgroundImage = new MetadataFile(LANCommander.GetMediaUrl(game.Media.First(m => m.Type == SDK.Enums.MediaType.Background)));
|
metadata.BackgroundImage = new MetadataFile(LANCommanderClient.GetMediaUrl(game.Media.First(m => m.Type == SDK.Enums.MediaType.Background)));
|
||||||
|
|
||||||
gameMetadata.Add(metadata);
|
gameMetadata.Add(metadata);
|
||||||
}
|
}
|
||||||
|
@ -224,9 +222,9 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
if (args.Games.Count == 1 && args.Games.First().IsInstalled && !String.IsNullOrWhiteSpace(args.Games.First().InstallDirectory))
|
if (args.Games.Count == 1 && args.Games.First().IsInstalled && !String.IsNullOrWhiteSpace(args.Games.First().InstallDirectory))
|
||||||
{
|
{
|
||||||
var nameChangeScriptPath = PowerShellRuntime.GetScriptFilePath(args.Games.First(), SDK.Enums.ScriptType.NameChange);
|
var nameChangeScriptPath = ScriptHelper.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.NameChange);
|
||||||
var keyChangeScriptPath = PowerShellRuntime.GetScriptFilePath(args.Games.First(), SDK.Enums.ScriptType.KeyChange);
|
var keyChangeScriptPath = ScriptHelper.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.KeyChange);
|
||||||
var installScriptPath = PowerShellRuntime.GetScriptFilePath(args.Games.First(), SDK.Enums.ScriptType.Install);
|
var installScriptPath = ScriptHelper.GetScriptFilePath(args.Games.First().InstallDirectory, SDK.Enums.ScriptType.Install);
|
||||||
|
|
||||||
if (File.Exists(nameChangeScriptPath))
|
if (File.Exists(nameChangeScriptPath))
|
||||||
{
|
{
|
||||||
|
@ -243,8 +241,11 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
if (result.Result == true)
|
if (result.Result == true)
|
||||||
{
|
{
|
||||||
PowerShellRuntime.RunScript(nameChangeArgs.Games.First(), SDK.Enums.ScriptType.NameChange, $@"""{result.SelectedString}"" ""{oldName}""");
|
var game = nameChangeArgs.Games.First();
|
||||||
LANCommander.ChangeAlias(result.SelectedString);
|
|
||||||
|
RunNameChangeScript(game.InstallDirectory, oldName, result.SelectedString);
|
||||||
|
|
||||||
|
LANCommanderClient.ChangeAlias(result.SelectedString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -264,12 +265,12 @@ namespace LANCommander.PlaynitePlugin
|
||||||
if (Guid.TryParse(keyChangeArgs.Games.First().GameId, out gameId))
|
if (Guid.TryParse(keyChangeArgs.Games.First().GameId, out gameId))
|
||||||
{
|
{
|
||||||
// NUKIEEEE
|
// NUKIEEEE
|
||||||
var newKey = LANCommander.GetNewKey(gameId);
|
var newKey = LANCommanderClient.GetNewKey(gameId);
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(newKey))
|
if (String.IsNullOrEmpty(newKey))
|
||||||
PlayniteApi.Dialogs.ShowErrorMessage("There are no more keys available on the server.", "No Keys Available");
|
PlayniteApi.Dialogs.ShowErrorMessage("There are no more keys available on the server.", "No Keys Available");
|
||||||
else
|
else
|
||||||
PowerShellRuntime.RunScript(keyChangeArgs.Games.First(), SDK.Enums.ScriptType.KeyChange, $@"""{newKey}""");
|
RunKeyChangeScript(keyChangeArgs.Games.First().InstallDirectory, newKey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -291,13 +292,9 @@ namespace LANCommander.PlaynitePlugin
|
||||||
Guid gameId;
|
Guid gameId;
|
||||||
|
|
||||||
if (Guid.TryParse(installArgs.Games.First().GameId, out gameId))
|
if (Guid.TryParse(installArgs.Games.First().GameId, out gameId))
|
||||||
{
|
RunInstallScript(installArgs.Games.First().InstallDirectory);
|
||||||
PowerShellRuntime.RunScript(installArgs.Games.First(), SDK.Enums.ScriptType.Install);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
PlayniteApi.Dialogs.ShowErrorMessage("This game could not be found on the server. Your game may be corrupted.");
|
PlayniteApi.Dialogs.ShowErrorMessage("This game could not be found on the server. Your game may be corrupted.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -334,12 +331,42 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
public override void OnGameStarting(OnGameStartingEventArgs args)
|
public override void OnGameStarting(OnGameStartingEventArgs args)
|
||||||
{
|
{
|
||||||
GameSaveService.DownloadSave(args.Game);
|
if (args.Game.PluginId == Id)
|
||||||
|
{
|
||||||
|
var gameId = Guid.Parse(args.Game.GameId);
|
||||||
|
|
||||||
|
LANCommanderClient.StartPlaySession(gameId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SaveController = new LANCommanderSaveController(this, args.Game);
|
||||||
|
SaveController.Download(args.Game);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.Error(ex, "Could not download save");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnGameStopped(OnGameStoppedEventArgs args)
|
public override void OnGameStopped(OnGameStoppedEventArgs args)
|
||||||
{
|
{
|
||||||
GameSaveService.UploadSave(args.Game);
|
if (args.Game.PluginId == Id)
|
||||||
|
{
|
||||||
|
var gameId = Guid.Parse(args.Game.GameId);
|
||||||
|
|
||||||
|
LANCommanderClient.EndPlaySession(gameId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SaveController = new LANCommanderSaveController(this, args.Game);
|
||||||
|
SaveController.Upload(args.Game);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.Error(ex, "Could not upload save");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<TopPanelItem> GetTopPanelItems()
|
public override IEnumerable<TopPanelItem> GetTopPanelItems()
|
||||||
|
@ -393,6 +420,8 @@ namespace LANCommander.PlaynitePlugin
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var oldName = Settings.PlayerName;
|
||||||
|
|
||||||
Settings.PlayerName = result.SelectedString;
|
Settings.PlayerName = result.SelectedString;
|
||||||
|
|
||||||
Logger.Trace($"New player name of \"{Settings.PlayerName}\" has been set!");
|
Logger.Trace($"New player name of \"{Settings.PlayerName}\" has been set!");
|
||||||
|
@ -402,18 +431,28 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
var games = PlayniteApi.Database.Games.Where(g => g.IsInstalled).ToList();
|
var games = PlayniteApi.Database.Games.Where(g => g.IsInstalled).ToList();
|
||||||
|
|
||||||
LANCommander.ChangeAlias(result.SelectedString);
|
LANCommanderClient.ChangeAlias(result.SelectedString);
|
||||||
|
|
||||||
Logger.Trace($"Running name change scripts across {games.Count} installed game(s)");
|
Logger.Trace($"Running name change scripts across {games.Count} installed game(s)");
|
||||||
|
|
||||||
PowerShellRuntime.RunScripts(games, SDK.Enums.ScriptType.NameChange, Settings.PlayerName);
|
foreach (var game in games)
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("OldName", oldName);
|
||||||
|
script.AddVariable("NewName", Settings.PlayerName);
|
||||||
|
|
||||||
|
script.UseFile(ScriptHelper.GetScriptFilePath(game.InstallDirectory, SDK.Enums.ScriptType.NameChange));
|
||||||
|
|
||||||
|
script.Execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Logger.Trace("Name change was cancelled");
|
Logger.Trace("Name change was cancelled");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Window ShowAuthenticationWindow(string serverAddress = null)
|
public Window ShowAuthenticationWindow(string serverAddress = null, EventHandler onClose = null)
|
||||||
{
|
{
|
||||||
Window window = null;
|
Window window = null;
|
||||||
Application.Current.Dispatcher.Invoke((Action)delegate
|
Application.Current.Dispatcher.Invoke((Action)delegate
|
||||||
|
@ -435,15 +474,19 @@ namespace LANCommander.PlaynitePlugin
|
||||||
window.Owner = PlayniteApi.Dialogs.GetCurrentAppWindow();
|
window.Owner = PlayniteApi.Dialogs.GetCurrentAppWindow();
|
||||||
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
window.ResizeMode = ResizeMode.NoResize;
|
window.ResizeMode = ResizeMode.NoResize;
|
||||||
|
|
||||||
|
if (onClose != null)
|
||||||
|
window.Closed += onClose;
|
||||||
|
|
||||||
window.ShowDialog();
|
window.ShowDialog();
|
||||||
});
|
});
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateGame(SDK.GameManifest manifest, Guid gameId)
|
public void UpdateGame(SDK.GameManifest manifest)
|
||||||
{
|
{
|
||||||
var game = PlayniteApi.Database.Games.First(g => g.GameId == gameId.ToString());
|
var game = PlayniteApi.Database.Games.FirstOrDefault(g => g.GameId == manifest?.Id.ToString());
|
||||||
|
|
||||||
if (game == null)
|
if (game == null)
|
||||||
return;
|
return;
|
||||||
|
@ -525,5 +568,77 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
PlayniteApi.Database.Games.Update(game);
|
PlayniteApi.Database.Games.Update(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int RunInstallScript(string installDirectory)
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Settings.ServerAddress);
|
||||||
|
|
||||||
|
script.UseFile(path);
|
||||||
|
|
||||||
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RunNameChangeScript(string installDirectory, string oldPlayerAlias, string newPlayerAlias)
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Settings.ServerAddress);
|
||||||
|
script.AddVariable("OldPlayerAlias", oldPlayerAlias);
|
||||||
|
script.AddVariable("NewPlayerAlias", newPlayerAlias);
|
||||||
|
|
||||||
|
script.UseFile(path);
|
||||||
|
|
||||||
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RunKeyChangeScript(string installDirectory, string key = "")
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
if (String.IsNullOrEmpty(key))
|
||||||
|
key = LANCommanderClient.GetAllocatedKey(manifest.Id);
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", Settings.InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Settings.ServerAddress);
|
||||||
|
script.AddVariable("AllocatedKey", key);
|
||||||
|
|
||||||
|
script.UseFile(path);
|
||||||
|
|
||||||
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LANCommander.PlaynitePlugin
|
||||||
|
{
|
||||||
|
public sealed class PlayniteLogger : ILogger
|
||||||
|
{
|
||||||
|
private readonly Playnite.SDK.ILogger Logger;
|
||||||
|
|
||||||
|
public PlayniteLogger(Playnite.SDK.ILogger logger) {
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable BeginScope<TState>(TState state)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled(LogLevel logLevel)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||||
|
{
|
||||||
|
switch (logLevel)
|
||||||
|
{
|
||||||
|
case LogLevel.Trace:
|
||||||
|
Logger?.Trace(formatter.Invoke(state, exception));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LogLevel.Debug:
|
||||||
|
Logger?.Debug(formatter.Invoke(state, exception));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LogLevel.Information:
|
||||||
|
Logger.Info(formatter.Invoke(state, exception));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LogLevel.Warning:
|
||||||
|
Logger.Warn(formatter.Invoke(state, exception));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LogLevel.Error:
|
||||||
|
case LogLevel.Critical:
|
||||||
|
Logger.Error(formatter.Invoke(state, exception));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,165 +0,0 @@
|
||||||
using LANCommander.SDK.Enums;
|
|
||||||
using Playnite.SDK;
|
|
||||||
using Playnite.SDK.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Management.Automation;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Security.RightsManagement;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin
|
|
||||||
{
|
|
||||||
internal class PowerShellRuntime
|
|
||||||
{
|
|
||||||
public static readonly ILogger Logger = LogManager.GetLogger();
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
|
||||||
static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
|
||||||
static extern bool Wow64RevertWow64FsRedirection(ref IntPtr ptr);
|
|
||||||
|
|
||||||
public void RunCommand(string command, bool asAdmin = false)
|
|
||||||
{
|
|
||||||
Logger.Trace($"Executing command `{command}` | Admin: {asAdmin}");
|
|
||||||
|
|
||||||
var tempScript = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".ps1");
|
|
||||||
|
|
||||||
Logger.Trace($"Creating temp script at path {tempScript}");
|
|
||||||
|
|
||||||
File.WriteAllText(tempScript, command);
|
|
||||||
|
|
||||||
RunScript(tempScript, asAdmin);
|
|
||||||
|
|
||||||
File.Delete(tempScript);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RunScript(string path, bool asAdmin = false, string arguments = null, string workingDirectory = null)
|
|
||||||
{
|
|
||||||
Logger.Trace($"Executing script at path {path} | Admin: {asAdmin} | Arguments: {arguments}");
|
|
||||||
|
|
||||||
var wow64Value = IntPtr.Zero;
|
|
||||||
|
|
||||||
// Disable Wow64 redirection so we can hit areas of the registry absolutely
|
|
||||||
Wow64DisableWow64FsRedirection(ref wow64Value);
|
|
||||||
|
|
||||||
var process = new Process();
|
|
||||||
|
|
||||||
process.StartInfo.FileName = "powershell.exe";
|
|
||||||
process.StartInfo.Arguments = $@"-ExecutionPolicy Unrestricted -File ""{path}""";
|
|
||||||
process.StartInfo.UseShellExecute = false;
|
|
||||||
process.StartInfo.RedirectStandardOutput = false;
|
|
||||||
|
|
||||||
if (arguments != null)
|
|
||||||
process.StartInfo.Arguments += " " + arguments;
|
|
||||||
|
|
||||||
if (workingDirectory != null)
|
|
||||||
process.StartInfo.WorkingDirectory = workingDirectory;
|
|
||||||
|
|
||||||
if (asAdmin)
|
|
||||||
{
|
|
||||||
process.StartInfo.Verb = "runas";
|
|
||||||
process.StartInfo.UseShellExecute = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
Wow64RevertWow64FsRedirection(ref wow64Value);
|
|
||||||
|
|
||||||
return process.ExitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunScript(Game game, ScriptType type, string arguments = null)
|
|
||||||
{
|
|
||||||
var path = GetScriptFilePath(game, type);
|
|
||||||
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
|
||||||
var contents = File.ReadAllText(path);
|
|
||||||
|
|
||||||
if (contents.StartsWith("# Requires Admin"))
|
|
||||||
RunScript(path, true, arguments);
|
|
||||||
else
|
|
||||||
RunScript(path, false, arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunScriptsAsAdmin(IEnumerable<string> paths, string arguments = null)
|
|
||||||
{
|
|
||||||
// Concatenate scripts
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
Logger.Trace("Concatenating scripts...");
|
|
||||||
|
|
||||||
foreach (var path in paths)
|
|
||||||
{
|
|
||||||
var contents = File.ReadAllText(path);
|
|
||||||
|
|
||||||
sb.AppendLine(contents);
|
|
||||||
|
|
||||||
Logger.Trace($"Added {path}!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.Trace("Done concatenating!");
|
|
||||||
|
|
||||||
if (sb.Length > 0)
|
|
||||||
{
|
|
||||||
var scriptPath = Path.GetTempFileName();
|
|
||||||
|
|
||||||
Logger.Trace($"Creating temp script at path {scriptPath}");
|
|
||||||
|
|
||||||
File.WriteAllText(scriptPath, sb.ToString());
|
|
||||||
|
|
||||||
RunScript(scriptPath, true, arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunScripts(IEnumerable<Game> games, ScriptType type, string arguments = null)
|
|
||||||
{
|
|
||||||
List<string> scripts = new List<string>();
|
|
||||||
List<string> adminScripts = new List<string>();
|
|
||||||
|
|
||||||
foreach (var game in games)
|
|
||||||
{
|
|
||||||
var path = GetScriptFilePath(game, type);
|
|
||||||
|
|
||||||
if (!File.Exists(path))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var contents = File.ReadAllText(path);
|
|
||||||
|
|
||||||
if (contents.StartsWith("# Requires Admin"))
|
|
||||||
adminScripts.Add(path);
|
|
||||||
else
|
|
||||||
scripts.Add(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
RunScriptsAsAdmin(adminScripts, arguments);
|
|
||||||
|
|
||||||
foreach (var script in scripts)
|
|
||||||
{
|
|
||||||
RunScript(script, false, arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetScriptFilePath(Game game, ScriptType type)
|
|
||||||
{
|
|
||||||
Dictionary<ScriptType, string> filenames = new Dictionary<ScriptType, string>() {
|
|
||||||
{ ScriptType.Install, "_install.ps1" },
|
|
||||||
{ ScriptType.Uninstall, "_uninstall.ps1" },
|
|
||||||
{ ScriptType.NameChange, "_changename.ps1" },
|
|
||||||
{ ScriptType.KeyChange, "_changekey.ps1" }
|
|
||||||
};
|
|
||||||
|
|
||||||
var filename = filenames[type];
|
|
||||||
|
|
||||||
return Path.Combine(game.InstallDirectory, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
using LANCommander.SDK;
|
||||||
|
using Playnite.SDK;
|
||||||
|
using Playnite.SDK.Models;
|
||||||
|
using Playnite.SDK.Plugins;
|
||||||
|
|
||||||
|
namespace LANCommander.PlaynitePlugin
|
||||||
|
{
|
||||||
|
public class LANCommanderSaveController : ControllerBase
|
||||||
|
{
|
||||||
|
private static readonly ILogger Logger;
|
||||||
|
|
||||||
|
private LANCommanderLibraryPlugin Plugin;
|
||||||
|
|
||||||
|
public LANCommanderSaveController(LANCommanderLibraryPlugin plugin, Game game) : base(game)
|
||||||
|
{
|
||||||
|
Name = "Download save using LANCommander";
|
||||||
|
Plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Download(Game game)
|
||||||
|
{
|
||||||
|
if (game != null)
|
||||||
|
{
|
||||||
|
Plugin.PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
||||||
|
{
|
||||||
|
progress.ProgressMaxValue = 100;
|
||||||
|
progress.CurrentProgressValue = 0;
|
||||||
|
|
||||||
|
var saveManager = new GameSaveManager(Plugin.LANCommanderClient);
|
||||||
|
|
||||||
|
saveManager.OnDownloadProgress += (downloadProgress) =>
|
||||||
|
{
|
||||||
|
progress.CurrentProgressValue = downloadProgress.ProgressPercentage;
|
||||||
|
};
|
||||||
|
|
||||||
|
saveManager.OnDownloadComplete += (downloadComplete) =>
|
||||||
|
{
|
||||||
|
progress.CurrentProgressValue = 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
saveManager.Download(game.InstallDirectory);
|
||||||
|
|
||||||
|
// Lock the thread until the download is done
|
||||||
|
while (progress.CurrentProgressValue != 100) { }
|
||||||
|
},
|
||||||
|
new GlobalProgressOptions("Downloading latest save...")
|
||||||
|
{
|
||||||
|
IsIndeterminate = false,
|
||||||
|
Cancelable = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Upload(Game game)
|
||||||
|
{
|
||||||
|
var saveManager = new GameSaveManager(Plugin.LANCommanderClient);
|
||||||
|
|
||||||
|
saveManager.Upload(game.InstallDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,289 +0,0 @@
|
||||||
using LANCommander.SDK;
|
|
||||||
using Playnite.SDK;
|
|
||||||
using Playnite.SDK.Models;
|
|
||||||
using SharpCompress.Archives;
|
|
||||||
using SharpCompress.Archives.Zip;
|
|
||||||
using SharpCompress.Common;
|
|
||||||
using SharpCompress.Readers;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using YamlDotNet.Serialization;
|
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin.Services
|
|
||||||
{
|
|
||||||
internal class GameSaveService
|
|
||||||
{
|
|
||||||
private readonly LANCommanderClient LANCommander;
|
|
||||||
private readonly IPlayniteAPI PlayniteApi;
|
|
||||||
private readonly PowerShellRuntime PowerShellRuntime;
|
|
||||||
|
|
||||||
internal GameSaveService(LANCommanderClient lanCommander, IPlayniteAPI playniteApi, PowerShellRuntime powerShellRuntime)
|
|
||||||
{
|
|
||||||
LANCommander = lanCommander;
|
|
||||||
PlayniteApi = playniteApi;
|
|
||||||
PowerShellRuntime = powerShellRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void DownloadSave(Game game)
|
|
||||||
{
|
|
||||||
string tempFile = String.Empty;
|
|
||||||
|
|
||||||
if (game != null)
|
|
||||||
{
|
|
||||||
PlayniteApi.Dialogs.ActivateGlobalProgress(progress =>
|
|
||||||
{
|
|
||||||
progress.ProgressMaxValue = 100;
|
|
||||||
progress.CurrentProgressValue = 0;
|
|
||||||
|
|
||||||
var destination = LANCommander.DownloadLatestSave(Guid.Parse(game.GameId), (changed) =>
|
|
||||||
{
|
|
||||||
progress.CurrentProgressValue = changed.ProgressPercentage;
|
|
||||||
}, (complete) =>
|
|
||||||
{
|
|
||||||
progress.CurrentProgressValue = 100;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Lock the thread until download is done
|
|
||||||
while (progress.CurrentProgressValue != 100)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tempFile = destination;
|
|
||||||
},
|
|
||||||
new GlobalProgressOptions("Downloading latest save...")
|
|
||||||
{
|
|
||||||
IsIndeterminate = false,
|
|
||||||
Cancelable = false
|
|
||||||
});
|
|
||||||
|
|
||||||
// Go into the archive and extract the files to the correct locations
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var tempLocation = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
||||||
|
|
||||||
Directory.CreateDirectory(tempLocation);
|
|
||||||
|
|
||||||
ExtractFilesFromZip(tempFile, tempLocation);
|
|
||||||
|
|
||||||
var deserializer = new DeserializerBuilder()
|
|
||||||
.WithNamingConvention(new PascalCaseNamingConvention())
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var manifestContents = File.ReadAllText(Path.Combine(tempLocation, "_manifest.yml"));
|
|
||||||
|
|
||||||
var manifest = deserializer.Deserialize<GameManifest>(manifestContents);
|
|
||||||
|
|
||||||
#region Move files
|
|
||||||
foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File"))
|
|
||||||
{
|
|
||||||
bool inInstallDir = savePath.Path.StartsWith("{InstallDir}");
|
|
||||||
string tempSavePath = Path.Combine(tempLocation, savePath.Id.ToString());
|
|
||||||
|
|
||||||
var tempSavePathFile = Path.Combine(tempSavePath, savePath.Path.Replace('/', '\\').Replace("{InstallDir}\\", ""));
|
|
||||||
|
|
||||||
var destination = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", game.InstallDirectory));
|
|
||||||
|
|
||||||
if (File.Exists(tempSavePathFile))
|
|
||||||
{
|
|
||||||
// Is file, move file
|
|
||||||
if (File.Exists(destination))
|
|
||||||
File.Delete(destination);
|
|
||||||
|
|
||||||
File.Move(tempSavePathFile, destination);
|
|
||||||
}
|
|
||||||
else if (Directory.Exists(tempSavePath))
|
|
||||||
{
|
|
||||||
var files = Directory.GetFiles(tempSavePath, "*", SearchOption.AllDirectories);
|
|
||||||
|
|
||||||
if (inInstallDir)
|
|
||||||
{
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
if (inInstallDir)
|
|
||||||
{
|
|
||||||
// Files are in the game's install directory. Move them there from the save path.
|
|
||||||
destination = file.Replace(tempSavePath, savePath.Path.Replace('/', '\\').TrimEnd('\\').Replace("{InstallDir}", game.InstallDirectory));
|
|
||||||
|
|
||||||
if (File.Exists(destination))
|
|
||||||
File.Delete(destination);
|
|
||||||
|
|
||||||
File.Move(file, destination);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Specified path is probably an absolute path, maybe with environment variables.
|
|
||||||
destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', '\\')));
|
|
||||||
|
|
||||||
if (File.Exists(destination))
|
|
||||||
File.Delete(destination);
|
|
||||||
|
|
||||||
File.Move(file, destination);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Handle registry importing
|
|
||||||
var registryImportFilePath = Path.Combine(tempLocation, "_registry.reg");
|
|
||||||
|
|
||||||
if (File.Exists(registryImportFilePath))
|
|
||||||
{
|
|
||||||
var registryImportFileContents = File.ReadAllText(registryImportFilePath);
|
|
||||||
|
|
||||||
PowerShellRuntime.RunCommand($"regedit.exe /s \"{registryImportFilePath}\"", registryImportFileContents.Contains("HKEY_LOCAL_MACHINE"));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
// Clean up temp files
|
|
||||||
Directory.Delete(tempLocation, true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void UploadSave(Game game)
|
|
||||||
{
|
|
||||||
var manifestPath = Path.Combine(game.InstallDirectory, "_manifest.yml");
|
|
||||||
|
|
||||||
if (File.Exists(manifestPath))
|
|
||||||
{
|
|
||||||
var deserializer = new DeserializerBuilder()
|
|
||||||
.WithNamingConvention(new PascalCaseNamingConvention())
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var manifest = deserializer.Deserialize<GameManifest>(File.ReadAllText(manifestPath));
|
|
||||||
var temp = Path.GetTempFileName();
|
|
||||||
|
|
||||||
if (manifest.SavePaths != null && manifest.SavePaths.Count() > 0)
|
|
||||||
{
|
|
||||||
using (var archive = ZipArchive.Create())
|
|
||||||
{
|
|
||||||
archive.DeflateCompressionLevel = SharpCompress.Compressors.Deflate.CompressionLevel.BestCompression;
|
|
||||||
|
|
||||||
#region Add files from defined paths
|
|
||||||
foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File"))
|
|
||||||
{
|
|
||||||
var localPath = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", game.InstallDirectory));
|
|
||||||
|
|
||||||
if (Directory.Exists(localPath))
|
|
||||||
{
|
|
||||||
AddDirectoryToZip(archive, localPath, localPath, savePath.Id);
|
|
||||||
}
|
|
||||||
else if (File.Exists(localPath))
|
|
||||||
{
|
|
||||||
archive.AddEntry(Path.Combine(savePath.Id.ToString(), savePath.Path.Replace("{InstallDir}/", "")), localPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add files from defined paths
|
|
||||||
foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File"))
|
|
||||||
{
|
|
||||||
var localPath = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", game.InstallDirectory));
|
|
||||||
|
|
||||||
if (Directory.Exists(localPath))
|
|
||||||
{
|
|
||||||
AddDirectoryToZip(archive, localPath, localPath, savePath.Id);
|
|
||||||
}
|
|
||||||
else if (File.Exists(localPath))
|
|
||||||
{
|
|
||||||
archive.AddEntry(Path.Combine(savePath.Id.ToString(), savePath.Path.Replace("{InstallDir}/", "")), localPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Export registry keys
|
|
||||||
if (manifest.SavePaths.Any(sp => sp.Type == "Registry"))
|
|
||||||
{
|
|
||||||
List<string> tempRegFiles = new List<string>();
|
|
||||||
|
|
||||||
var exportCommand = new StringBuilder();
|
|
||||||
|
|
||||||
foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "Registry"))
|
|
||||||
{
|
|
||||||
var tempRegFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".reg");
|
|
||||||
|
|
||||||
exportCommand.AppendLine($"reg.exe export \"{savePath.Path.Replace(":\\", "\\")}\" \"{tempRegFile}\"");
|
|
||||||
tempRegFiles.Add(tempRegFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
PowerShellRuntime.RunCommand(exportCommand.ToString());
|
|
||||||
|
|
||||||
var exportFile = new StringBuilder();
|
|
||||||
|
|
||||||
foreach (var tempRegFile in tempRegFiles)
|
|
||||||
{
|
|
||||||
exportFile.AppendLine(File.ReadAllText(tempRegFile));
|
|
||||||
File.Delete(tempRegFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
archive.AddEntry("_registry.reg", new MemoryStream(Encoding.UTF8.GetBytes(exportFile.ToString())), true);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
archive.AddEntry("_manifest.yml", manifestPath);
|
|
||||||
|
|
||||||
using (var ms = new MemoryStream())
|
|
||||||
{
|
|
||||||
archive.SaveTo(ms);
|
|
||||||
|
|
||||||
ms.Seek(0, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
var save = LANCommander.UploadSave(game.GameId, ms.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddDirectoryToZip(ZipArchive zipArchive, string path, string workingDirectory, Guid pathId)
|
|
||||||
{
|
|
||||||
foreach (var file in Directory.GetFiles(path))
|
|
||||||
{
|
|
||||||
// Oh man is this a hack. We should be removing only the working directory from the start,
|
|
||||||
// but we're making the assumption that the working dir put in actually prefixes the path.
|
|
||||||
// Also wtf, that Path.Combine is stripping the pathId out?
|
|
||||||
zipArchive.AddEntry(Path.Combine(pathId.ToString(), path.Substring(workingDirectory.Length), Path.GetFileName(file)), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var child in Directory.GetDirectories(path))
|
|
||||||
{
|
|
||||||
// See above
|
|
||||||
//ZipEntry entry = new ZipEntry(Path.Combine(pathId.ToString(), path.Substring(workingDirectory.Length), Path.GetFileName(path)));
|
|
||||||
|
|
||||||
//zipStream.PutNextEntry(entry);
|
|
||||||
//zipStream.CloseEntry();
|
|
||||||
|
|
||||||
AddDirectoryToZip(zipArchive, child, workingDirectory, pathId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExtractFilesFromZip(string zipPath, string destination)
|
|
||||||
{
|
|
||||||
using (var fs = File.OpenRead(zipPath))
|
|
||||||
using (var ts = new TrackableStream(fs))
|
|
||||||
using (var reader = ReaderFactory.Open(ts))
|
|
||||||
{
|
|
||||||
reader.WriteAllToDirectory(destination, new ExtractionOptions()
|
|
||||||
{
|
|
||||||
ExtractFullPath = true,
|
|
||||||
Overwrite = true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,6 @@
|
||||||
using LANCommander.SDK.Enums;
|
using LANCommander.SDK.Enums;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using LANCommander.SDK.PowerShell;
|
||||||
using Playnite.SDK;
|
using Playnite.SDK;
|
||||||
using Playnite.SDK.Models;
|
using Playnite.SDK.Models;
|
||||||
using Playnite.SDK.Plugins;
|
using Playnite.SDK.Plugins;
|
||||||
|
@ -12,29 +14,49 @@ namespace LANCommander.PlaynitePlugin
|
||||||
public static readonly ILogger Logger = LogManager.GetLogger();
|
public static readonly ILogger Logger = LogManager.GetLogger();
|
||||||
|
|
||||||
private LANCommanderLibraryPlugin Plugin;
|
private LANCommanderLibraryPlugin Plugin;
|
||||||
private PowerShellRuntime PowerShellRuntime;
|
|
||||||
|
|
||||||
public LANCommanderUninstallController(LANCommanderLibraryPlugin plugin, Game game) : base(game)
|
public LANCommanderUninstallController(LANCommanderLibraryPlugin plugin, Game game) : base(game)
|
||||||
{
|
{
|
||||||
Name = "Uninstall LANCommander Game";
|
Name = "Uninstall LANCommander Game";
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
PowerShellRuntime = new PowerShellRuntime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Uninstall(UninstallActionArgs args)
|
public override void Uninstall(UninstallActionArgs args)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PowerShellRuntime.RunScript(Game, ScriptType.Uninstall);
|
var gameManager = new LANCommander.SDK.GameManager(Plugin.LANCommanderClient, Plugin.Settings.InstallDirectory);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var scriptPath = ScriptHelper.GetScriptFilePath(Game.InstallDirectory, SDK.Enums.ScriptType.Uninstall);
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(scriptPath) && File.Exists(scriptPath))
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(Game.InstallDirectory);
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", Game.InstallDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", Plugin.Settings.InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Plugin.Settings.ServerAddress);
|
||||||
|
|
||||||
|
script.UseFile(scriptPath);
|
||||||
|
|
||||||
|
script.Execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(ex, "There was an error running the uninstall script");
|
||||||
|
}
|
||||||
|
|
||||||
|
gameManager.Uninstall(Game.InstallDirectory);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(ex, "There was an error uninstalling the game");
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
|
|
||||||
Logger.Trace("Attempting to delete install directory...");
|
|
||||||
|
|
||||||
if (!String.IsNullOrWhiteSpace(Game.InstallDirectory) && Directory.Exists(Game.InstallDirectory))
|
|
||||||
Directory.Delete(Game.InstallDirectory, true);
|
|
||||||
|
|
||||||
Logger.Trace("Deleted!");
|
|
||||||
|
|
||||||
InvokeOnUninstalled(new GameUninstalledEventArgs());
|
InvokeOnUninstalled(new GameUninstalledEventArgs());
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,24 +100,18 @@ namespace LANCommander.PlaynitePlugin.Views
|
||||||
LoginButton.Content = "Logging in...";
|
LoginButton.Content = "Logging in...";
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (Plugin.LANCommander == null || Plugin.LANCommander.Client == null)
|
if (Plugin.LANCommanderClient == null)
|
||||||
Plugin.LANCommander = new LANCommanderClient(Context.ServerAddress);
|
Plugin.LANCommanderClient = new LANCommander.SDK.Client(Context.ServerAddress);
|
||||||
else
|
else
|
||||||
Plugin.LANCommander.Client.BaseUrl = new Uri(Context.ServerAddress);
|
Plugin.LANCommanderClient.UseServerAddress(Context.ServerAddress);
|
||||||
|
|
||||||
var response = await Plugin.LANCommander.AuthenticateAsync(Context.UserName, Context.Password);
|
var response = await Plugin.LANCommanderClient.AuthenticateAsync(Context.UserName, Context.Password);
|
||||||
|
|
||||||
Plugin.Settings.ServerAddress = Context.ServerAddress;
|
Plugin.Settings.ServerAddress = Context.ServerAddress;
|
||||||
Plugin.Settings.AccessToken = response.AccessToken;
|
Plugin.Settings.AccessToken = response.AccessToken;
|
||||||
Plugin.Settings.RefreshToken = response.RefreshToken;
|
Plugin.Settings.RefreshToken = response.RefreshToken;
|
||||||
|
|
||||||
Plugin.LANCommander.Token = new AuthToken()
|
var profile = Plugin.LANCommanderClient.GetProfile();
|
||||||
{
|
|
||||||
AccessToken = response.AccessToken,
|
|
||||||
RefreshToken = response.RefreshToken,
|
|
||||||
};
|
|
||||||
|
|
||||||
var profile = Plugin.LANCommander.GetProfile();
|
|
||||||
|
|
||||||
Plugin.Settings.PlayerName = String.IsNullOrWhiteSpace(profile.Alias) ? profile.UserName : profile.Alias;
|
Plugin.Settings.PlayerName = String.IsNullOrWhiteSpace(profile.Alias) ? profile.UserName : profile.Alias;
|
||||||
|
|
||||||
|
@ -130,6 +124,8 @@ namespace LANCommander.PlaynitePlugin.Views
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Error(ex, ex.Message);
|
||||||
|
|
||||||
Plugin.PlayniteApi.Dialogs.ShowErrorMessage(ex.Message);
|
Plugin.PlayniteApi.Dialogs.ShowErrorMessage(ex.Message);
|
||||||
|
|
||||||
LoginButton.Dispatcher.Invoke(new System.Action(() =>
|
LoginButton.Dispatcher.Invoke(new System.Action(() =>
|
||||||
|
@ -148,24 +144,16 @@ namespace LANCommander.PlaynitePlugin.Views
|
||||||
RegisterButton.IsEnabled = false;
|
RegisterButton.IsEnabled = false;
|
||||||
RegisterButton.Content = "Working...";
|
RegisterButton.Content = "Working...";
|
||||||
|
|
||||||
if (Plugin.LANCommander == null || Plugin.LANCommander.Client == null)
|
if (Plugin.LANCommanderClient == null)
|
||||||
Plugin.LANCommander = new LANCommanderClient(Context.ServerAddress);
|
Plugin.LANCommanderClient = new LANCommander.SDK.Client(Context.ServerAddress);
|
||||||
else
|
|
||||||
Plugin.LANCommander.Client.BaseUrl = new Uri(Context.ServerAddress);
|
|
||||||
|
|
||||||
var response = await Plugin.LANCommander.RegisterAsync(Context.UserName, Context.Password);
|
var response = await Plugin.LANCommanderClient.RegisterAsync(Context.UserName, Context.Password);
|
||||||
|
|
||||||
Plugin.Settings.ServerAddress = Context.ServerAddress;
|
Plugin.Settings.ServerAddress = Context.ServerAddress;
|
||||||
Plugin.Settings.AccessToken = response.AccessToken;
|
Plugin.Settings.AccessToken = response.AccessToken;
|
||||||
Plugin.Settings.RefreshToken = response.RefreshToken;
|
Plugin.Settings.RefreshToken = response.RefreshToken;
|
||||||
Plugin.Settings.PlayerName = Context.UserName;
|
Plugin.Settings.PlayerName = Context.UserName;
|
||||||
|
|
||||||
Plugin.LANCommander.Token = new AuthToken()
|
|
||||||
{
|
|
||||||
AccessToken = response.AccessToken,
|
|
||||||
RefreshToken = response.RefreshToken,
|
|
||||||
};
|
|
||||||
|
|
||||||
Context.Password = String.Empty;
|
Context.Password = String.Empty;
|
||||||
|
|
||||||
Plugin.SavePluginSettings(Plugin.Settings);
|
Plugin.SavePluginSettings(Plugin.Settings);
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
RefreshToken = Settings.RefreshToken,
|
RefreshToken = Settings.RefreshToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
var task = Task.Run(() => Plugin.LANCommander.ValidateToken(token))
|
var task = Task.Run(() => Plugin.LANCommanderClient.ValidateToken(token))
|
||||||
.ContinueWith(antecedent =>
|
.ContinueWith(antecedent =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -81,16 +81,14 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
private void AuthenticateButton_Click(object sender, RoutedEventArgs e)
|
private void AuthenticateButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var authWindow = Plugin.ShowAuthenticationWindow();
|
var authWindow = Plugin.ShowAuthenticationWindow(Settings.ServerAddress, AuthWindow_Closed);
|
||||||
|
|
||||||
authWindow.Closed += AuthWindow_Closed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisconnectButton_Click(object sender, RoutedEventArgs e)
|
private void DisconnectButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Plugin.Settings.AccessToken = String.Empty;
|
Plugin.Settings.AccessToken = String.Empty;
|
||||||
Plugin.Settings.RefreshToken = String.Empty;
|
Plugin.Settings.RefreshToken = String.Empty;
|
||||||
Plugin.LANCommander.Token = null;
|
Plugin.LANCommanderClient.UseToken(null);
|
||||||
|
|
||||||
Plugin.SavePluginSettings(Plugin.Settings);
|
Plugin.SavePluginSettings(Plugin.Settings);
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,28 @@ Packages:
|
||||||
- Version: 0.2.1
|
- Version: 0.2.1
|
||||||
RequiredApiVersion: 6.0.0
|
RequiredApiVersion: 6.0.0
|
||||||
ReleaseDate: 2023-11-03
|
ReleaseDate: 2023-11-03
|
||||||
PackageUrl: https://github.com/LANCommander/LANCommander/releases/download/v0.2.0/LANCommander.PlaynitePlugin_48e1bac7-e0a0-45d7-ba83-36f5e9e959fc_0_2_1.pext
|
PackageUrl: https://github.com/LANCommander/LANCommander/releases/download/v0.2.1/LANCommander.PlaynitePlugin_48e1bac7-e0a0-45d7-ba83-36f5e9e959fc_0_2_1.pext
|
||||||
Changelog:
|
Changelog:
|
||||||
- LANCommander servers can now provide game art to Playnite clients
|
- LANCommander servers can now provide game art to Playnite clients
|
||||||
- Added server address to addon settings
|
- Added server address to addon settings
|
||||||
- Added disconnect button to addon settings
|
- Added disconnect button to addon settings
|
||||||
|
- Version: 0.2.2
|
||||||
|
RequiredApiVersion: 6.0.0
|
||||||
|
ReleaseDate: 2023-11-20
|
||||||
|
PackageUrl: https://github.com/LANCommander/LANCommander/releases/download/v0.2.2/LANCommander.PlaynitePlugin_48e1bac7-e0a0-45d7-ba83-36f5e9e959fc_0_2_2.pext
|
||||||
|
Changelog:
|
||||||
|
- _manifest.yml files in the game's install directory now includes the game's ID
|
||||||
|
- Installation progress dialog now shows the download percentage and transfer speed
|
||||||
|
- Full game download will be skipped if the game files already exist, see full release notes for more details
|
||||||
|
- Play sessions are now recorded to the server with user ID, start time, and end time
|
||||||
|
- Connection status now updates correctly when authenticating through addon settings
|
||||||
|
- Version: 0.3.0
|
||||||
|
RequiredApiVersion: 6.0.0
|
||||||
|
ReleaseDate: 2023-12-03
|
||||||
|
PackageUrl: https://github.com/LANCommander/LANCommander/releases/download/v0.3.0/LANCommander.PlaynitePlugin_48e1bac7-e0a0-45d7-ba83-36f5e9e959fc_0_3_0.pext
|
||||||
|
Changelog:
|
||||||
|
- Save paths now support regex patterns (experimental)
|
||||||
|
- Fixed redistributable archive downloading
|
||||||
|
- Fixed redistributable scripts not being able to run as admin if marked as such
|
||||||
|
- Fixed game save downloading
|
||||||
|
- Fixed addon loading of YamlDotNet library
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="7.0.0" targetFramework="net462" />
|
<package id="ByteSize" version="2.1.1" targetFramework="net462" />
|
||||||
<package id="NuGet.CommandLine" version="6.7.0" targetFramework="net462" developmentDependency="true" />
|
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net462" />
|
||||||
<package id="PlayniteSDK" version="6.9.0" targetFramework="net462" />
|
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="8.0.0" targetFramework="net462" />
|
||||||
|
<package id="Microsoft.Extensions.Logging.Abstractions" version="8.0.0" targetFramework="net462" />
|
||||||
|
<package id="NuGet.CommandLine" version="6.8.0" targetFramework="net462" developmentDependency="true" />
|
||||||
|
<package id="PlayniteSDK" version="6.10.0" targetFramework="net462" />
|
||||||
<package id="PowerShellStandard.Library" version="5.1.1" targetFramework="net462" />
|
<package id="PowerShellStandard.Library" version="5.1.1" targetFramework="net462" />
|
||||||
<package id="RestSharp" version="106.15.0" targetFramework="net462" />
|
<package id="RestSharp" version="106.15.0" targetFramework="net462" />
|
||||||
<package id="rix0rrr.BeaconLib" version="1.0.2" targetFramework="net462" />
|
<package id="rix0rrr.BeaconLib" version="1.0.2" targetFramework="net462" />
|
||||||
<package id="SharpCompress" version="0.33.0" targetFramework="net462" />
|
<package id="SharpCompress" version="0.34.2" targetFramework="net462" />
|
||||||
<package id="System.Buffers" version="4.5.1" targetFramework="net462" />
|
<package id="System.Buffers" version="4.5.1" targetFramework="net462" />
|
||||||
<package id="System.Memory" version="4.5.5" targetFramework="net462" />
|
<package id="System.Memory" version="4.5.5" targetFramework="net462" />
|
||||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net462" />
|
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net462" />
|
||||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
|
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
|
||||||
<package id="System.Text.Encoding.CodePages" version="7.0.0" targetFramework="net462" />
|
<package id="System.Text.Encoding.CodePages" version="8.0.0" targetFramework="net462" />
|
||||||
<package id="System.Text.Encodings.Web" version="7.0.0" targetFramework="net462" />
|
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net462" />
|
||||||
<package id="System.Text.Json" version="7.0.3" targetFramework="net462" />
|
<package id="System.Text.Json" version="8.0.0" targetFramework="net462" />
|
||||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
|
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
|
||||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net462" />
|
<package id="System.ValueTuple" version="4.5.0" targetFramework="net462" />
|
||||||
<package id="YamlDotNet" version="5.4.0" targetFramework="net462" />
|
<package id="YamlDotNet" version="5.4.0" targetFramework="net462" />
|
||||||
|
<package id="ZstdSharp.Port" version="0.7.2" targetFramework="net462" />
|
||||||
</packages>
|
</packages>
|
|
@ -0,0 +1,64 @@
|
||||||
|
using LANCommander.PowerShell.Cmdlets;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CmdletTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ConvertToSerializedBase64ShouldBeDeserializable()
|
||||||
|
{
|
||||||
|
var testPhrase = "Hello world! This should be deserializable back to its original form.";
|
||||||
|
|
||||||
|
var encodingCmdlet = new ConvertToSerializedBase64Cmdlet()
|
||||||
|
{
|
||||||
|
Input = testPhrase
|
||||||
|
};
|
||||||
|
|
||||||
|
var encodingResults = encodingCmdlet.Invoke().OfType<string>().ToList();
|
||||||
|
|
||||||
|
Assert.AreEqual(1, encodingResults.Count);
|
||||||
|
|
||||||
|
var decodingCmdlet = new ConvertFromSerializedBase64Cmdlet()
|
||||||
|
{
|
||||||
|
Input = encodingResults.First()
|
||||||
|
};
|
||||||
|
|
||||||
|
var decodingResults = decodingCmdlet.Invoke().OfType<string>().ToList();
|
||||||
|
|
||||||
|
Assert.AreEqual(1, encodingResults.Count);
|
||||||
|
Assert.AreEqual(testPhrase, decodingResults.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(640, 480, 640, 360, 16, 9)]
|
||||||
|
[DataRow(1024, 768, 1024, 576, 16, 9)]
|
||||||
|
[DataRow(1600, 1200, 1600, 900, 16, 9)]
|
||||||
|
[DataRow(1920, 1080, 1440, 1080, 4, 3)]
|
||||||
|
[DataRow(1366, 1024, 1024, 768, 4, 3)]
|
||||||
|
[DataRow(854, 480, 640, 480, 4, 3)]
|
||||||
|
public void ConvertAspectRatioShouldReturnCorrectBounds(int x1, int y1, int x2, int y2, int ratioX, int ratioY)
|
||||||
|
{
|
||||||
|
var aspectRatio = (double)ratioX / (double)ratioY;
|
||||||
|
|
||||||
|
var cmdlet = new ConvertAspectRatioCmdlet()
|
||||||
|
{
|
||||||
|
AspectRatio = aspectRatio,
|
||||||
|
Width = x1,
|
||||||
|
Height = y1
|
||||||
|
};
|
||||||
|
|
||||||
|
var output = cmdlet.Invoke().OfType<DisplayResolution>().ToList();
|
||||||
|
|
||||||
|
Assert.AreEqual(1, output.Count);
|
||||||
|
|
||||||
|
var bounds = output.First();
|
||||||
|
|
||||||
|
Assert.AreEqual(x2, bounds.Width);
|
||||||
|
Assert.AreEqual(y2, bounds.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{D7069A13-F0AA-4CBF-9013-4276F130A6DD}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>LANCommander.PowerShell.Tests</RootNamespace>
|
||||||
|
<AssemblyName>LANCommander.PowerShell.Tests</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||||
|
<IsCodedUITest>False</IsCodedUITest>
|
||||||
|
<TestProjectType>UnitTest</TestProjectType>
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RestSharp, Version=106.15.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\RestSharp.106.15.0\lib\net452\RestSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SharpCompress, Version=0.34.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\SharpCompress.0.34.2\lib\net462\SharpCompress.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||||
|
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Text.Encoding.CodePages, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Text.Encoding.CodePages.8.0.0\lib\net462\System.Text.Encoding.CodePages.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
<Reference Include="YamlDotNet, Version=5.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\YamlDotNet.5.4.0\lib\net45\YamlDotNet.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ZstdSharp, Version=0.7.4.0, Culture=neutral, PublicKeyToken=8d151af33a4ad5cf, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ZstdSharp.Port.0.7.4\lib\net462\ZstdSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Cmdlets.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LANCommander.PowerShell\LANCommander.PowerShell.csproj">
|
||||||
|
<Project>{807943bf-0c7d-4ed3-8393-cfee64e3138c}</Project>
|
||||||
|
<Name>LANCommander.PowerShell</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\LANCommander.SDK\LANCommander.SDK.csproj">
|
||||||
|
<Project>{4c2a71fd-a30b-4d62-888a-4ef843d8e506}</Project>
|
||||||
|
<Name>LANCommander.SDK</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets'))" />
|
||||||
|
</Target>
|
||||||
|
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("LANCommander.PowerShell.Tests")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("LANCommander.PowerShell.Tests")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2023")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
[assembly: Guid("d7069a13-f0aa-4cbf-9013-4276f130a6dd")]
|
||||||
|
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" targetFramework="net462" />
|
||||||
|
<package id="MSTest.TestAdapter" version="2.2.10" targetFramework="net462" />
|
||||||
|
<package id="MSTest.TestFramework" version="2.2.10" targetFramework="net462" />
|
||||||
|
<package id="RestSharp" version="106.15.0" targetFramework="net462" />
|
||||||
|
<package id="SharpCompress" version="0.34.2" targetFramework="net462" />
|
||||||
|
<package id="System.Buffers" version="4.5.1" targetFramework="net462" />
|
||||||
|
<package id="System.Memory" version="4.5.5" targetFramework="net462" />
|
||||||
|
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net462" />
|
||||||
|
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
|
||||||
|
<package id="System.Text.Encoding.CodePages" version="8.0.0" targetFramework="net462" />
|
||||||
|
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
|
||||||
|
<package id="YamlDotNet" version="5.4.0" targetFramework="net462" />
|
||||||
|
<package id="ZstdSharp.Port" version="0.7.4" targetFramework="net462" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using System.Management.Automation;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
public class DisplayResolution
|
||||||
|
{
|
||||||
|
public int Width { get; set; }
|
||||||
|
public int Height { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmdlet(VerbsData.Convert, "AspectRatio")]
|
||||||
|
[OutputType(typeof(string))]
|
||||||
|
public class ConvertAspectRatioCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0)]
|
||||||
|
public int Width { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true, Position = 1)]
|
||||||
|
public int Height { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true, Position = 2)]
|
||||||
|
public double AspectRatio { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
var resolution = new DisplayResolution();
|
||||||
|
|
||||||
|
// Display is wider, pillar box
|
||||||
|
if ((Width / Height) < AspectRatio)
|
||||||
|
{
|
||||||
|
resolution.Width = (int)Math.Ceiling(Height * AspectRatio);
|
||||||
|
resolution.Height = Height;
|
||||||
|
}
|
||||||
|
// Letterbox
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resolution.Width = Width;
|
||||||
|
resolution.Height = (int)Math.Ceiling(Width * (1 / AspectRatio));
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteObject(resolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsData.ConvertFrom, "SerializedBase64")]
|
||||||
|
[OutputType(typeof(object))]
|
||||||
|
public class ConvertFromSerializedBase64Cmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||||
|
public string Input { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
var xml = Encoding.UTF8.GetString(Convert.FromBase64String(Input));
|
||||||
|
|
||||||
|
WriteObject(PSSerializer.Deserialize(xml));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsData.ConvertTo, "SerializedBase64")]
|
||||||
|
[OutputType(typeof(object))]
|
||||||
|
public class ConvertToSerializedBase64Cmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||||
|
public object Input { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
var output = Convert.ToBase64String(Encoding.UTF8.GetBytes(PSSerializer.Serialize(Input)));
|
||||||
|
|
||||||
|
WriteObject(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using LANCommander.SDK;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using System.Management.Automation;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsData.ConvertTo, "StringBytes")]
|
||||||
|
[OutputType(typeof(byte[]))]
|
||||||
|
public class ConvertToStringBytesCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||||
|
public string Input { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool Utf16 { get; set; } = false;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool BigEndian { get; set; } = false;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int MaxLength { get; set; } = 0;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int MinLength { get; set; } = 0;
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
byte[] output;
|
||||||
|
|
||||||
|
if (MaxLength > 0 && Input.Length > MaxLength)
|
||||||
|
Input = Input.Substring(0, MaxLength);
|
||||||
|
|
||||||
|
if (MinLength > 0 && MinLength < MaxLength)
|
||||||
|
Input = Input.PadRight(MinLength, '\0');
|
||||||
|
else if (MinLength > 0)
|
||||||
|
Input = Input.PadRight(MaxLength, '\0');
|
||||||
|
|
||||||
|
if (Utf16 && BigEndian)
|
||||||
|
output = System.Text.Encoding.BigEndianUnicode.GetBytes(Input);
|
||||||
|
else if (Utf16)
|
||||||
|
output = System.Text.Encoding.Unicode.GetBytes(Input);
|
||||||
|
else
|
||||||
|
output = System.Text.Encoding.ASCII.GetBytes(Input);
|
||||||
|
|
||||||
|
WriteObject(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Management.Automation;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsData.Edit, "PatchBinary")]
|
||||||
|
[OutputType(typeof(string))]
|
||||||
|
public class EditPatchBinaryCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0)]
|
||||||
|
public long Offset { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true, Position = 1)]
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true, Position = 2)]
|
||||||
|
public string FilePath { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
using (var writer = File.OpenWrite(FilePath))
|
||||||
|
{
|
||||||
|
writer.Seek(Offset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
writer.Write(Data, 0, Data.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using LANCommander.SDK;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using System.Management.Automation;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsCommon.Get, "GameManifest")]
|
||||||
|
[OutputType(typeof(GameManifest))]
|
||||||
|
public class GetGameManifestCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||||
|
public string Path { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
WriteObject(ManifestHelper.Read(Path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsCommon.Get, "PrimaryDisplay")]
|
||||||
|
[OutputType(typeof(string))]
|
||||||
|
public class GetPrimaryDisplayCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
var screens = Screen.AllScreens;
|
||||||
|
|
||||||
|
WriteObject(screens.First(s => s.Primary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
using LANCommander.SDK;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using LANCommander.SDK.PowerShell;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsLifecycle.Install, "Game")]
|
||||||
|
[OutputType(typeof(string))]
|
||||||
|
public class InstallGameCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true)]
|
||||||
|
public Client Client { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true)]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = false)]
|
||||||
|
public string InstallDirectory { get; set; } = "C:\\Games";
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
var gameManager = new GameManager(Client, InstallDirectory);
|
||||||
|
var game = Client.GetGame(Id);
|
||||||
|
|
||||||
|
var progress = new ProgressRecord(1, $"Installing {game.Title}", "Progress:");
|
||||||
|
|
||||||
|
Stopwatch stopwatch = new Stopwatch();
|
||||||
|
stopwatch.Start();
|
||||||
|
|
||||||
|
gameManager.OnArchiveExtractionProgress += (long position, long length) =>
|
||||||
|
{
|
||||||
|
// Only update a max of every 500ms
|
||||||
|
if (stopwatch.ElapsedMilliseconds > 500)
|
||||||
|
{
|
||||||
|
progress.PercentComplete = (int)Math.Ceiling((position / (decimal)length) * 100);
|
||||||
|
|
||||||
|
WriteProgress(progress);
|
||||||
|
|
||||||
|
stopwatch.Restart();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var installDirectory = gameManager.Install(Id);
|
||||||
|
|
||||||
|
stopwatch.Stop();
|
||||||
|
|
||||||
|
RunInstallScript(installDirectory);
|
||||||
|
RunNameChangeScript(installDirectory);
|
||||||
|
RunKeyChangeScript(installDirectory);
|
||||||
|
|
||||||
|
WriteObject(installDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RunInstallScript(string installDirectory)
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Client.BaseUrl);
|
||||||
|
|
||||||
|
script.UseFile(ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.Install));
|
||||||
|
|
||||||
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RunNameChangeScript(string installDirectory)
|
||||||
|
{
|
||||||
|
var user = Client.GetProfile();
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.NameChange);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Client.BaseUrl);
|
||||||
|
script.AddVariable("OldPlayerAlias", "");
|
||||||
|
script.AddVariable("NewPlayerAlias", user.UserName);
|
||||||
|
|
||||||
|
script.UseFile(path);
|
||||||
|
|
||||||
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RunKeyChangeScript(string installDirectory)
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
var path = ScriptHelper.GetScriptFilePath(installDirectory, SDK.Enums.ScriptType.KeyChange);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
var key = Client.GetAllocatedKey(manifest.Id);
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", installDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
script.AddVariable("DefaultInstallDirectory", InstallDirectory);
|
||||||
|
script.AddVariable("ServerAddress", Client.BaseUrl);
|
||||||
|
script.AddVariable("AllocatedKey", key);
|
||||||
|
|
||||||
|
script.UseFile(path);
|
||||||
|
|
||||||
|
return script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
using LANCommander.SDK;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using LANCommander.SDK.PowerShell;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsLifecycle.Uninstall, "Game")]
|
||||||
|
[OutputType(typeof(string))]
|
||||||
|
public class UninstallGameCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true)]
|
||||||
|
public string InstallDirectory { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
var scriptPath = ScriptHelper.GetScriptFilePath(InstallDirectory, SDK.Enums.ScriptType.Uninstall);
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(scriptPath) && File.Exists(scriptPath))
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(InstallDirectory);
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("InstallDirectory", InstallDirectory);
|
||||||
|
script.AddVariable("GameManifest", manifest);
|
||||||
|
|
||||||
|
script.UseFile(scriptPath);
|
||||||
|
|
||||||
|
script.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
var gameManager = new GameManager(null, InstallDirectory);
|
||||||
|
|
||||||
|
gameManager.Uninstall(InstallDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using LANCommander.SDK;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using System.Management.Automation;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
[Cmdlet(VerbsCommunications.Write, "GameManifest")]
|
||||||
|
[OutputType(typeof(string))]
|
||||||
|
public class WriteGameManifestCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||||
|
public string Path { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||||
|
public GameManifest Manifest { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
var destination = ManifestHelper.Write(Manifest, Path);
|
||||||
|
|
||||||
|
WriteObject(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace LANCommander.PowerShell.Cmdlets
|
||||||
|
{
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommunications.Write, "ReplaceContentInFile")]
|
||||||
|
[OutputType(typeof(string))]
|
||||||
|
public class ReplaceContentInFileCmdlet : Cmdlet
|
||||||
|
{
|
||||||
|
[Parameter(Mandatory = true, Position = 0)]
|
||||||
|
public string Pattern { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true, Position = 1)]
|
||||||
|
public string Substitution { get; set; }
|
||||||
|
|
||||||
|
[Parameter(Mandatory = true, Position = 2)]
|
||||||
|
public string FilePath { get; set; }
|
||||||
|
|
||||||
|
protected override void ProcessRecord()
|
||||||
|
{
|
||||||
|
if (File.Exists(FilePath))
|
||||||
|
{
|
||||||
|
var contents = File.ReadAllText(FilePath);
|
||||||
|
var regex = new Regex(Pattern, RegexOptions.Multiline);
|
||||||
|
|
||||||
|
contents = regex.Replace(contents, Substitution);
|
||||||
|
|
||||||
|
File.WriteAllText(FilePath, contents);
|
||||||
|
|
||||||
|
WriteObject(contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{807943BF-0C7D-4ED3-8393-CFEE64E3138C}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>LANCommander.PowerShell</RootNamespace>
|
||||||
|
<AssemblyName>LANCommander.PowerShell</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\PowerShellStandard.Library.5.1.1\lib\net452\System.Management.Automation.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Cmdlets\ConvertTo-SerializedBase64.cs" />
|
||||||
|
<Compile Include="Cmdlets\ConvertFrom-SerializedBase64.cs" />
|
||||||
|
<Compile Include="Cmdlets\Edit-PatchBinary.cs" />
|
||||||
|
<Compile Include="Cmdlets\Uninstall-Game.cs" />
|
||||||
|
<Compile Include="Cmdlets\Install-Game.cs" />
|
||||||
|
<Compile Include="Cmdlets\Write-ReplaceContentInFile.cs" />
|
||||||
|
<Compile Include="Cmdlets\ConvertTo-StringBytes.cs" />
|
||||||
|
<Compile Include="Cmdlets\Get-PrimaryDisplay.cs" />
|
||||||
|
<Compile Include="Cmdlets\Convert-AspectRatio.cs" />
|
||||||
|
<Compile Include="Cmdlets\Get-GameManifest.cs" />
|
||||||
|
<Compile Include="Cmdlets\Write-GameManifest.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="LANCommander.PowerShell.psd1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LANCommander.SDK\LANCommander.SDK.csproj">
|
||||||
|
<Project>{4c2a71fd-a30b-4d62-888a-4ef843d8e506}</Project>
|
||||||
|
<Name>LANCommander.SDK</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
Binary file not shown.
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("LANCommander.PowerShell")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("LANCommander.PowerShell")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2023")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("807943bf-0c7d-4ed3-8393-cfee64e3138c")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="PowerShellStandard.Library" version="5.1.1" targetFramework="net472" />
|
||||||
|
</packages>
|
|
@ -1,6 +1,6 @@
|
||||||
using LANCommander.SDK;
|
using LANCommander.SDK;
|
||||||
using LANCommander.SDK.Models;
|
using LANCommander.SDK.Models;
|
||||||
using Playnite.SDK;
|
using Microsoft.Extensions.Logging;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -11,19 +11,33 @@ using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin
|
namespace LANCommander.SDK
|
||||||
{
|
{
|
||||||
internal class LANCommanderClient
|
public class Client
|
||||||
{
|
{
|
||||||
public static readonly ILogger Logger = LogManager.GetLogger();
|
private readonly ILogger Logger;
|
||||||
|
|
||||||
public readonly RestClient Client;
|
private RestClient ApiClient;
|
||||||
public AuthToken Token;
|
private AuthToken Token;
|
||||||
|
|
||||||
public LANCommanderClient(string baseUrl)
|
public string BaseUrl;
|
||||||
|
|
||||||
|
public Client(string baseUrl)
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrWhiteSpace(baseUrl))
|
BaseUrl = baseUrl;
|
||||||
Client = new RestClient(baseUrl);
|
|
||||||
|
if (!String.IsNullOrWhiteSpace(BaseUrl))
|
||||||
|
ApiClient = new RestClient(BaseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Client(string baseUrl, ILogger logger)
|
||||||
|
{
|
||||||
|
BaseUrl = baseUrl;
|
||||||
|
|
||||||
|
if (!String.IsNullOrWhiteSpace(BaseUrl))
|
||||||
|
ApiClient = new RestClient(BaseUrl);
|
||||||
|
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private T PostRequest<T>(string route, object body)
|
private T PostRequest<T>(string route, object body)
|
||||||
|
@ -32,7 +46,17 @@ namespace LANCommander.PlaynitePlugin
|
||||||
.AddJsonBody(body)
|
.AddJsonBody(body)
|
||||||
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
||||||
|
|
||||||
var response = Client.Post<T>(request);
|
var response = ApiClient.Post<T>(request);
|
||||||
|
|
||||||
|
return response.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T PostRequest<T>(string route)
|
||||||
|
{
|
||||||
|
var request = new RestRequest(route)
|
||||||
|
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
||||||
|
|
||||||
|
var response = ApiClient.Post<T>(request);
|
||||||
|
|
||||||
return response.Data;
|
return response.Data;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +66,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
var request = new RestRequest(route)
|
var request = new RestRequest(route)
|
||||||
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
||||||
|
|
||||||
var response = Client.Get<T>(request);
|
var response = ApiClient.Get<T>(request);
|
||||||
|
|
||||||
return response.Data;
|
return response.Data;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +82,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
client.DownloadProgressChanged += (s, e) => progressHandler(e);
|
client.DownloadProgressChanged += (s, e) => progressHandler(e);
|
||||||
client.DownloadFileCompleted += (s, e) => completeHandler(e);
|
client.DownloadFileCompleted += (s, e) => completeHandler(e);
|
||||||
|
|
||||||
client.DownloadFileAsync(new Uri($"{Client.BaseUrl}{route}"), tempFile);
|
client.DownloadFileAsync(new Uri($"{ApiClient.BaseUrl}{route}"), tempFile);
|
||||||
|
|
||||||
return tempFile;
|
return tempFile;
|
||||||
}
|
}
|
||||||
|
@ -72,14 +96,14 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
client.Headers.Add("Authorization", $"Bearer {Token.AccessToken}");
|
client.Headers.Add("Authorization", $"Bearer {Token.AccessToken}");
|
||||||
|
|
||||||
var ws = client.OpenRead(new Uri($"{Client.BaseUrl}{route}"));
|
var ws = client.OpenRead(new Uri($"{ApiClient.BaseUrl}{route}"));
|
||||||
|
|
||||||
return new TrackableStream(ws, true, Convert.ToInt64(client.ResponseHeaders["Content-Length"]));
|
return new TrackableStream(ws, true, Convert.ToInt64(client.ResponseHeaders["Content-Length"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<AuthResponse> AuthenticateAsync(string username, string password)
|
public async Task<AuthToken> AuthenticateAsync(string username, string password)
|
||||||
{
|
{
|
||||||
var response = await Client.ExecuteAsync<AuthResponse>(new RestRequest("/api/Auth", Method.POST).AddJsonBody(new AuthRequest()
|
var response = await ApiClient.ExecuteAsync<AuthResponse>(new RestRequest("/api/Auth", Method.POST).AddJsonBody(new AuthRequest()
|
||||||
{
|
{
|
||||||
UserName = username,
|
UserName = username,
|
||||||
Password = password
|
Password = password
|
||||||
|
@ -88,7 +112,14 @@ namespace LANCommander.PlaynitePlugin
|
||||||
switch (response.StatusCode)
|
switch (response.StatusCode)
|
||||||
{
|
{
|
||||||
case HttpStatusCode.OK:
|
case HttpStatusCode.OK:
|
||||||
return response.Data;
|
Token = new AuthToken
|
||||||
|
{
|
||||||
|
AccessToken = response.Data.AccessToken,
|
||||||
|
RefreshToken = response.Data.RefreshToken,
|
||||||
|
Expiration = response.Data.Expiration
|
||||||
|
};
|
||||||
|
|
||||||
|
return Token;
|
||||||
|
|
||||||
case HttpStatusCode.Forbidden:
|
case HttpStatusCode.Forbidden:
|
||||||
case HttpStatusCode.BadRequest:
|
case HttpStatusCode.BadRequest:
|
||||||
|
@ -100,9 +131,9 @@ namespace LANCommander.PlaynitePlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<AuthResponse> RegisterAsync(string username, string password)
|
public async Task<AuthToken> RegisterAsync(string username, string password)
|
||||||
{
|
{
|
||||||
var response = await Client.ExecuteAsync<AuthResponse>(new RestRequest("/api/auth/register", Method.POST).AddJsonBody(new AuthRequest()
|
var response = await ApiClient.ExecuteAsync<AuthResponse>(new RestRequest("/api/auth/register", Method.POST).AddJsonBody(new AuthRequest()
|
||||||
{
|
{
|
||||||
UserName = username,
|
UserName = username,
|
||||||
Password = password
|
Password = password
|
||||||
|
@ -111,7 +142,14 @@ namespace LANCommander.PlaynitePlugin
|
||||||
switch (response.StatusCode)
|
switch (response.StatusCode)
|
||||||
{
|
{
|
||||||
case HttpStatusCode.OK:
|
case HttpStatusCode.OK:
|
||||||
return response.Data;
|
Token = new AuthToken
|
||||||
|
{
|
||||||
|
AccessToken = response.Data.AccessToken,
|
||||||
|
RefreshToken = response.Data.RefreshToken,
|
||||||
|
Expiration = response.Data.Expiration
|
||||||
|
};
|
||||||
|
|
||||||
|
return Token;
|
||||||
|
|
||||||
case HttpStatusCode.BadRequest:
|
case HttpStatusCode.BadRequest:
|
||||||
case HttpStatusCode.Forbidden:
|
case HttpStatusCode.Forbidden:
|
||||||
|
@ -125,33 +163,45 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
public async Task<bool> PingAsync()
|
public async Task<bool> PingAsync()
|
||||||
{
|
{
|
||||||
var response = await Client.ExecuteAsync(new RestRequest("/api/Ping", Method.GET));
|
var response = await ApiClient.ExecuteAsync(new RestRequest("/api/Ping", Method.GET));
|
||||||
|
|
||||||
return response.StatusCode == HttpStatusCode.OK;
|
return response.StatusCode == HttpStatusCode.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthResponse RefreshToken(AuthToken token)
|
public AuthToken RefreshToken(AuthToken token)
|
||||||
{
|
{
|
||||||
Logger.Trace("Refreshing token...");
|
Logger?.LogTrace("Refreshing token...");
|
||||||
|
|
||||||
var request = new RestRequest("/api/Auth/Refresh")
|
var request = new RestRequest("/api/Auth/Refresh")
|
||||||
.AddJsonBody(token);
|
.AddJsonBody(token);
|
||||||
|
|
||||||
var response = Client.Post<AuthResponse>(request);
|
var response = ApiClient.Post<AuthResponse>(request);
|
||||||
|
|
||||||
if (response.StatusCode != HttpStatusCode.OK)
|
if (response.StatusCode != HttpStatusCode.OK)
|
||||||
throw new WebException(response.ErrorMessage);
|
throw new WebException(response.ErrorMessage);
|
||||||
|
|
||||||
return response.Data;
|
Token = new AuthToken
|
||||||
|
{
|
||||||
|
AccessToken = response.Data.AccessToken,
|
||||||
|
RefreshToken = response.Data.RefreshToken,
|
||||||
|
Expiration = response.Data.Expiration
|
||||||
|
};
|
||||||
|
|
||||||
|
return Token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ValidateToken()
|
||||||
|
{
|
||||||
|
return ValidateToken(Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidateToken(AuthToken token)
|
public bool ValidateToken(AuthToken token)
|
||||||
{
|
{
|
||||||
Logger.Trace("Validating token...");
|
Logger?.LogTrace("Validating token...");
|
||||||
|
|
||||||
if (token == null)
|
if (token == null)
|
||||||
{
|
{
|
||||||
Logger.Trace("Token is null!");
|
Logger?.LogTrace("Token is null!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,22 +210,33 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(token.AccessToken) || String.IsNullOrEmpty(token.RefreshToken))
|
if (String.IsNullOrEmpty(token.AccessToken) || String.IsNullOrEmpty(token.RefreshToken))
|
||||||
{
|
{
|
||||||
Logger.Trace("Token is empty!");
|
Logger?.LogTrace("Token is empty!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = Client.Post(request);
|
var response = ApiClient.Post(request);
|
||||||
|
|
||||||
var valid = response.StatusCode == HttpStatusCode.OK;
|
var valid = response.StatusCode == HttpStatusCode.OK;
|
||||||
|
|
||||||
if (valid)
|
if (valid)
|
||||||
Logger.Trace("Token is valid!");
|
Logger?.LogTrace("Token is valid!");
|
||||||
else
|
else
|
||||||
Logger.Trace("Token is invalid!");
|
Logger?.LogTrace("Token is invalid!");
|
||||||
|
|
||||||
return response.StatusCode == HttpStatusCode.OK;
|
return response.StatusCode == HttpStatusCode.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UseToken(AuthToken token)
|
||||||
|
{
|
||||||
|
Token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseServerAddress(string address)
|
||||||
|
{
|
||||||
|
BaseUrl = address;
|
||||||
|
ApiClient = new RestClient(BaseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<Game> GetGames()
|
public IEnumerable<Game> GetGames()
|
||||||
{
|
{
|
||||||
return GetRequest<IEnumerable<Game>>("/api/Games");
|
return GetRequest<IEnumerable<Game>>("/api/Games");
|
||||||
|
@ -223,26 +284,26 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
public GameSave UploadSave(string gameId, byte[] data)
|
public GameSave UploadSave(string gameId, byte[] data)
|
||||||
{
|
{
|
||||||
Logger.Trace("Uploading save...");
|
Logger?.LogTrace("Uploading save...");
|
||||||
|
|
||||||
var request = new RestRequest($"/api/Saves/Upload/{gameId}", Method.POST)
|
var request = new RestRequest($"/api/Saves/Upload/{gameId}", Method.POST)
|
||||||
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
||||||
|
|
||||||
request.AddFile(gameId, data, gameId);
|
request.AddFile(gameId, data, gameId);
|
||||||
|
|
||||||
var response = Client.Post<GameSave>(request);
|
var response = ApiClient.Post<GameSave>(request);
|
||||||
|
|
||||||
return response.Data;
|
return response.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetMediaUrl(Media media)
|
public string GetMediaUrl(Media media)
|
||||||
{
|
{
|
||||||
return (new Uri(Client.BaseUrl, $"/api/Media/{media.Id}/Download?fileId={media.FileId}").ToString());
|
return (new Uri(ApiClient.BaseUrl, $"/api/Media/{media.Id}/Download?fileId={media.FileId}").ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetKey(Guid id)
|
public string GetKey(Guid id)
|
||||||
{
|
{
|
||||||
Logger.Trace("Requesting key allocation...");
|
Logger?.LogTrace("Requesting key allocation...");
|
||||||
|
|
||||||
var macAddress = GetMacAddress();
|
var macAddress = GetMacAddress();
|
||||||
|
|
||||||
|
@ -261,7 +322,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
public string GetAllocatedKey(Guid id)
|
public string GetAllocatedKey(Guid id)
|
||||||
{
|
{
|
||||||
Logger.Trace("Requesting allocated key...");
|
Logger?.LogTrace("Requesting allocated key...");
|
||||||
|
|
||||||
var macAddress = GetMacAddress();
|
var macAddress = GetMacAddress();
|
||||||
|
|
||||||
|
@ -283,7 +344,7 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
public string GetNewKey(Guid id)
|
public string GetNewKey(Guid id)
|
||||||
{
|
{
|
||||||
Logger.Trace("Requesting new key allocation...");
|
Logger?.LogTrace("Requesting new key allocation...");
|
||||||
|
|
||||||
var macAddress = GetMacAddress();
|
var macAddress = GetMacAddress();
|
||||||
|
|
||||||
|
@ -305,20 +366,34 @@ namespace LANCommander.PlaynitePlugin
|
||||||
|
|
||||||
public User GetProfile()
|
public User GetProfile()
|
||||||
{
|
{
|
||||||
Logger.Trace("Requesting player's profile...");
|
Logger?.LogTrace("Requesting player's profile...");
|
||||||
|
|
||||||
return GetRequest<User>("/api/Profile");
|
return GetRequest<User>("/api/Profile");
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ChangeAlias(string alias)
|
public string ChangeAlias(string alias)
|
||||||
{
|
{
|
||||||
Logger.Trace("Requesting to change player alias...");
|
Logger?.LogTrace("Requesting to change player alias...");
|
||||||
|
|
||||||
var response = PostRequest<object>("/api/Profile/ChangeAlias", alias);
|
var response = PostRequest<object>("/api/Profile/ChangeAlias", alias);
|
||||||
|
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StartPlaySession(Guid gameId)
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Starting a game session...");
|
||||||
|
|
||||||
|
PostRequest<object>($"/api/PlaySessions/Start/{gameId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndPlaySession(Guid gameId)
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Ending a game session...");
|
||||||
|
|
||||||
|
PostRequest<object>($"/api/PlaySessions/End/{gameId}");
|
||||||
|
}
|
||||||
|
|
||||||
private string GetMacAddress()
|
private string GetMacAddress()
|
||||||
{
|
{
|
||||||
return NetworkInterface.GetAllNetworkInterfaces()
|
return NetworkInterface.GetAllNetworkInterfaces()
|
|
@ -0,0 +1,20 @@
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using SharpCompress.Readers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK
|
||||||
|
{
|
||||||
|
public class ArchiveExtractionProgressArgs : EventArgs
|
||||||
|
{
|
||||||
|
public long Position { get; set; }
|
||||||
|
public long Length { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArchiveEntryExtractionProgressArgs : EventArgs
|
||||||
|
{
|
||||||
|
public ReaderProgress Progress { get; set; }
|
||||||
|
public IEntry Entry { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin
|
namespace LANCommander.SDK
|
||||||
{
|
{
|
||||||
internal class ExtractionResult
|
internal class ExtractionResult
|
||||||
{
|
{
|
|
@ -0,0 +1,227 @@
|
||||||
|
using LANCommander.SDK.Enums;
|
||||||
|
using LANCommander.SDK.Extensions;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using LANCommander.SDK.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using SharpCompress.Readers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK
|
||||||
|
{
|
||||||
|
public class GameManager
|
||||||
|
{
|
||||||
|
private readonly ILogger Logger;
|
||||||
|
private Client Client { get; set; }
|
||||||
|
private string DefaultInstallDirectory { get; set; }
|
||||||
|
|
||||||
|
public delegate void OnArchiveEntryExtractionProgressHandler(object sender, ArchiveEntryExtractionProgressArgs e);
|
||||||
|
public event OnArchiveEntryExtractionProgressHandler OnArchiveEntryExtractionProgress;
|
||||||
|
|
||||||
|
public delegate void OnArchiveExtractionProgressHandler(long position, long length);
|
||||||
|
public event OnArchiveExtractionProgressHandler OnArchiveExtractionProgress;
|
||||||
|
|
||||||
|
private TrackableStream Stream;
|
||||||
|
private IReader Reader;
|
||||||
|
|
||||||
|
public GameManager(Client client, string defaultInstallDirectory)
|
||||||
|
{
|
||||||
|
Client = client;
|
||||||
|
DefaultInstallDirectory = defaultInstallDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameManager(Client client, string defaultInstallDirectory, ILogger logger)
|
||||||
|
{
|
||||||
|
Client = client;
|
||||||
|
DefaultInstallDirectory = defaultInstallDirectory;
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Downloads, extracts, and runs post-install scripts for the specified game
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="game">Game to install</param>
|
||||||
|
/// <param name="maxAttempts">Maximum attempts in case of transmission error</param>
|
||||||
|
/// <returns>Final install path</returns>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
public string Install(Guid gameId, int maxAttempts = 10)
|
||||||
|
{
|
||||||
|
GameManifest manifest = null;
|
||||||
|
|
||||||
|
var game = Client.GetGame(gameId);
|
||||||
|
|
||||||
|
var destination = Path.Combine(DefaultInstallDirectory, game.Title.SanitizeFilename());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ManifestHelper.Exists(destination))
|
||||||
|
manifest = ManifestHelper.Read(destination);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.LogTrace(ex, "Error reading manifest before install");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manifest == null || manifest.Id != gameId)
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Installing game {GameTitle} ({GameId})", game.Title, game.Id);
|
||||||
|
|
||||||
|
var result = RetryHelper.RetryOnException<ExtractionResult>(maxAttempts, TimeSpan.FromMilliseconds(500), new ExtractionResult(), () =>
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Attempting to download and extract game");
|
||||||
|
|
||||||
|
return DownloadAndExtract(game, destination);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.Success && !result.Canceled)
|
||||||
|
throw new Exception("Could not extract the installer. Retry the install or check your connection");
|
||||||
|
else if (result.Canceled)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
game.InstallDirectory = result.Directory;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Game {GameTitle} ({GameId}) is already installed to {InstallDirectory}", game.Title, game.Id, destination);
|
||||||
|
|
||||||
|
game.InstallDirectory = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
var writeManifestSuccess = RetryHelper.RetryOnException(maxAttempts, TimeSpan.FromSeconds(1), false, () =>
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Attempting to get game manifest");
|
||||||
|
|
||||||
|
manifest = Client.GetGameManifest(game.Id);
|
||||||
|
|
||||||
|
ManifestHelper.Write(manifest, game.InstallDirectory);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!writeManifestSuccess)
|
||||||
|
throw new Exception("Could not grab the manifest file. Retry the install or check your connection");
|
||||||
|
|
||||||
|
Logger?.LogTrace("Saving scripts");
|
||||||
|
|
||||||
|
ScriptHelper.SaveScript(game, ScriptType.Install);
|
||||||
|
ScriptHelper.SaveScript(game, ScriptType.Uninstall);
|
||||||
|
ScriptHelper.SaveScript(game, ScriptType.NameChange);
|
||||||
|
ScriptHelper.SaveScript(game, ScriptType.KeyChange);
|
||||||
|
|
||||||
|
return game.InstallDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Uninstall(string installDirectory)
|
||||||
|
{
|
||||||
|
|
||||||
|
Logger?.LogTrace("Attempting to delete the install directory");
|
||||||
|
|
||||||
|
if (Directory.Exists(installDirectory))
|
||||||
|
Directory.Delete(installDirectory, true);
|
||||||
|
|
||||||
|
Logger?.LogTrace("Deleted install directory {InstallDirectory}", installDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExtractionResult DownloadAndExtract(Game game, string destination)
|
||||||
|
{
|
||||||
|
if (game == null)
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Game failed to download, no game was specified");
|
||||||
|
|
||||||
|
throw new ArgumentNullException("No game was specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger?.LogTrace("Downloading and extracting {Game} to path {Destination}", game.Title, destination);
|
||||||
|
|
||||||
|
var extractionResult = new ExtractionResult
|
||||||
|
{
|
||||||
|
Canceled = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destination);
|
||||||
|
|
||||||
|
Stream = Client.StreamGame(game.Id);
|
||||||
|
Reader = ReaderFactory.Open(Stream);
|
||||||
|
|
||||||
|
Stream.OnProgress += (pos, len) =>
|
||||||
|
{
|
||||||
|
OnArchiveExtractionProgress?.Invoke(pos, len);
|
||||||
|
};
|
||||||
|
|
||||||
|
Reader.EntryExtractionProgress += (object sender, ReaderExtractionEventArgs<IEntry> e) =>
|
||||||
|
{
|
||||||
|
OnArchiveEntryExtractionProgress?.Invoke(this, new ArchiveEntryExtractionProgressArgs
|
||||||
|
{
|
||||||
|
Entry = e.Item,
|
||||||
|
Progress = e.ReaderProgress,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
while (Reader.MoveToNextEntry())
|
||||||
|
{
|
||||||
|
if (Reader.Cancelled)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Reader.WriteEntryToDirectory(destination, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true,
|
||||||
|
PreserveFileTime = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Reader.Dispose();
|
||||||
|
Stream.Dispose();
|
||||||
|
}
|
||||||
|
catch (ReaderCancelledException ex)
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("User cancelled the download");
|
||||||
|
|
||||||
|
extractionResult.Canceled = true;
|
||||||
|
|
||||||
|
if (Directory.Exists(destination))
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Cleaning up orphaned files after cancelled install");
|
||||||
|
|
||||||
|
Directory.Delete(destination, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.LogError(ex, "Could not extract to path {Destination}", destination);
|
||||||
|
|
||||||
|
if (Directory.Exists(destination))
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Cleaning up orphaned install files after bad install");
|
||||||
|
|
||||||
|
Directory.Delete(destination, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("The game archive could not be extracted, is it corrupted? Please try again");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extractionResult.Canceled)
|
||||||
|
{
|
||||||
|
extractionResult.Success = true;
|
||||||
|
extractionResult.Directory = destination;
|
||||||
|
|
||||||
|
Logger?.LogTrace("Game {Game} successfully downloaded and extracted to {Destination}", game.Title, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
return extractionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelInstall()
|
||||||
|
{
|
||||||
|
Reader?.Cancel();
|
||||||
|
// Reader?.Dispose();
|
||||||
|
// Stream?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,285 @@
|
||||||
|
using LANCommander.SDK;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using LANCommander.SDK.Models;
|
||||||
|
using LANCommander.SDK.PowerShell;
|
||||||
|
using SharpCompress.Archives;
|
||||||
|
using SharpCompress.Archives.Zip;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using SharpCompress.Readers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK
|
||||||
|
{
|
||||||
|
public class GameSaveManager
|
||||||
|
{
|
||||||
|
private readonly Client Client;
|
||||||
|
|
||||||
|
public delegate void OnDownloadProgressHandler(DownloadProgressChangedEventArgs e);
|
||||||
|
public event OnDownloadProgressHandler OnDownloadProgress;
|
||||||
|
|
||||||
|
public delegate void OnDownloadCompleteHandler(AsyncCompletedEventArgs e);
|
||||||
|
public event OnDownloadCompleteHandler OnDownloadComplete;
|
||||||
|
|
||||||
|
public GameSaveManager(Client client)
|
||||||
|
{
|
||||||
|
Client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Download(string installDirectory)
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
|
||||||
|
string tempFile = String.Empty;
|
||||||
|
|
||||||
|
if (manifest != null)
|
||||||
|
{
|
||||||
|
var destination = Client.DownloadLatestSave(manifest.Id, (changed) =>
|
||||||
|
{
|
||||||
|
OnDownloadProgress?.Invoke(changed);
|
||||||
|
}, (complete) =>
|
||||||
|
{
|
||||||
|
OnDownloadComplete?.Invoke(complete);
|
||||||
|
});
|
||||||
|
|
||||||
|
tempFile = destination;
|
||||||
|
|
||||||
|
// Go into the archive and extract the files to the correct locations
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tempLocation = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||||
|
|
||||||
|
Directory.CreateDirectory(tempLocation);
|
||||||
|
|
||||||
|
ExtractFilesFromZip(tempFile, tempLocation);
|
||||||
|
|
||||||
|
#region Move files
|
||||||
|
foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File"))
|
||||||
|
{
|
||||||
|
bool inInstallDir = savePath.Path.StartsWith("{InstallDir}");
|
||||||
|
string tempSavePath = Path.Combine(tempLocation, savePath.Id.ToString());
|
||||||
|
|
||||||
|
foreach (var entry in savePath.Entries)
|
||||||
|
{
|
||||||
|
var tempSavePathFile = Path.Combine(tempSavePath, entry.ArchivePath);
|
||||||
|
|
||||||
|
destination = Environment.ExpandEnvironmentVariables(entry.ActualPath).Replace("{InstallDir}", installDirectory);
|
||||||
|
|
||||||
|
if (File.Exists(tempSavePathFile))
|
||||||
|
{
|
||||||
|
if (File.Exists(destination))
|
||||||
|
File.Delete(destination);
|
||||||
|
|
||||||
|
File.Move(tempSavePathFile, destination);
|
||||||
|
}
|
||||||
|
else if (Directory.Exists(tempSavePath))
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(tempSavePath, "*", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
if (inInstallDir)
|
||||||
|
{
|
||||||
|
// Files are in the game's install directory. Move them there from the save path.
|
||||||
|
destination = file.Replace(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory));
|
||||||
|
|
||||||
|
if (File.Exists(destination))
|
||||||
|
File.Delete(destination);
|
||||||
|
|
||||||
|
File.Move(file, destination);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Specified path is probably an absolute path, maybe with environment variables.
|
||||||
|
destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', Path.DirectorySeparatorChar)));
|
||||||
|
|
||||||
|
if (File.Exists(destination))
|
||||||
|
File.Delete(destination);
|
||||||
|
|
||||||
|
File.Move(file, destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Handle registry importing
|
||||||
|
var registryImportFilePath = Path.Combine(tempLocation, "_registry.reg");
|
||||||
|
|
||||||
|
if (File.Exists(registryImportFilePath))
|
||||||
|
{
|
||||||
|
var registryImportFileContents = File.ReadAllText(registryImportFilePath);
|
||||||
|
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.UseInline($"regedit.exe /s \"{registryImportFilePath}\"");
|
||||||
|
|
||||||
|
if (registryImportFileContents.Contains("HKEY_LOCAL_MACHINE"))
|
||||||
|
script.RunAsAdmin();
|
||||||
|
|
||||||
|
script.Execute();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// Clean up temp files
|
||||||
|
Directory.Delete(tempLocation, true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Upload(string installDirectory)
|
||||||
|
{
|
||||||
|
var manifest = ManifestHelper.Read(installDirectory);
|
||||||
|
|
||||||
|
var temp = Path.GetTempFileName();
|
||||||
|
|
||||||
|
if (manifest.SavePaths != null && manifest.SavePaths.Count() > 0)
|
||||||
|
{
|
||||||
|
using (var archive = ZipArchive.Create())
|
||||||
|
{
|
||||||
|
archive.DeflateCompressionLevel = SharpCompress.Compressors.Deflate.CompressionLevel.BestCompression;
|
||||||
|
|
||||||
|
#region Add files from defined paths
|
||||||
|
foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File"))
|
||||||
|
{
|
||||||
|
IEnumerable<string> localPaths;
|
||||||
|
|
||||||
|
if (savePath.IsRegex)
|
||||||
|
{
|
||||||
|
var regex = new Regex(Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", installDirectory)));
|
||||||
|
|
||||||
|
localPaths = Directory.GetFiles(installDirectory, "*", SearchOption.AllDirectories)
|
||||||
|
.Where(p => regex.IsMatch(p))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
localPaths = new string[] { savePath.Path };
|
||||||
|
|
||||||
|
var entries = new List<SavePathEntry>();
|
||||||
|
|
||||||
|
foreach (var localPath in localPaths)
|
||||||
|
{
|
||||||
|
var actualPath = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory));
|
||||||
|
var relativePath = actualPath.Replace(installDirectory + Path.DirectorySeparatorChar, "");
|
||||||
|
|
||||||
|
if (Directory.Exists(actualPath))
|
||||||
|
{
|
||||||
|
AddDirectoryToZip(archive, relativePath, actualPath, savePath.Id);
|
||||||
|
}
|
||||||
|
else if (File.Exists(actualPath))
|
||||||
|
{
|
||||||
|
archive.AddEntry(Path.Combine(savePath.Id.ToString(), relativePath), actualPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.Add(new SavePathEntry
|
||||||
|
{
|
||||||
|
ArchivePath = relativePath,
|
||||||
|
ActualPath = actualPath.Replace(installDirectory, "{InstallDir}")
|
||||||
|
});
|
||||||
|
|
||||||
|
savePath.Entries = entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Export registry keys
|
||||||
|
if (manifest.SavePaths.Any(sp => sp.Type == "Registry"))
|
||||||
|
{
|
||||||
|
List<string> tempRegFiles = new List<string>();
|
||||||
|
|
||||||
|
var exportCommand = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "Registry"))
|
||||||
|
{
|
||||||
|
var tempRegFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".reg");
|
||||||
|
|
||||||
|
exportCommand.AppendLine($"reg.exe export \"{savePath.Path.Replace(":\\", "\\")}\" \"{tempRegFile}\"");
|
||||||
|
tempRegFiles.Add(tempRegFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.UseInline(exportCommand.ToString());
|
||||||
|
|
||||||
|
script.Execute();
|
||||||
|
|
||||||
|
var exportFile = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var tempRegFile in tempRegFiles)
|
||||||
|
{
|
||||||
|
exportFile.AppendLine(File.ReadAllText(tempRegFile));
|
||||||
|
File.Delete(tempRegFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
archive.AddEntry("_registry.reg", new MemoryStream(Encoding.UTF8.GetBytes(exportFile.ToString())), true);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var tempManifest = Path.GetTempFileName();
|
||||||
|
|
||||||
|
File.WriteAllText(tempManifest, ManifestHelper.Serialize(manifest));
|
||||||
|
|
||||||
|
archive.AddEntry("_manifest.yml", tempManifest);
|
||||||
|
|
||||||
|
using (var ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
archive.SaveTo(ms);
|
||||||
|
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
var save = Client.UploadSave(manifest.Id.ToString(), ms.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDirectoryToZip(ZipArchive zipArchive, string path, string workingDirectory, Guid pathId)
|
||||||
|
{
|
||||||
|
foreach (var file in Directory.GetFiles(path))
|
||||||
|
{
|
||||||
|
// Oh man is this a hack. We should be removing only the working directory from the start,
|
||||||
|
// but we're making the assumption that the working dir put in actually prefixes the path.
|
||||||
|
// Also wtf, that Path.Combine is stripping the pathId out?
|
||||||
|
zipArchive.AddEntry(Path.Combine(pathId.ToString(), path.Substring(workingDirectory.Length), Path.GetFileName(file)), file);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in Directory.GetDirectories(path))
|
||||||
|
{
|
||||||
|
// See above
|
||||||
|
//ZipEntry entry = new ZipEntry(Path.Combine(pathId.ToString(), path.Substring(workingDirectory.Length), Path.GetFileName(path)));
|
||||||
|
|
||||||
|
//zipStream.PutNextEntry(entry);
|
||||||
|
//zipStream.CloseEntry();
|
||||||
|
|
||||||
|
AddDirectoryToZip(zipArchive, child, workingDirectory, pathId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExtractFilesFromZip(string zipPath, string destination)
|
||||||
|
{
|
||||||
|
using (var fs = File.OpenRead(zipPath))
|
||||||
|
using (var ts = new TrackableStream(fs))
|
||||||
|
using (var reader = ReaderFactory.Open(ts))
|
||||||
|
{
|
||||||
|
reader.WriteAllToDirectory(destination, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK.Helpers
|
||||||
|
{
|
||||||
|
public static class ManifestHelper
|
||||||
|
{
|
||||||
|
public static readonly ILogger Logger;
|
||||||
|
|
||||||
|
public const string ManifestFilename = "_manifest.yml";
|
||||||
|
|
||||||
|
public static bool Exists(string installDirectory)
|
||||||
|
{
|
||||||
|
var path = GetPath(installDirectory);
|
||||||
|
|
||||||
|
return File.Exists(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameManifest Read(string installDirectory)
|
||||||
|
{
|
||||||
|
var source = GetPath(installDirectory);
|
||||||
|
var yaml = File.ReadAllText(source);
|
||||||
|
|
||||||
|
var deserializer = new DeserializerBuilder()
|
||||||
|
.WithNamingConvention(new PascalCaseNamingConvention())
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Logger?.LogTrace("Deserializing manifest");
|
||||||
|
|
||||||
|
var manifest = deserializer.Deserialize<GameManifest>(yaml);
|
||||||
|
|
||||||
|
return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Write(GameManifest manifest, string installDirectory)
|
||||||
|
{
|
||||||
|
var destination = GetPath(installDirectory);
|
||||||
|
|
||||||
|
Logger?.LogTrace("Attempting to write manifest to path {Destination}", destination);
|
||||||
|
|
||||||
|
var yaml = Serialize(manifest);
|
||||||
|
|
||||||
|
Logger?.LogTrace("Writing manifest file");
|
||||||
|
|
||||||
|
File.WriteAllText(destination, yaml);
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Serialize(GameManifest manifest)
|
||||||
|
{
|
||||||
|
var serializer = new SerializerBuilder()
|
||||||
|
.WithNamingConvention(new PascalCaseNamingConvention())
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Logger?.LogTrace("Serializing manifest");
|
||||||
|
|
||||||
|
var yaml = serializer.Serialize(manifest);
|
||||||
|
|
||||||
|
return yaml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string installDirectory)
|
||||||
|
{
|
||||||
|
return Path.Combine(installDirectory, ManifestFilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,12 @@
|
||||||
using Playnite.SDK;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin.Helpers
|
namespace LANCommander.SDK.Helpers
|
||||||
{
|
{
|
||||||
internal static class RetryHelper
|
internal static class RetryHelper
|
||||||
{
|
{
|
||||||
internal static readonly ILogger Logger = LogManager.GetLogger();
|
internal static readonly ILogger Logger;
|
||||||
|
|
||||||
internal static T RetryOnException<T>(int maxAttempts, TimeSpan delay, T @default, Func<T> action)
|
internal static T RetryOnException<T>(int maxAttempts, TimeSpan delay, T @default, Func<T> action)
|
||||||
{
|
{
|
||||||
|
@ -19,14 +16,14 @@ namespace LANCommander.PlaynitePlugin.Helpers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logger.Trace($"Attempt #{attempts + 1}/{maxAttempts}...");
|
Logger?.LogTrace($"Attempt #{attempts + 1}/{maxAttempts}...");
|
||||||
|
|
||||||
attempts++;
|
attempts++;
|
||||||
return action();
|
return action();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error(ex, $"Attempt failed!");
|
Logger?.LogError(ex, $"Attempt failed!");
|
||||||
|
|
||||||
if (attempts >= maxAttempts)
|
if (attempts >= maxAttempts)
|
||||||
return @default;
|
return @default;
|
|
@ -0,0 +1,78 @@
|
||||||
|
using LANCommander.SDK.Enums;
|
||||||
|
using LANCommander.SDK.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK.Helpers
|
||||||
|
{
|
||||||
|
public static class ScriptHelper
|
||||||
|
{
|
||||||
|
public static readonly ILogger Logger;
|
||||||
|
|
||||||
|
public static string SaveTempScript(Script script)
|
||||||
|
{
|
||||||
|
var tempPath = SaveTempScript(script.Contents);
|
||||||
|
|
||||||
|
Logger?.LogTrace("Wrote script {Script} to {Destination}", script.Name, tempPath);
|
||||||
|
|
||||||
|
return tempPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SaveTempScript(string contents)
|
||||||
|
{
|
||||||
|
var tempPath = Path.GetTempFileName();
|
||||||
|
|
||||||
|
// PowerShell will only run scripts with the .ps1 file extension
|
||||||
|
File.Move(tempPath, tempPath + ".ps1");
|
||||||
|
|
||||||
|
tempPath = tempPath + ".ps1";
|
||||||
|
|
||||||
|
File.WriteAllText(tempPath, contents);
|
||||||
|
|
||||||
|
return tempPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveScript(Game game, ScriptType type)
|
||||||
|
{
|
||||||
|
var script = game.Scripts.FirstOrDefault(s => s.Type == type);
|
||||||
|
|
||||||
|
if (script == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (script.RequiresAdmin)
|
||||||
|
script.Contents = "# Requires Admin" + "\r\n\r\n" + script.Contents;
|
||||||
|
|
||||||
|
var filename = GetScriptFilePath(game, type);
|
||||||
|
|
||||||
|
if (File.Exists(filename))
|
||||||
|
File.Delete(filename);
|
||||||
|
|
||||||
|
Logger?.LogTrace("Writing {ScriptType} script to {Destination}", type, filename);
|
||||||
|
|
||||||
|
File.WriteAllText(filename, script.Contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetScriptFilePath(Game game, ScriptType type)
|
||||||
|
{
|
||||||
|
return GetScriptFilePath(game.InstallDirectory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetScriptFilePath(string installDirectory, ScriptType type)
|
||||||
|
{
|
||||||
|
Dictionary<ScriptType, string> filenames = new Dictionary<ScriptType, string>() {
|
||||||
|
{ ScriptType.Install, "_install.ps1" },
|
||||||
|
{ ScriptType.Uninstall, "_uninstall.ps1" },
|
||||||
|
{ ScriptType.NameChange, "_changename.ps1" },
|
||||||
|
{ ScriptType.KeyChange, "_changekey.ps1" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var filename = filenames[type];
|
||||||
|
|
||||||
|
return Path.Combine(installDirectory, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,15 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||||
|
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
|
||||||
|
<PackageReference Include="RestSharp" Version="106.15.0" />
|
||||||
|
<PackageReference Include="SharpCompress" Version="0.34.2" />
|
||||||
|
<PackageReference Include="YamlDotNet" Version="5.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -8,5 +8,6 @@ namespace LANCommander.SDK.Models
|
||||||
{
|
{
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
public string RefreshToken { get; set; }
|
public string RefreshToken { get; set; }
|
||||||
|
public DateTime Expiration { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace LANCommander.SDK.Models
|
||||||
public string DirectoryName { get; set; }
|
public string DirectoryName { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public DateTime ReleasedOn { get; set; }
|
public DateTime ReleasedOn { get; set; }
|
||||||
|
public string InstallDirectory { get; set; }
|
||||||
public virtual IEnumerable<Action> Actions { get; set; }
|
public virtual IEnumerable<Action> Actions { get; set; }
|
||||||
public virtual IEnumerable<Tag> Tags { get; set; }
|
public virtual IEnumerable<Tag> Tags { get; set; }
|
||||||
public virtual Company Publisher { get; set; }
|
public virtual Company Publisher { get; set; }
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace LANCommander.SDK
|
||||||
{
|
{
|
||||||
public class GameManifest
|
public class GameManifest
|
||||||
{
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string SortTitle { get; set; }
|
public string SortTitle { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
@ -46,5 +47,13 @@ namespace LANCommander.SDK
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
public bool IsRegex { get; set; }
|
||||||
|
public IEnumerable<SavePathEntry> Entries { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SavePathEntry
|
||||||
|
{
|
||||||
|
public string ArchivePath { get; set; }
|
||||||
|
public string ActualPath { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace LANCommander.SDK.Models
|
||||||
{
|
{
|
||||||
public SavePathType Type { get; set; }
|
public SavePathType Type { get; set; }
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
public bool IsRegex { get; set; }
|
||||||
public virtual Game Game { get; set; }
|
public virtual Game Game { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK.PowerShell
|
||||||
|
{
|
||||||
|
public class PowerShellArgument
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
public PowerShellArgument(string name, object value, Type type)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK.PowerShell
|
||||||
|
{
|
||||||
|
public class PowerShellScript
|
||||||
|
{
|
||||||
|
private string Contents { get; set; } = "";
|
||||||
|
private string WorkingDirectory { get; set; } = "";
|
||||||
|
private bool AsAdmin { get; set; } = false;
|
||||||
|
private bool ShellExecute { get; set; } = false;
|
||||||
|
private bool IgnoreWow64 { get; set; } = false;
|
||||||
|
private ICollection<PowerShellVariable> Variables { get; set; }
|
||||||
|
private Dictionary<string, string> Arguments { get; set; }
|
||||||
|
private List<string> Modules { get; set; }
|
||||||
|
private Process Process { get; set; }
|
||||||
|
|
||||||
|
public PowerShellScript()
|
||||||
|
{
|
||||||
|
Variables = new List<PowerShellVariable>();
|
||||||
|
Arguments = new Dictionary<string, string>();
|
||||||
|
Modules = new List<string>();
|
||||||
|
Process = new Process();
|
||||||
|
|
||||||
|
Process.StartInfo.FileName = "powershell.exe";
|
||||||
|
Process.StartInfo.RedirectStandardOutput = false;
|
||||||
|
|
||||||
|
AddArgument("ExecutionPolicy", "Unrestricted");
|
||||||
|
|
||||||
|
var moduleManifests = Directory.EnumerateFiles(Environment.CurrentDirectory, "LANCommander.PowerShell.psd1", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
if (moduleManifests.Any())
|
||||||
|
AddModule(moduleManifests.First());
|
||||||
|
|
||||||
|
IgnoreWow64Redirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript UseFile(string path)
|
||||||
|
{
|
||||||
|
Contents = File.ReadAllText(path);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript UseInline(string contents)
|
||||||
|
{
|
||||||
|
Contents = contents;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript UseWorkingDirectory(string path)
|
||||||
|
{
|
||||||
|
WorkingDirectory = path;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript UseShellExecute()
|
||||||
|
{
|
||||||
|
ShellExecute = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript AddVariable<T>(string name, T value)
|
||||||
|
{
|
||||||
|
Variables.Add(new PowerShellVariable(name, value, typeof(T)));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript AddArgument<T>(string name, T value)
|
||||||
|
{
|
||||||
|
Arguments.Add(name, $"\"{value}\"");
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript AddArgument(string name, int value)
|
||||||
|
{
|
||||||
|
Arguments[name] = value.ToString();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript AddArgument(string name, long value)
|
||||||
|
{
|
||||||
|
Arguments[name] = value.ToString();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript AddModule(string path)
|
||||||
|
{
|
||||||
|
Modules.Add(path);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript RunAsAdmin()
|
||||||
|
{
|
||||||
|
AsAdmin = true;
|
||||||
|
|
||||||
|
Process.StartInfo.Verb = "runas";
|
||||||
|
Process.StartInfo.UseShellExecute = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerShellScript IgnoreWow64Redirection()
|
||||||
|
{
|
||||||
|
IgnoreWow64 = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Execute()
|
||||||
|
{
|
||||||
|
var scriptBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
var wow64Value = IntPtr.Zero;
|
||||||
|
|
||||||
|
if (Contents.StartsWith("# Requires Admin"))
|
||||||
|
RunAsAdmin();
|
||||||
|
|
||||||
|
foreach (var module in Modules)
|
||||||
|
{
|
||||||
|
scriptBuilder.AppendLine($"Import-Module \"{module}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var variable in Variables)
|
||||||
|
{
|
||||||
|
scriptBuilder.AppendLine($"${variable.Name} = ConvertFrom-SerializedBase64 \"{Serialize(variable.Value)}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptBuilder.AppendLine(Contents);
|
||||||
|
|
||||||
|
var path = ScriptHelper.SaveTempScript(scriptBuilder.ToString());
|
||||||
|
|
||||||
|
AddArgument("File", path);
|
||||||
|
|
||||||
|
if (IgnoreWow64)
|
||||||
|
Wow64DisableWow64FsRedirection(ref wow64Value);
|
||||||
|
|
||||||
|
foreach (var argument in Arguments)
|
||||||
|
{
|
||||||
|
Process.StartInfo.Arguments += $" -{argument.Key} {argument.Value}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(WorkingDirectory))
|
||||||
|
Process.StartInfo.WorkingDirectory = WorkingDirectory;
|
||||||
|
|
||||||
|
if (ShellExecute)
|
||||||
|
Process.StartInfo.UseShellExecute = true;
|
||||||
|
|
||||||
|
if (AsAdmin)
|
||||||
|
{
|
||||||
|
Process.StartInfo.Verb = "runas";
|
||||||
|
Process.StartInfo.UseShellExecute = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.Start();
|
||||||
|
Process.WaitForExit();
|
||||||
|
|
||||||
|
if (IgnoreWow64)
|
||||||
|
Wow64RevertWow64FsRedirection(ref wow64Value);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
File.Delete(path);
|
||||||
|
|
||||||
|
return Process.ExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Serialize<T>(T input)
|
||||||
|
{
|
||||||
|
// Use the PowerShell serializer to generate XML for our input. Then convert to base64 so we can put it on one line.
|
||||||
|
return Convert.ToBase64String(Encoding.UTF8.GetBytes(System.Management.Automation.PSSerializer.Serialize(input)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
static extern bool Wow64RevertWow64FsRedirection(ref IntPtr ptr);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK.PowerShell
|
||||||
|
{
|
||||||
|
public class PowerShellVariable
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
public PowerShellVariable(string name, object value, Type type)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,184 @@
|
||||||
|
using LANCommander.SDK.Enums;
|
||||||
|
using LANCommander.SDK.Extensions;
|
||||||
|
using LANCommander.SDK.Helpers;
|
||||||
|
using LANCommander.SDK.Models;
|
||||||
|
using LANCommander.SDK.PowerShell;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using SharpCompress.Readers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LANCommander.SDK
|
||||||
|
{
|
||||||
|
public class RedistributableManager
|
||||||
|
{
|
||||||
|
private readonly ILogger Logger;
|
||||||
|
private Client Client { get; set; }
|
||||||
|
|
||||||
|
public delegate void OnArchiveEntryExtractionProgressHandler(object sender, ArchiveEntryExtractionProgressArgs e);
|
||||||
|
public event OnArchiveEntryExtractionProgressHandler OnArchiveEntryExtractionProgress;
|
||||||
|
|
||||||
|
public delegate void OnArchiveExtractionProgressHandler(long position, long length);
|
||||||
|
public event OnArchiveExtractionProgressHandler OnArchiveExtractionProgress;
|
||||||
|
|
||||||
|
public RedistributableManager(Client client)
|
||||||
|
{
|
||||||
|
Client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedistributableManager(Client client, ILogger logger)
|
||||||
|
{
|
||||||
|
Client = client;
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Install(Game game)
|
||||||
|
{
|
||||||
|
foreach (var redistributable in game.Redistributables)
|
||||||
|
{
|
||||||
|
Install(redistributable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Install(Redistributable redistributable)
|
||||||
|
{
|
||||||
|
string installScriptTempFile = null;
|
||||||
|
string detectionScriptTempFile = null;
|
||||||
|
string extractTempPath = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var installScript = redistributable.Scripts.FirstOrDefault(s => s.Type == ScriptType.Install);
|
||||||
|
installScriptTempFile = ScriptHelper.SaveTempScript(installScript);
|
||||||
|
|
||||||
|
var detectionScript = redistributable.Scripts.FirstOrDefault(s => s.Type == ScriptType.DetectInstall);
|
||||||
|
detectionScriptTempFile = ScriptHelper.SaveTempScript(detectionScript);
|
||||||
|
|
||||||
|
var detectionResult = RunScript(detectionScriptTempFile, redistributable, detectionScript.RequiresAdmin);
|
||||||
|
|
||||||
|
// Redistributable is not installed
|
||||||
|
if (detectionResult == 0)
|
||||||
|
{
|
||||||
|
if (redistributable.Archives.Count() > 0)
|
||||||
|
{
|
||||||
|
var extractionResult = DownloadAndExtract(redistributable);
|
||||||
|
|
||||||
|
if (extractionResult.Success)
|
||||||
|
{
|
||||||
|
extractTempPath = extractionResult.Directory;
|
||||||
|
|
||||||
|
RunScript(installScriptTempFile, redistributable, installScript.RequiresAdmin, extractTempPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RunScript(installScriptTempFile, redistributable, installScript.RequiresAdmin, extractTempPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.LogError(ex, "Redistributable {Redistributable} failed to install", redistributable.Name);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (File.Exists(installScriptTempFile))
|
||||||
|
File.Delete(installScriptTempFile);
|
||||||
|
|
||||||
|
if (File.Exists(detectionScriptTempFile))
|
||||||
|
File.Delete(detectionScriptTempFile);
|
||||||
|
|
||||||
|
if (Directory.Exists(extractTempPath))
|
||||||
|
Directory.Delete(extractTempPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExtractionResult DownloadAndExtract(Redistributable redistributable)
|
||||||
|
{
|
||||||
|
if (redistributable == null)
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Redistributable failed to download! No redistributable was specified");
|
||||||
|
throw new ArgumentNullException("No redistributable was specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
var destination = Path.Combine(Path.GetTempPath(), redistributable.Name.SanitizeFilename());
|
||||||
|
|
||||||
|
Logger?.LogTrace("Downloading and extracting {Redistributable} to path {Destination}", redistributable.Name, destination);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destination);
|
||||||
|
|
||||||
|
using (var redistributableStream = Client.StreamRedistributable(redistributable.Id))
|
||||||
|
using (var reader = ReaderFactory.Open(redistributableStream))
|
||||||
|
{
|
||||||
|
redistributableStream.OnProgress += (pos, len) =>
|
||||||
|
{
|
||||||
|
OnArchiveExtractionProgress?.Invoke(pos, len);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.EntryExtractionProgress += (object sender, ReaderExtractionEventArgs<IEntry> e) =>
|
||||||
|
{
|
||||||
|
OnArchiveEntryExtractionProgress?.Invoke(this, new ArchiveEntryExtractionProgressArgs
|
||||||
|
{
|
||||||
|
Entry = e.Item,
|
||||||
|
Progress = e.ReaderProgress,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.WriteAllToDirectory(destination, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.LogError(ex, "Could not extract to path {Destination}", destination);
|
||||||
|
|
||||||
|
if (Directory.Exists(destination))
|
||||||
|
{
|
||||||
|
Logger?.LogTrace("Cleaning up orphaned files after bad install");
|
||||||
|
|
||||||
|
Directory.Delete(destination, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("The redistributable archive could not be extracted, is it corrupted? Please try again");
|
||||||
|
}
|
||||||
|
|
||||||
|
var extractionResult = new ExtractionResult
|
||||||
|
{
|
||||||
|
Canceled = false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!extractionResult.Canceled)
|
||||||
|
{
|
||||||
|
extractionResult.Success = true;
|
||||||
|
extractionResult.Directory = destination;
|
||||||
|
Logger?.LogTrace("Redistributable {Redistributable} successfully downloaded and extracted to {Destination}", redistributable.Name, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
return extractionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RunScript(string path, Redistributable redistributable, bool requiresAdmin = false, string workingDirectory = "")
|
||||||
|
{
|
||||||
|
var script = new PowerShellScript();
|
||||||
|
|
||||||
|
script.AddVariable("Redistributable", redistributable);
|
||||||
|
|
||||||
|
script.UseWorkingDirectory(workingDirectory);
|
||||||
|
script.UseFile(path);
|
||||||
|
|
||||||
|
if (requiresAdmin)
|
||||||
|
script.RunAsAdmin();
|
||||||
|
|
||||||
|
return script.Execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin
|
namespace LANCommander.SDK
|
||||||
{
|
{
|
||||||
internal class TrackableStream : MemoryStream, IDisposable
|
public class TrackableStream : MemoryStream, IDisposable
|
||||||
{
|
{
|
||||||
public delegate void OnProgressDelegate(long Position, long Length);
|
public delegate void OnProgressDelegate(long Position, long Length);
|
||||||
public event OnProgressDelegate OnProgress = delegate { };
|
public event OnProgressDelegate OnProgress = delegate { };
|
|
@ -11,6 +11,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.SDK", "LANComm
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.PCGamingWiki", "LANCommander.PCGamingWiki\LANCommander.PCGamingWiki.csproj", "{2436B817-4475-4E70-9BB2-E1E7866DB79F}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.PCGamingWiki", "LANCommander.PCGamingWiki\LANCommander.PCGamingWiki.csproj", "{2436B817-4475-4E70-9BB2-E1E7866DB79F}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LANCommander.PowerShell", "LANCommander.PowerShell\LANCommander.PowerShell.csproj", "{807943BF-0C7D-4ED3-8393-CFEE64E3138C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LANCommander.PowerShell.Tests", "LANCommander.PowerShell.Tests\LANCommander.PowerShell.Tests.csproj", "{D7069A13-F0AA-4CBF-9013-4276F130A6DD}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -33,6 +37,14 @@ Global
|
||||||
{2436B817-4475-4E70-9BB2-E1E7866DB79F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{2436B817-4475-4E70-9BB2-E1E7866DB79F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{2436B817-4475-4E70-9BB2-E1E7866DB79F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{2436B817-4475-4E70-9BB2-E1E7866DB79F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{2436B817-4475-4E70-9BB2-E1E7866DB79F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{2436B817-4475-4E70-9BB2-E1E7866DB79F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{807943BF-0C7D-4ED3-8393-CFEE64E3138C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D7069A13-F0AA-4CBF-9013-4276F130A6DD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -15,49 +15,20 @@ namespace LANCommander.Areas.Identity.Pages.Account
|
||||||
{
|
{
|
||||||
public class LogoutModel : PageModel
|
public class LogoutModel : PageModel
|
||||||
{
|
{
|
||||||
private readonly SignInManager<User> _signInManager;
|
private readonly SignInManager<User> SignInManager;
|
||||||
private readonly ILogger<LogoutModel> _logger;
|
private readonly ILogger<LogoutModel> Logger;
|
||||||
|
|
||||||
public LogoutModel(SignInManager<User> signInManager, ILogger<LogoutModel> logger)
|
public LogoutModel(SignInManager<User> signInManager, ILogger<LogoutModel> logger)
|
||||||
{
|
{
|
||||||
_signInManager = signInManager;
|
SignInManager = signInManager;
|
||||||
_logger = logger;
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet(string returnUrl = null, bool force = false)
|
public async Task<IActionResult> OnGet()
|
||||||
{
|
{
|
||||||
if (force)
|
await SignInManager.SignOutAsync();
|
||||||
{
|
|
||||||
await _signInManager.SignOutAsync();
|
|
||||||
_logger.LogInformation("User logged out.");
|
|
||||||
|
|
||||||
if (returnUrl != null)
|
return LocalRedirect("/");
|
||||||
{
|
|
||||||
return LocalRedirect(returnUrl);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return LocalRedirect("/Identity/Account/Login");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IActionResult> OnPost(string returnUrl = null)
|
|
||||||
{
|
|
||||||
await _signInManager.SignOutAsync();
|
|
||||||
_logger.LogInformation("User logged out.");
|
|
||||||
if (returnUrl != null)
|
|
||||||
{
|
|
||||||
return LocalRedirect(returnUrl);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This needs to be a redirect so that the browser performs a new
|
|
||||||
// request and the identity for the user gets updated.
|
|
||||||
return RedirectToPage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<Space Direction="DirectionVHType.Vertical" Style="width: 100%">
|
<Space Direction="DirectionVHType.Vertical" Style="width: 100%">
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
<Table TItem="Archive" DataSource="@Archives.OrderByDescending(a => a.CreatedOn)" HidePagination="true" Responsive>
|
<Table TItem="Archive" DataSource="@Archives" HidePagination="true" Responsive>
|
||||||
<PropertyColumn Property="a => a.Version" />
|
<PropertyColumn Property="a => a.Version" />
|
||||||
<PropertyColumn Property="a => a.CompressedSize">
|
<PropertyColumn Property="a => a.CompressedSize">
|
||||||
@ByteSizeLib.ByteSize.FromBytes(context.CompressedSize)
|
@ByteSizeLib.ByteSize.FromBytes(context.CompressedSize)
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<PropertyColumn Property="a => a.CreatedBy">
|
<PropertyColumn Property="a => a.CreatedBy">
|
||||||
@context.CreatedBy?.UserName
|
@context.CreatedBy?.UserName
|
||||||
</PropertyColumn>
|
</PropertyColumn>
|
||||||
<PropertyColumn Property="a => a.CreatedOn" Format="MM/dd/yyyy hh:mm tt" />
|
<PropertyColumn Property="a => a.CreatedOn" Format="MM/dd/yyyy hh:mm tt" DefaultSortOrder="@SortDirection.Descending" />
|
||||||
<ActionColumn Title="">
|
<ActionColumn Title="">
|
||||||
<Space Style="display: flex; justify-content: end">
|
<Space Style="display: flex; justify-content: end">
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
|
@ -46,15 +46,14 @@
|
||||||
</SpaceItem>
|
</SpaceItem>
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
<ArchiveUploader @ref="Uploader" OnArchiveUploaded="AddArchive" />
|
<ArchiveUploader @ref="Uploader" GameId="GameId" RedistributableId="RedistributableId" OnArchiveUploaded="LoadData" />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public Guid GameId { get; set; }
|
[Parameter] public Guid GameId { get; set; }
|
||||||
[Parameter] public Guid RedistributableId { get; set; }
|
[Parameter] public Guid RedistributableId { get; set; }
|
||||||
[Parameter] public ICollection<Archive> Archives { get; set; }
|
|
||||||
[Parameter] public EventCallback<ICollection<Archive>> ArchivesChanged { get; set; }
|
|
||||||
|
|
||||||
Archive Archive;
|
ICollection<Archive> Archives { get; set; }
|
||||||
|
|
||||||
ArchiveUploader Uploader;
|
ArchiveUploader Uploader;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
|
@ -66,7 +65,10 @@
|
||||||
|
|
||||||
private async Task LoadData()
|
private async Task LoadData()
|
||||||
{
|
{
|
||||||
Archives = await ArchiveService.Get(a => a.GameId == GameId).OrderByDescending(a => a.CreatedOn).ToListAsync();
|
if (GameId != Guid.Empty)
|
||||||
|
Archives = await ArchiveService.Get(a => a.GameId == GameId).ToListAsync();
|
||||||
|
else if (RedistributableId != Guid.Empty)
|
||||||
|
Archives = await ArchiveService.Get(a => a.RedistributableId == RedistributableId).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Download(Archive archive)
|
private async Task Download(Archive archive)
|
||||||
|
@ -78,27 +80,7 @@
|
||||||
|
|
||||||
private async Task UploadArchive()
|
private async Task UploadArchive()
|
||||||
{
|
{
|
||||||
if (GameId != Guid.Empty)
|
await Uploader.Open();
|
||||||
Archive = new Archive() { GameId = GameId, Id = Guid.NewGuid() };
|
|
||||||
|
|
||||||
if (RedistributableId != Guid.Empty)
|
|
||||||
Archive = new Archive() { RedistributableId = RedistributableId, Id = Guid.NewGuid() };
|
|
||||||
|
|
||||||
await Uploader.Open(Archive);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task AddArchive(Archive archive)
|
|
||||||
{
|
|
||||||
var lastArchive = Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault();
|
|
||||||
|
|
||||||
Archive = await ArchiveService.Add(archive);
|
|
||||||
|
|
||||||
await LoadData();
|
|
||||||
|
|
||||||
var settings = SettingService.GetSettings();
|
|
||||||
|
|
||||||
if (lastArchive != null && settings.Archives.EnablePatching)
|
|
||||||
BackgroundJob.Enqueue<PatchArchiveBackgroundJob>(x => x.Execute(lastArchive.Id, Archive.Id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Delete(Archive archive)
|
private async Task Delete(Archive archive)
|
||||||
|
@ -107,6 +89,8 @@
|
||||||
{
|
{
|
||||||
await ArchiveService.Delete(archive);
|
await ArchiveService.Delete(archive);
|
||||||
|
|
||||||
|
await LoadData();
|
||||||
|
|
||||||
await MessageService.Success("Archive deleted!");
|
await MessageService.Success("Archive deleted!");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
@using System.Diagnostics;
|
@using System.Diagnostics;
|
||||||
@using Hangfire;
|
@using Hangfire;
|
||||||
@using LANCommander.Jobs.Background;
|
@using LANCommander.Jobs.Background;
|
||||||
|
@using Microsoft.EntityFrameworkCore;
|
||||||
@inject HttpClient HttpClient
|
@inject HttpClient HttpClient
|
||||||
@inject NavigationManager Navigator
|
@inject NavigationManager Navigator
|
||||||
@inject ArchiveService ArchiveService
|
@inject ArchiveService ArchiveService
|
||||||
|
@ -62,7 +63,9 @@
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public EventCallback<Archive> OnArchiveUploaded { get; set; }
|
[Parameter] public Guid GameId { get; set; }
|
||||||
|
[Parameter] public Guid RedistributableId { get; set; }
|
||||||
|
[Parameter] public EventCallback<Guid> OnArchiveUploaded { get; set; }
|
||||||
|
|
||||||
Archive Archive;
|
Archive Archive;
|
||||||
|
|
||||||
|
@ -113,9 +116,21 @@
|
||||||
File = args.File;
|
File = args.File;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Open(Archive archive)
|
public async Task Open(Guid? archiveId = null)
|
||||||
{
|
{
|
||||||
Archive = archive;
|
if (archiveId.HasValue && archiveId != Guid.Empty)
|
||||||
|
{
|
||||||
|
Archive = await ArchiveService.Get(archiveId.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Archive = new Archive();
|
||||||
|
|
||||||
|
if (GameId != Guid.Empty)
|
||||||
|
Archive.GameId = GameId;
|
||||||
|
else if (RedistributableId != Guid.Empty)
|
||||||
|
Archive.RedistributableId = RedistributableId;
|
||||||
|
}
|
||||||
|
|
||||||
Visible = true;
|
Visible = true;
|
||||||
|
|
||||||
|
@ -128,8 +143,8 @@
|
||||||
{
|
{
|
||||||
if (FileInput != null)
|
if (FileInput != null)
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrWhiteSpace(archive.ObjectKey) && archive.ObjectKey != Guid.Empty.ToString())
|
if (!String.IsNullOrWhiteSpace(Archive.ObjectKey) && Archive.ObjectKey != Guid.Empty.ToString())
|
||||||
await JS.InvokeVoidAsync("Uploader.Init", "FileInput", archive.ObjectKey.ToString());
|
await JS.InvokeVoidAsync("Uploader.Init", "FileInput", Archive.ObjectKey.ToString());
|
||||||
else
|
else
|
||||||
await JS.InvokeVoidAsync("Uploader.Init", "FileInput", "");
|
await JS.InvokeVoidAsync("Uploader.Init", "FileInput", "");
|
||||||
|
|
||||||
|
@ -163,12 +178,32 @@
|
||||||
Archive.ObjectKey = objectKey.ToString();
|
Archive.ObjectKey = objectKey.ToString();
|
||||||
Archive.CompressedSize = File.Size;
|
Archive.CompressedSize = File.Size;
|
||||||
|
|
||||||
|
if (Archive.Id != Guid.Empty)
|
||||||
|
Archive = await ArchiveService.Update(Archive);
|
||||||
|
else
|
||||||
|
Archive = await ArchiveService.Add(Archive);
|
||||||
|
|
||||||
Visible = false;
|
Visible = false;
|
||||||
|
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
|
Archive? lastArchive = null;
|
||||||
|
|
||||||
|
var settings = SettingService.GetSettings();
|
||||||
|
|
||||||
|
if (settings.Archives.EnablePatching)
|
||||||
|
{
|
||||||
|
if (Archive.GameId != Guid.Empty)
|
||||||
|
lastArchive = await ArchiveService.Get(a => a.Id != Archive.Id && a.GameId == Archive.GameId).OrderByDescending(a => a.CreatedOn).FirstOrDefaultAsync();
|
||||||
|
else if (Archive.RedistributableId != Guid.Empty)
|
||||||
|
lastArchive = await ArchiveService.Get(a => a.Id != Archive.Id && a.RedistributableId == Archive.RedistributableId).OrderByDescending(a => a.CreatedOn).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (lastArchive != null && settings.Archives.EnablePatching)
|
||||||
|
BackgroundJob.Enqueue<PatchArchiveBackgroundJob>(x => x.Execute(lastArchive.Id, Archive.Id));
|
||||||
|
}
|
||||||
|
|
||||||
if (OnArchiveUploaded.HasDelegate)
|
if (OnArchiveUploaded.HasDelegate)
|
||||||
await OnArchiveUploaded.InvokeAsync(Archive);
|
await OnArchiveUploaded.InvokeAsync(Archive.Id);
|
||||||
|
|
||||||
await MessageService.Success("Archive uploaded!");
|
await MessageService.Success("Archive uploaded!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,24 +239,37 @@
|
||||||
|
|
||||||
async Task<HashSet<FileManagerDirectory>> GetArchiveDirectoriesAsync(Guid archiveId)
|
async Task<HashSet<FileManagerDirectory>> GetArchiveDirectoriesAsync(Guid archiveId)
|
||||||
{
|
{
|
||||||
var entries = await ArchiveService.GetContents(archiveId);
|
try
|
||||||
var directories = new HashSet<FileManagerDirectory>();
|
|
||||||
|
|
||||||
var root = new FileManagerDirectory
|
|
||||||
{
|
{
|
||||||
Name = "Root",
|
var entries = await ArchiveService.GetContents(archiveId);
|
||||||
Path = "",
|
var directories = new HashSet<FileManagerDirectory>();
|
||||||
IsExpanded = true
|
|
||||||
};
|
|
||||||
|
|
||||||
root.PopulateChildren(entries);
|
var root = new FileManagerDirectory
|
||||||
|
{
|
||||||
|
Name = "Root",
|
||||||
|
Path = "",
|
||||||
|
IsExpanded = true
|
||||||
|
};
|
||||||
|
|
||||||
await ChangeDirectory(root, true);
|
root.PopulateChildren(entries);
|
||||||
|
|
||||||
return new HashSet<FileManagerDirectory>
|
await ChangeDirectory(root, true);
|
||||||
|
|
||||||
|
return new HashSet<FileManagerDirectory>
|
||||||
|
{
|
||||||
|
root
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
{
|
{
|
||||||
root
|
MessageService.Error("Could not open archive! Is it missing?");
|
||||||
};
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageService.Error("An unknown error occurred trying to open the archive");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HashSet<FileManagerDirectory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
string GetEntryName(IFileManagerEntry entry)
|
string GetEntryName(IFileManagerEntry entry)
|
||||||
|
|
|
@ -4,75 +4,12 @@
|
||||||
@using LANCommander.Models
|
@using LANCommander.Models
|
||||||
@using LANCommander.Services
|
@using LANCommander.Services
|
||||||
@using System.IO.Compression;
|
@using System.IO.Compression;
|
||||||
|
@using Microsoft.EntityFrameworkCore;
|
||||||
@inject ScriptService ScriptService
|
@inject ScriptService ScriptService
|
||||||
@inject ModalService ModalService
|
@inject ModalService ModalService
|
||||||
@inject IMessageService MessageService
|
@inject IMessageService MessageService
|
||||||
|
|
||||||
@{
|
|
||||||
RenderFragment Footer =
|
|
||||||
@<Template>
|
|
||||||
<Button OnClick="Save" Disabled="@(String.IsNullOrWhiteSpace(Script.Name))" Type="@ButtonType.Primary">Save</Button>
|
|
||||||
<Button OnClick="Close">Close</Button>
|
|
||||||
</Template>;
|
|
||||||
}
|
|
||||||
|
|
||||||
<Modal Visible="ModalVisible" Footer="@Footer" Title="@(Script == null ? "Add Script" : "Edit Script")" OkText="@("Save")" Maximizable="false" DefaultMaximized="true" Closable="true" OnCancel="Close">
|
|
||||||
<Form Model="@Script" Layout="@FormLayout.Vertical">
|
|
||||||
<FormItem>
|
|
||||||
@foreach (var group in Snippets.Select(s => s.Group).Distinct())
|
|
||||||
{
|
|
||||||
<Dropdown>
|
|
||||||
<Overlay>
|
|
||||||
<Menu>
|
|
||||||
@foreach (var snippet in Snippets.Where(s => s.Group == group))
|
|
||||||
{
|
|
||||||
<MenuItem OnClick="() => InsertSnippet(snippet)">
|
|
||||||
@snippet.Name
|
|
||||||
</MenuItem>
|
|
||||||
}
|
|
||||||
</Menu>
|
|
||||||
</Overlay>
|
|
||||||
|
|
||||||
<ChildContent>
|
|
||||||
<Button Type="@ButtonType.Primary">@group</Button>
|
|
||||||
</ChildContent>
|
|
||||||
</Dropdown>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (ArchiveId != Guid.Empty)
|
|
||||||
{
|
|
||||||
<Button Icon="@IconType.Outline.FolderOpen" OnClick="BrowseForPath" Type="@ButtonType.Text">Browse</Button>
|
|
||||||
}
|
|
||||||
|
|
||||||
<Button Icon="@IconType.Outline.Build" OnClick="() => RegToPowerShell.Open()" Type="@ButtonType.Text">Import .reg</Button>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem>
|
|
||||||
<StandaloneCodeEditor @ref="Editor" Id="editor" ConstructionOptions="EditorConstructionOptions" />
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem Label="Name">
|
|
||||||
<Input @bind-Value="@context.Name" />
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem Label="Type">
|
|
||||||
<Select @bind-Value="context.Type" TItem="ScriptType" TItemValue="ScriptType" DataSource="Enum.GetValues<ScriptType>().Where(st => AllowedTypes == null || AllowedTypes.Contains(st))">
|
|
||||||
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
|
||||||
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem>
|
|
||||||
<Checkbox @bind-Checked="context.RequiresAdmin">Requires Admin</Checkbox>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem Label="Description">
|
|
||||||
<TextArea @bind-Value="context.Description" MaxLength=500 ShowCount />
|
|
||||||
</FormItem>
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<RegToPowerShell @ref="RegToPowerShell" OnParsed="(text) => InsertText(text)" />
|
|
||||||
|
|
||||||
<Space Direction="DirectionVHType.Vertical" Size="@("large")" Style="width: 100%">
|
<Space Direction="DirectionVHType.Vertical" Size="@("large")" Style="width: 100%">
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
|
@ -85,8 +22,9 @@
|
||||||
<ActionColumn Title="">
|
<ActionColumn Title="">
|
||||||
<Space Style="display: flex; justify-content: end">
|
<Space Style="display: flex; justify-content: end">
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
<Button OnClick="() => Edit(context)" Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" />
|
<Button OnClick="() => Edit(context.Id)" Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" />
|
||||||
|
</SpaceItem>
|
||||||
|
<SpaceItem>
|
||||||
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this script?">
|
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this script?">
|
||||||
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
|
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
|
@ -115,61 +53,51 @@
|
||||||
[Parameter] public Guid GameId { get; set; }
|
[Parameter] public Guid GameId { get; set; }
|
||||||
[Parameter] public Guid RedistributableId { get; set; }
|
[Parameter] public Guid RedistributableId { get; set; }
|
||||||
[Parameter] public Guid ArchiveId { get; set; }
|
[Parameter] public Guid ArchiveId { get; set; }
|
||||||
[Parameter] public ICollection<Script> Scripts { get; set; }
|
|
||||||
[Parameter] public EventCallback<ICollection<Script>> ScriptsChanged { get; set; }
|
|
||||||
[Parameter] public IEnumerable<ScriptType> AllowedTypes { get; set; }
|
[Parameter] public IEnumerable<ScriptType> AllowedTypes { get; set; }
|
||||||
|
|
||||||
Script Script;
|
ICollection<Script> Scripts { get; set; } = new List<Script>();
|
||||||
|
|
||||||
bool ModalVisible = false;
|
protected override async Task OnParametersSetAsync()
|
||||||
|
|
||||||
IEnumerable<Snippet> Snippets { get; set; }
|
|
||||||
StandaloneCodeEditor? Editor;
|
|
||||||
RegToPowerShell RegToPowerShell;
|
|
||||||
|
|
||||||
private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
|
|
||||||
{
|
{
|
||||||
return new StandaloneEditorConstructionOptions
|
await LoadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadData()
|
||||||
|
{
|
||||||
|
if (GameId != Guid.Empty)
|
||||||
|
Scripts = await ScriptService.Get(s => s.GameId == GameId).ToListAsync();
|
||||||
|
else if (RedistributableId != Guid.Empty)
|
||||||
|
Scripts = await ScriptService.Get(s => s.RedistributableId == RedistributableId).ToListAsync();
|
||||||
|
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Edit(Guid? scriptId = null)
|
||||||
|
{
|
||||||
|
var modalOptions = new ModalOptions()
|
||||||
{
|
{
|
||||||
AutomaticLayout = true,
|
Title = scriptId == null ? "Add Script" : "Edit Script",
|
||||||
Language = "powershell",
|
Maximizable = false,
|
||||||
Value = Script.Contents,
|
DefaultMaximized = true,
|
||||||
Theme = "vs-dark",
|
Closable = true,
|
||||||
|
OkText = "Save"
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
var options = new ScriptEditorOptions()
|
||||||
{
|
{
|
||||||
if (Scripts == null)
|
ScriptId = scriptId ?? default,
|
||||||
Scripts = new List<Script>();
|
AllowedTypes = AllowedTypes,
|
||||||
|
ArchiveId = ArchiveId,
|
||||||
|
GameId = GameId,
|
||||||
|
RedistributableId = RedistributableId
|
||||||
|
};
|
||||||
|
|
||||||
Snippets = ScriptService.GetSnippets();
|
var modalRef = await ModalService.CreateModalAsync<ScriptEditorDialog, ScriptEditorOptions, Script>(modalOptions, options);
|
||||||
|
|
||||||
if (Script == null)
|
modalRef.OnOk = async (script) =>
|
||||||
Script = new Script();
|
{
|
||||||
}
|
await LoadData();
|
||||||
|
};
|
||||||
private async void Edit(Script script = null)
|
|
||||||
{
|
|
||||||
if (script == null) {
|
|
||||||
if (GameId != Guid.Empty)
|
|
||||||
Script = new Script() { GameId = GameId };
|
|
||||||
|
|
||||||
if (RedistributableId != Guid.Empty)
|
|
||||||
Script = new Script() { RedistributableId = RedistributableId };
|
|
||||||
|
|
||||||
if (Editor != null)
|
|
||||||
await Editor.SetValue("");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Script = script;
|
|
||||||
|
|
||||||
if (Editor != null && Script != null)
|
|
||||||
await Editor.SetValue(Script.Contents);
|
|
||||||
|
|
||||||
ModalVisible = true;
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Delete(Script script = null)
|
private async void Delete(Script script = null)
|
||||||
|
@ -179,81 +107,4 @@
|
||||||
|
|
||||||
await MessageService.Success("Script deleted!");
|
await MessageService.Success("Script deleted!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Close()
|
|
||||||
{
|
|
||||||
ModalVisible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Save()
|
|
||||||
{
|
|
||||||
var value = await Editor.GetValue();
|
|
||||||
|
|
||||||
Script.Contents = value;
|
|
||||||
|
|
||||||
if (Script.Id == Guid.Empty)
|
|
||||||
Script = await ScriptService.Add(Script);
|
|
||||||
else
|
|
||||||
Script = await ScriptService.Update(Script);
|
|
||||||
|
|
||||||
Close();
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
|
|
||||||
await MessageService.Success("Script saved!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task InsertText(string text)
|
|
||||||
{
|
|
||||||
var line = await Editor.GetPosition();
|
|
||||||
var range = new BlazorMonaco.Range(line.LineNumber, 1, line.LineNumber, 1);
|
|
||||||
|
|
||||||
var currentSelections = await Editor.GetSelections();
|
|
||||||
|
|
||||||
await Editor.ExecuteEdits("ScriptEditor", new List<IdentifiedSingleEditOperation>()
|
|
||||||
{
|
|
||||||
new IdentifiedSingleEditOperation
|
|
||||||
{
|
|
||||||
Range = range,
|
|
||||||
Text = text,
|
|
||||||
ForceMoveMarkers = true
|
|
||||||
}
|
|
||||||
}, currentSelections);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task InsertSnippet(Snippet snippet)
|
|
||||||
{
|
|
||||||
await InsertText(snippet.Content);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void BrowseForPath()
|
|
||||||
{
|
|
||||||
var modalOptions = new ModalOptions()
|
|
||||||
{
|
|
||||||
Title = "Choose Reference",
|
|
||||||
Maximizable = false,
|
|
||||||
DefaultMaximized = true,
|
|
||||||
Closable = true,
|
|
||||||
OkText = "Insert File Path"
|
|
||||||
};
|
|
||||||
|
|
||||||
var browserOptions = new FilePickerOptions()
|
|
||||||
{
|
|
||||||
ArchiveId = ArchiveId,
|
|
||||||
Select = true,
|
|
||||||
Multiple = false
|
|
||||||
};
|
|
||||||
|
|
||||||
var modalRef = await ModalService.CreateModalAsync<FilePickerDialog, FilePickerOptions, IEnumerable<IFileManagerEntry>>(modalOptions, browserOptions);
|
|
||||||
|
|
||||||
modalRef.OnOk = (results) =>
|
|
||||||
{
|
|
||||||
var path = results.FirstOrDefault().Path;
|
|
||||||
|
|
||||||
InsertText($"$InstallDir\\{path.Replace('/', '\\')}");
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
@using LANCommander.Components.FileManagerComponents;
|
||||||
|
@using LANCommander.Extensions;
|
||||||
|
@using LANCommander.Data.Enums;
|
||||||
|
@using LANCommander.Models;
|
||||||
|
@inherits FeedbackComponent<ScriptEditorOptions, Script>
|
||||||
|
@inject ScriptService ScriptService
|
||||||
|
@inject ModalService ModalService
|
||||||
|
@inject IMessageService MessageService
|
||||||
|
|
||||||
|
<Form Model="@Script" Layout="@FormLayout.Vertical">
|
||||||
|
<FormItem>
|
||||||
|
@foreach (var group in Snippets.Select(s => s.Group).Distinct())
|
||||||
|
{
|
||||||
|
<Dropdown>
|
||||||
|
<Overlay>
|
||||||
|
<Menu>
|
||||||
|
@foreach (var snippet in Snippets.Where(s => s.Group == group))
|
||||||
|
{
|
||||||
|
<MenuItem OnClick="() => InsertSnippet(snippet)">
|
||||||
|
@snippet.Name
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
|
</Menu>
|
||||||
|
</Overlay>
|
||||||
|
|
||||||
|
<ChildContent>
|
||||||
|
<Button Type="@ButtonType.Primary">@group</Button>
|
||||||
|
</ChildContent>
|
||||||
|
</Dropdown>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (Options.ArchiveId != Guid.Empty)
|
||||||
|
{
|
||||||
|
<Button Icon="@IconType.Outline.FolderOpen" OnClick="BrowseForPath" Type="@ButtonType.Text">Browse</Button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<Button Icon="@IconType.Outline.Build" OnClick="() => RegToPowerShell.Open()" Type="@ButtonType.Text">Import .reg</Button>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem>
|
||||||
|
<StandaloneCodeEditor @ref="Editor" Id="@("editor-" + Id.ToString())" ConstructionOptions="EditorConstructionOptions" />
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem Label="Name">
|
||||||
|
<Input @bind-Value="@context.Name" />
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem Label="Type">
|
||||||
|
<Select @bind-Value="context.Type" TItem="ScriptType" TItemValue="ScriptType" DataSource="Enum.GetValues<ScriptType>().Where(st => Options.AllowedTypes == null || Options.AllowedTypes.Contains(st))">
|
||||||
|
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
||||||
|
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem>
|
||||||
|
<Checkbox @bind-Checked="context.RequiresAdmin">Requires Admin</Checkbox>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem Label="Description">
|
||||||
|
<TextArea @bind-Value="context.Description" MaxLength=500 ShowCount />
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
|
||||||
|
<RegToPowerShell @ref="RegToPowerShell" OnParsed="(text) => InsertText(text)" />
|
||||||
|
|
||||||
|
@code {
|
||||||
|
Guid Id = Guid.NewGuid();
|
||||||
|
Script Script;
|
||||||
|
StandaloneCodeEditor? Editor;
|
||||||
|
RegToPowerShell RegToPowerShell;
|
||||||
|
IEnumerable<Snippet> Snippets { get; set; }
|
||||||
|
|
||||||
|
private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
|
||||||
|
{
|
||||||
|
return new StandaloneEditorConstructionOptions
|
||||||
|
{
|
||||||
|
AutomaticLayout = true,
|
||||||
|
Language = "powershell",
|
||||||
|
Value = Script.Contents,
|
||||||
|
Theme = "vs-dark",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (Options.ScriptId != Guid.Empty)
|
||||||
|
Script = await ScriptService.Get(Options.ScriptId);
|
||||||
|
else if (Options.GameId != Guid.Empty)
|
||||||
|
Script = new Script()
|
||||||
|
{
|
||||||
|
GameId = Options.GameId
|
||||||
|
};
|
||||||
|
else if (Options.RedistributableId != Guid.Empty)
|
||||||
|
Script = new Script()
|
||||||
|
{
|
||||||
|
RedistributableId = Options.RedistributableId
|
||||||
|
};
|
||||||
|
|
||||||
|
Snippets = ScriptService.GetSnippets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args)
|
||||||
|
{
|
||||||
|
await Save();
|
||||||
|
|
||||||
|
Editor.Dispose();
|
||||||
|
|
||||||
|
await base.OkCancelRefWithResult!.OnOk(Script);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task CancelAsync(ModalClosingEventArgs args)
|
||||||
|
{
|
||||||
|
Editor.Dispose();
|
||||||
|
|
||||||
|
await base.CancelAsync(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void BrowseForPath()
|
||||||
|
{
|
||||||
|
|
||||||
|
var modalOptions = new ModalOptions()
|
||||||
|
{
|
||||||
|
Title = "Choose Reference",
|
||||||
|
Maximizable = false,
|
||||||
|
DefaultMaximized = true,
|
||||||
|
Closable = true,
|
||||||
|
OkText = "Insert File Path"
|
||||||
|
};
|
||||||
|
|
||||||
|
var browserOptions = new FilePickerOptions()
|
||||||
|
{
|
||||||
|
ArchiveId = Options.ArchiveId,
|
||||||
|
Select = true,
|
||||||
|
Multiple = false
|
||||||
|
};
|
||||||
|
|
||||||
|
var modalRef = await ModalService.CreateModalAsync<FilePickerDialog, FilePickerOptions, IEnumerable<IFileManagerEntry>>(modalOptions, browserOptions);
|
||||||
|
|
||||||
|
modalRef.OnOk = (results) =>
|
||||||
|
{
|
||||||
|
var path = results.FirstOrDefault().Path;
|
||||||
|
|
||||||
|
InsertText($"$InstallDir\\{path.Replace('/', '\\')}");
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InsertText(string text)
|
||||||
|
{
|
||||||
|
var line = await Editor.GetPosition();
|
||||||
|
var range = new BlazorMonaco.Range(line.LineNumber, 1, line.LineNumber, 1);
|
||||||
|
|
||||||
|
var currentSelections = await Editor.GetSelections();
|
||||||
|
|
||||||
|
await Editor.ExecuteEdits("ScriptEditor", new List<IdentifiedSingleEditOperation>()
|
||||||
|
{
|
||||||
|
new IdentifiedSingleEditOperation
|
||||||
|
{
|
||||||
|
Range = range,
|
||||||
|
Text = text,
|
||||||
|
ForceMoveMarkers = true
|
||||||
|
}
|
||||||
|
}, currentSelections);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InsertSnippet(Snippet snippet)
|
||||||
|
{
|
||||||
|
await InsertText(snippet.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Save()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var value = await Editor.GetValue();
|
||||||
|
|
||||||
|
Script.Contents = value;
|
||||||
|
|
||||||
|
if (Script.Id == Guid.Empty)
|
||||||
|
Script = await ScriptService.Add(Script);
|
||||||
|
else
|
||||||
|
Script = await ScriptService.Update(Script);
|
||||||
|
|
||||||
|
MessageService.Success("Script saved!");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageService.Error("Script could not be saved!");
|
||||||
|
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<Select Mode="tags" TItem="Guid" TItemValue="Guid" @bind-Values="@SelectedValues" OnSelectedItemsChanged="OnSelectedItemsChanged" EnableSearch>
|
<Select Mode="tags" TItem="Guid" TItemValue="Guid" @bind-Values="@SelectedValues" OnSelectedItemsChanged="OnSelectedItemsChanged" EnableSearch>
|
||||||
<SelectOptions>
|
<SelectOptions>
|
||||||
@foreach (var entity in Entities)
|
@foreach (var entity in Entities.OrderBy(OptionLabelSelector))
|
||||||
{
|
{
|
||||||
<SelectOption TItemValue="Guid" TItem="Guid" Value="@entity.Id" Label="@OptionLabelSelector.Invoke(entity)" />
|
<SelectOption TItemValue="Guid" TItem="Guid" Value="@entity.Id" Label="@OptionLabelSelector.Invoke(entity)" />
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ValuesChanged.HasDelegate)
|
if (ValuesChanged.HasDelegate)
|
||||||
await ValuesChanged.InvokeAsync();
|
await ValuesChanged.InvokeAsync(Values);
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
Title = TitleSelector.Invoke(i)
|
Title = TitleSelector.Invoke(i)
|
||||||
});
|
});
|
||||||
|
|
||||||
TargetKeys = Values.Select(i => i.Id.ToString()).ToList();
|
if (Values != null)
|
||||||
|
TargetKeys = Values.Select(i => i.Id.ToString()).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
using LANCommander.Data.Models;
|
||||||
|
using LANCommander.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LANCommander.Controllers.Api
|
||||||
|
{
|
||||||
|
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class PlaySessionsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly PlaySessionService PlaySessionService;
|
||||||
|
private readonly GameService GameService;
|
||||||
|
private readonly UserManager<User> UserManager;
|
||||||
|
|
||||||
|
public PlaySessionsController(PlaySessionService playSessionService, GameService gameService, UserManager<User> userManager)
|
||||||
|
{
|
||||||
|
PlaySessionService = playSessionService;
|
||||||
|
GameService = gameService;
|
||||||
|
UserManager = userManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("Start/{id}")]
|
||||||
|
public async Task<IActionResult> Start(Guid id)
|
||||||
|
{
|
||||||
|
var user = await UserManager.FindByNameAsync(User.Identity.Name);
|
||||||
|
var game = await GameService.Get(id);
|
||||||
|
|
||||||
|
if (game == null || user == null)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
await PlaySessionService.StartSession(game.Id, user.Id);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("End/{id}")]
|
||||||
|
public async Task<IActionResult> End(Guid id)
|
||||||
|
{
|
||||||
|
var user = await UserManager.FindByNameAsync(User.Identity.Name);
|
||||||
|
var game = await GameService.Get(id);
|
||||||
|
|
||||||
|
if (game == null || user == null)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
await PlaySessionService.EndSession(game.Id, user.Id);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,14 @@ namespace LANCommander.Controllers
|
||||||
if (!System.IO.File.Exists(filename))
|
if (!System.IO.File.Exists(filename))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", $"{archive.Game.Title.SanitizeFilename()}.zip");
|
string name = "";
|
||||||
|
|
||||||
|
if (archive.GameId != null && archive.GameId != Guid.Empty)
|
||||||
|
name = $"{archive.Game.Title.SanitizeFilename()}.zip";
|
||||||
|
else if (archive.RedistributableId != null && archive.RedistributableId != Guid.Empty)
|
||||||
|
name = $"{archive.Redistributable.Name.SanitizeFilename()}.zip";
|
||||||
|
|
||||||
|
return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace LANCommander.Controllers
|
||||||
if (!System.IO.File.Exists(filename))
|
if (!System.IO.File.Exists(filename))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/zip", $"{save.User?.UserName} - {save.Game?.Title} - {save.CreatedOn.ToString("MM-dd-yyyy.hh-mm")}");
|
return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/zip", $"{save.User?.UserName} - {(save.Game == null ? "Unknown" : save.Game?.Title)} - {save.CreatedOn.ToString("MM-dd-yyyy.hh-mm")}.zip");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,44 @@ namespace LANCommander.Controllers
|
||||||
if (server == null)
|
if (server == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
path = path.Replace('/', Path.DirectorySeparatorChar);
|
if (server.HttpPaths == null || server.HttpPaths.Count == 0)
|
||||||
|
|
||||||
var filename = Path.Combine(server.HTTPRootPath, path);
|
|
||||||
|
|
||||||
if (!System.IO.File.Exists(filename))
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", Path.GetFileName(filename));
|
// Sanitize
|
||||||
|
if (path == null)
|
||||||
|
path = "/";
|
||||||
|
|
||||||
|
path = path.Trim('/');
|
||||||
|
path = path + "/";
|
||||||
|
|
||||||
|
var httpPath = server.HttpPaths.FirstOrDefault(hp => path.StartsWith(hp.Path.TrimStart('/')));
|
||||||
|
|
||||||
|
// Check to see if there's a root path defined if nothing else matches
|
||||||
|
if (httpPath == null)
|
||||||
|
httpPath = server.HttpPaths.FirstOrDefault(hp => hp.Path == "/");
|
||||||
|
|
||||||
|
if (httpPath == null)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
var relativePath = path.Substring(httpPath.Path.TrimStart('/').Length).Replace('/', Path.DirectorySeparatorChar).TrimStart('\\');
|
||||||
|
|
||||||
|
var localPath = Path.Combine(httpPath.LocalPath, relativePath).TrimEnd('\\');
|
||||||
|
var attrs = System.IO.File.GetAttributes(localPath);
|
||||||
|
|
||||||
|
if ((attrs & FileAttributes.Directory) == FileAttributes.Directory)
|
||||||
|
{
|
||||||
|
if (!System.IO.Directory.Exists(localPath))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return Json(Directory.GetFileSystemEntries(localPath).Select(fse => fse.Substring(localPath.Length)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!System.IO.File.Exists(localPath))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return File(new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", Path.GetFileName(localPath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,26 @@ namespace LANCommander.Data
|
||||||
{
|
{
|
||||||
base.OnModelCreating(builder);
|
base.OnModelCreating(builder);
|
||||||
|
|
||||||
|
builder.ConfigureBaseRelationships<Data.Models.Action>();
|
||||||
|
builder.ConfigureBaseRelationships<Archive>();
|
||||||
|
builder.ConfigureBaseRelationships<Category>();
|
||||||
|
builder.ConfigureBaseRelationships<Collection>();
|
||||||
|
builder.ConfigureBaseRelationships<Company>();
|
||||||
|
builder.ConfigureBaseRelationships<Game>();
|
||||||
|
builder.ConfigureBaseRelationships<GameSave>();
|
||||||
|
builder.ConfigureBaseRelationships<Genre>();
|
||||||
|
builder.ConfigureBaseRelationships<Key>();
|
||||||
|
builder.ConfigureBaseRelationships<Media>();
|
||||||
|
builder.ConfigureBaseRelationships<MultiplayerMode>();
|
||||||
|
builder.ConfigureBaseRelationships<PlaySession>();
|
||||||
|
builder.ConfigureBaseRelationships<Redistributable>();
|
||||||
|
builder.ConfigureBaseRelationships<SavePath>();
|
||||||
|
builder.ConfigureBaseRelationships<Script>();
|
||||||
|
builder.ConfigureBaseRelationships<Server>();
|
||||||
|
builder.ConfigureBaseRelationships<ServerConsole>();
|
||||||
|
builder.ConfigureBaseRelationships<ServerHttpPath>();
|
||||||
|
builder.ConfigureBaseRelationships<Tag>();
|
||||||
|
|
||||||
builder.Entity<Genre>()
|
builder.Entity<Genre>()
|
||||||
.HasMany(g => g.Games)
|
.HasMany(g => g.Games)
|
||||||
.WithMany(g => g.Genres);
|
.WithMany(g => g.Genres);
|
||||||
|
@ -34,6 +54,7 @@ namespace LANCommander.Data
|
||||||
.HasMany(t => t.Games)
|
.HasMany(t => t.Games)
|
||||||
.WithMany(g => g.Tags);
|
.WithMany(g => g.Tags);
|
||||||
|
|
||||||
|
#region Game Relationships
|
||||||
builder.Entity<Game>()
|
builder.Entity<Game>()
|
||||||
.HasMany(g => g.Archives)
|
.HasMany(g => g.Archives)
|
||||||
.WithOne(g => g.Game)
|
.WithOne(g => g.Game)
|
||||||
|
@ -63,6 +84,28 @@ namespace LANCommander.Data
|
||||||
.IsRequired(true)
|
.IsRequired(true)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.Entity<Game>()
|
||||||
|
.HasMany(g => g.Media)
|
||||||
|
.WithOne(m => m.Game)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.Entity<Game>()
|
||||||
|
.HasMany(g => g.SavePaths)
|
||||||
|
.WithOne(p => p.Game)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.Entity<Game>()
|
||||||
|
.HasMany(g => g.PlaySessions)
|
||||||
|
.WithOne(ps => ps.Game)
|
||||||
|
.IsRequired(false)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
builder.Entity<Game>()
|
||||||
|
.HasMany(g => g.GameSaves)
|
||||||
|
.WithOne(gs => gs.Game)
|
||||||
|
.IsRequired(false)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
builder.Entity<Game>()
|
builder.Entity<Game>()
|
||||||
.HasMany(g => g.Developers)
|
.HasMany(g => g.Developers)
|
||||||
.WithMany(c => c.DevelopedGames)
|
.WithMany(c => c.DevelopedGames)
|
||||||
|
@ -89,29 +132,28 @@ namespace LANCommander.Data
|
||||||
gr => gr.HasOne<Redistributable>().WithMany().HasForeignKey("RedistributableId"),
|
gr => gr.HasOne<Redistributable>().WithMany().HasForeignKey("RedistributableId"),
|
||||||
gr => gr.HasOne<Game>().WithMany().HasForeignKey("GameId")
|
gr => gr.HasOne<Game>().WithMany().HasForeignKey("GameId")
|
||||||
);
|
);
|
||||||
|
#endregion
|
||||||
|
|
||||||
builder.Entity<Game>()
|
#region User Relationships
|
||||||
.HasMany(g => g.Media)
|
|
||||||
.WithOne(m => m.Game)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
builder.Entity<User>()
|
builder.Entity<User>()
|
||||||
.HasMany(u => u.GameSaves)
|
.HasMany(u => u.GameSaves)
|
||||||
.WithOne(gs => gs.User)
|
.WithOne(gs => gs.User)
|
||||||
.IsRequired(true)
|
.IsRequired(true)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
builder.Entity<Game>()
|
builder.Entity<User>()
|
||||||
.HasMany(g => g.GameSaves)
|
.HasMany(u => u.PlaySessions)
|
||||||
.WithOne(gs => gs.Game)
|
.WithOne(ps => ps.User)
|
||||||
.IsRequired(true)
|
.IsRequired(true)
|
||||||
.OnDelete(DeleteBehavior.NoAction);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Server Relationships
|
||||||
builder.Entity<Server>()
|
builder.Entity<Server>()
|
||||||
.HasOne(s => s.Game)
|
.HasOne(s => s.Game)
|
||||||
.WithMany(g => g.Servers)
|
.WithMany(g => g.Servers)
|
||||||
.IsRequired(false)
|
.IsRequired(false)
|
||||||
.OnDelete(DeleteBehavior.NoAction);
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
builder.Entity<Server>()
|
builder.Entity<Server>()
|
||||||
.HasMany<ServerConsole>()
|
.HasMany<ServerConsole>()
|
||||||
|
@ -119,6 +161,14 @@ namespace LANCommander.Data
|
||||||
.IsRequired(true)
|
.IsRequired(true)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.Entity<Server>()
|
||||||
|
.HasMany<ServerHttpPath>()
|
||||||
|
.WithOne(s => s.Server)
|
||||||
|
.IsRequired(true)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Redistributable Relationships
|
||||||
builder.Entity<Redistributable>()
|
builder.Entity<Redistributable>()
|
||||||
.HasMany(r => r.Archives)
|
.HasMany(r => r.Archives)
|
||||||
.WithOne(a => a.Redistributable)
|
.WithOne(a => a.Redistributable)
|
||||||
|
@ -130,6 +180,29 @@ namespace LANCommander.Data
|
||||||
.WithOne(s => s.Redistributable)
|
.WithOne(s => s.Redistributable)
|
||||||
.IsRequired(false)
|
.IsRequired(false)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Collection Relationships
|
||||||
|
builder.Entity<Collection>()
|
||||||
|
.HasMany(c => c.Games)
|
||||||
|
.WithMany(g => g.Collections)
|
||||||
|
.UsingEntity<Dictionary<string, object>>(
|
||||||
|
"CollectionGame",
|
||||||
|
cg => cg.HasOne<Game>().WithMany().HasForeignKey("GameId"),
|
||||||
|
cg => cg.HasOne<Collection>().WithMany().HasForeignKey("CollectionId")
|
||||||
|
);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Role Relationships
|
||||||
|
builder.Entity<Role>()
|
||||||
|
.HasMany(r => r.Collections)
|
||||||
|
.WithMany(c => c.Roles)
|
||||||
|
.UsingEntity<Dictionary<string, object>>(
|
||||||
|
"RoleCollection",
|
||||||
|
rc => rc.HasOne<Collection>().WithMany().HasForeignKey("CollectionId"),
|
||||||
|
rc => rc.HasOne<Role>().WithMany().HasForeignKey("RoleId")
|
||||||
|
);
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<Game>? Games { get; set; }
|
public DbSet<Game>? Games { get; set; }
|
||||||
|
@ -146,6 +219,8 @@ namespace LANCommander.Data
|
||||||
|
|
||||||
public DbSet<GameSave>? GameSaves { get; set; }
|
public DbSet<GameSave>? GameSaves { get; set; }
|
||||||
|
|
||||||
|
public DbSet<PlaySession>? PlaySessions { get; set; }
|
||||||
|
|
||||||
public DbSet<Server>? Servers { get; set; }
|
public DbSet<Server>? Servers { get; set; }
|
||||||
|
|
||||||
public DbSet<ServerConsole>? ServerConsoles { get; set; }
|
public DbSet<ServerConsole>? ServerConsoles { get; set; }
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
using LANCommander.Data.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LANCommander.Data
|
||||||
|
{
|
||||||
|
public static class ModelBuilderExtensions
|
||||||
|
{
|
||||||
|
public static void ConfigureBaseRelationships<T>(this ModelBuilder modelBuilder) where T : BaseModel
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<T>()
|
||||||
|
.HasOne(x => x.CreatedBy)
|
||||||
|
.WithMany()
|
||||||
|
.IsRequired(false)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
modelBuilder.Entity<T>()
|
||||||
|
.HasOne(x => x.UpdatedBy)
|
||||||
|
.WithMany()
|
||||||
|
.IsRequired(false)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,10 +10,13 @@ namespace LANCommander.Data.Models
|
||||||
|
|
||||||
[Display(Name = "Created On")]
|
[Display(Name = "Created On")]
|
||||||
public DateTime CreatedOn { get; set; }
|
public DateTime CreatedOn { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Created By")]
|
[Display(Name = "Created By")]
|
||||||
public virtual User? CreatedBy { get; set; }
|
public virtual User? CreatedBy { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Updated On")]
|
[Display(Name = "Updated On")]
|
||||||
public DateTime UpdatedOn { get; set; }
|
public DateTime UpdatedOn { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Updated By")]
|
[Display(Name = "Updated By")]
|
||||||
public virtual User? UpdatedBy { get; set; }
|
public virtual User? UpdatedBy { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace LANCommander.Data.Models
|
||||||
|
{
|
||||||
|
[Table("Collections")]
|
||||||
|
public class Collection : BaseModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual ICollection<Game> Games { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual ICollection<Role> Roles { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ namespace LANCommander.Data.Models
|
||||||
public virtual ICollection<Archive>? Archives { get; set; }
|
public virtual ICollection<Archive>? Archives { get; set; }
|
||||||
public virtual ICollection<Script>? Scripts { get; set; }
|
public virtual ICollection<Script>? Scripts { get; set; }
|
||||||
public virtual ICollection<GameSave>? GameSaves { get; set; }
|
public virtual ICollection<GameSave>? GameSaves { get; set; }
|
||||||
|
public virtual ICollection<PlaySession>? PlaySessions { get; set; }
|
||||||
public virtual ICollection<SavePath>? SavePaths { get; set; }
|
public virtual ICollection<SavePath>? SavePaths { get; set; }
|
||||||
public virtual ICollection<Server>? Servers { get; set; }
|
public virtual ICollection<Server>? Servers { get; set; }
|
||||||
public virtual ICollection<Redistributable>? Redistributables { get; set; }
|
public virtual ICollection<Redistributable>? Redistributables { get; set; }
|
||||||
|
@ -38,5 +39,6 @@ namespace LANCommander.Data.Models
|
||||||
|
|
||||||
public string? ValidKeyRegex { get; set; }
|
public string? ValidKeyRegex { get; set; }
|
||||||
public virtual ICollection<Key>? Keys { get; set; }
|
public virtual ICollection<Key>? Keys { get; set; }
|
||||||
|
public virtual ICollection<Collection> Collections { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace LANCommander.Data.Models
|
||||||
[Table("GameSaves")]
|
[Table("GameSaves")]
|
||||||
public class GameSave : BaseModel
|
public class GameSave : BaseModel
|
||||||
{
|
{
|
||||||
public Guid GameId { get; set; }
|
public Guid? GameId { get; set; }
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
[ForeignKey(nameof(GameId))]
|
[ForeignKey(nameof(GameId))]
|
||||||
[InverseProperty("GameSaves")]
|
[InverseProperty("GameSaves")]
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace LANCommander.Data.Models
|
||||||
|
{
|
||||||
|
[Table("PlaySessions")]
|
||||||
|
public class PlaySession : BaseModel
|
||||||
|
{
|
||||||
|
public Guid? GameId { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
[ForeignKey(nameof(GameId))]
|
||||||
|
[InverseProperty("PlaySessions")]
|
||||||
|
public virtual Game? Game { get; set; }
|
||||||
|
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
[ForeignKey(nameof(UserId))]
|
||||||
|
[InverseProperty("PlaySessions")]
|
||||||
|
public virtual User? User { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Start")]
|
||||||
|
public DateTime? Start { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "End")]
|
||||||
|
public DateTime? End { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,5 +6,6 @@ namespace LANCommander.Data.Models
|
||||||
[Table("Roles")]
|
[Table("Roles")]
|
||||||
public class Role : IdentityRole<Guid>
|
public class Role : IdentityRole<Guid>
|
||||||
{
|
{
|
||||||
|
public virtual ICollection<Collection> Collections { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace LANCommander.Data.Models
|
||||||
{
|
{
|
||||||
public SavePathType Type { get; set; }
|
public SavePathType Type { get; set; }
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
public bool IsRegex { get; set; }
|
||||||
|
|
||||||
public Guid? GameId { get; set; }
|
public Guid? GameId { get; set; }
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
|
|
@ -17,9 +17,6 @@ namespace LANCommander.Data.Models
|
||||||
public bool Autostart { get; set; }
|
public bool Autostart { get; set; }
|
||||||
public int AutostartDelay { get; set; }
|
public int AutostartDelay { get; set; }
|
||||||
|
|
||||||
public bool EnableHTTP { get; set; }
|
|
||||||
public string HTTPRootPath { get; set; }
|
|
||||||
|
|
||||||
public Guid? GameId { get; set; }
|
public Guid? GameId { get; set; }
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
[ForeignKey(nameof(GameId))]
|
[ForeignKey(nameof(GameId))]
|
||||||
|
@ -27,5 +24,6 @@ namespace LANCommander.Data.Models
|
||||||
public virtual Game? Game { get; set; }
|
public virtual Game? Game { get; set; }
|
||||||
|
|
||||||
public virtual ICollection<ServerConsole>? ServerConsoles { get; set; }
|
public virtual ICollection<ServerConsole>? ServerConsoles { get; set; }
|
||||||
|
public virtual ICollection<ServerHttpPath>? HttpPaths { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace LANCommander.Data.Models
|
||||||
|
{
|
||||||
|
public class ServerHttpPath : BaseModel
|
||||||
|
{
|
||||||
|
public string LocalPath { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
|
||||||
|
public Guid ServerId { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
[ForeignKey(nameof(ServerId))]
|
||||||
|
[InverseProperty("HttpPaths")]
|
||||||
|
public virtual Server Server { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,6 +46,9 @@ namespace LANCommander.Data.Models
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual ICollection<GameSave>? GameSaves { get; set; }
|
public virtual ICollection<GameSave>? GameSaves { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual ICollection<PlaySession>? PlaySessions { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<UserSecretsId>aspnet-LANCommander-C1F79CFA-9767-4AD7-BD5A-2549F8328A2D</UserSecretsId>
|
<UserSecretsId>aspnet-LANCommander-C1F79CFA-9767-4AD7-BD5A-2549F8328A2D</UserSecretsId>
|
||||||
|
@ -22,26 +22,26 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AntDesign" Version="0.15.5" />
|
<PackageReference Include="AntDesign" Version="0.16.1" />
|
||||||
<PackageReference Include="AntDesign.Charts" Version="0.3.1" />
|
<PackageReference Include="AntDesign.Charts" Version="0.3.2" />
|
||||||
<PackageReference Include="Blazor-ApexCharts" Version="1.0.1" />
|
<PackageReference Include="Blazor-ApexCharts" Version="1.0.1" />
|
||||||
<PackageReference Include="BlazorMonaco" Version="3.1.0" />
|
<PackageReference Include="BlazorMonaco" Version="3.1.0" />
|
||||||
<PackageReference Include="ByteSize" Version="2.1.1" />
|
<PackageReference Include="ByteSize" Version="2.1.1" />
|
||||||
<PackageReference Include="CoreRCON" Version="5.0.5" />
|
<PackageReference Include="CoreRCON" Version="5.0.5" />
|
||||||
<PackageReference Include="craftersmine.SteamGridDB.Net" Version="1.1.5" />
|
<PackageReference Include="craftersmine.SteamGridDB.Net" Version="1.1.5" />
|
||||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.5" />
|
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.6" />
|
||||||
<PackageReference Include="Hangfire.Core" Version="1.8.5" />
|
<PackageReference Include="Hangfire.Core" Version="1.8.6" />
|
||||||
<PackageReference Include="Hangfire.InMemory" Version="0.5.1" />
|
<PackageReference Include="Hangfire.InMemory" Version="0.6.0" />
|
||||||
<PackageReference Include="IGDB" Version="2.3.2" />
|
<PackageReference Include="IGDB" Version="2.3.2" />
|
||||||
<PackageReference Include="IPXRelayDotNet" Version="1.0.0" />
|
<PackageReference Include="IPXRelayDotNet" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.11" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.11" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -50,15 +50,15 @@
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.10" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
|
||||||
<PackageReference Include="NLog" Version="5.2.4" />
|
<PackageReference Include="NLog" Version="5.2.5" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.4" />
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.5" />
|
||||||
<PackageReference Include="RegParserDotNet" Version="1.0.4" />
|
<PackageReference Include="RegParserDotNet" Version="1.0.4" />
|
||||||
<PackageReference Include="rix0rrr.BeaconLib" Version="1.0.2" />
|
<PackageReference Include="rix0rrr.BeaconLib" Version="1.0.2" />
|
||||||
<PackageReference Include="swashbuckle" Version="5.6.0" />
|
<PackageReference Include="swashbuckle" Version="5.6.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="7.0.0" />
|
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="8.0.0" />
|
||||||
<PackageReference Include="XtermBlazor" Version="1.9.0" />
|
<PackageReference Include="XtermBlazor" Version="1.10.0" />
|
||||||
<PackageReference Include="YamlDotNet" Version="13.3.1" />
|
<PackageReference Include="YamlDotNet" Version="13.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -66,7 +66,6 @@
|
||||||
<Folder Include="bin\Debug\net6.0\" />
|
<Folder Include="bin\Debug\net6.0\" />
|
||||||
<Folder Include="Data\Migrations\" />
|
<Folder Include="Data\Migrations\" />
|
||||||
<Folder Include="Migrations\" />
|
<Folder Include="Migrations\" />
|
||||||
<Folder Include="Pages\Games\Archives\" />
|
|
||||||
<Folder Include="Scripts\" />
|
<Folder Include="Scripts\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -88,6 +87,81 @@
|
||||||
<None Update="favicon.png">
|
<None Update="favicon.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Copy Directory.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Create Directory.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Create Registry Path.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Get User Registry Virtual Store.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Patch Binary.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Remove Directory.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Rename File.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Sanitize Filename.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Set Compatibility Mode.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Set Registry Key.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Trim String.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Examples\Write to File.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Functions\Convert-AspectRatio.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Functions\ConvertTo-StringBytes.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Functions\Edit-PatchBinary.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Functions\Get-GameManifest.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Functions\Get-PrimaryDisplay.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Functions\Write-ReplaceContentInFile.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Variables\Allocated Key.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Variables\Default Install Directory.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Variables\Game Install Directory.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Variables\Game Manifest.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Variables\New Player Alias.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Variables\Old Player Alias.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Snippets\Variables\Server Address.ps1">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,82 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddServerHttpPaths : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ServerHttpPath",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
LocalPath = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Path = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
ServerId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
ServerId1 = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||||
|
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
CreatedById = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ServerHttpPath", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_Servers_ServerId",
|
||||||
|
column: x => x.ServerId,
|
||||||
|
principalTable: "Servers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_Servers_ServerId1",
|
||||||
|
column: x => x.ServerId1,
|
||||||
|
principalTable: "Servers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ServerHttpPath_CreatedById",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ServerHttpPath_ServerId",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "ServerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ServerHttpPath_ServerId1",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "ServerId1");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ServerHttpPath_UpdatedById",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "UpdatedById");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ServerHttpPath");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1691
LANCommander/Migrations/20231105210731_RemoveDeprecatedServerHttpOptions.Designer.cs
generated
Normal file
1691
LANCommander/Migrations/20231105210731_RemoveDeprecatedServerHttpOptions.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,40 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class RemoveDeprecatedServerHttpOptions : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "EnableHTTP",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "HTTPRootPath",
|
||||||
|
table: "Servers");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "EnableHTTP",
|
||||||
|
table: "Servers",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "HTTPRootPath",
|
||||||
|
table: "Servers",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1691
LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.Designer.cs
generated
Normal file
1691
LANCommander/Migrations/20231117064657_DeleteDeprecatedSnippets.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,56 @@
|
||||||
|
using LANCommander.Data.Enums;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class DeleteDeprecatedSnippets : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
string[] snippetsToRemove = new string[]
|
||||||
|
{
|
||||||
|
"Examples\\Replace Content In File.ps1",
|
||||||
|
"Examples\\Separate ASCII Bytes.ps1",
|
||||||
|
"Examples\\String to ASCII Bytes.ps1",
|
||||||
|
"Functions\\Get-43Resolution.ps1",
|
||||||
|
"Functions\\Get-AsciiBytes.ps1",
|
||||||
|
"Functions\\Patch-Binary.ps1",
|
||||||
|
"Functions\\Separate-AsciiBytes.ps1",
|
||||||
|
"Variables\\Display.ps1",
|
||||||
|
"Variables\\InstallDir.ps1",
|
||||||
|
"Variables\\NewName.ps1",
|
||||||
|
"Variables\\OldName.ps1",
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var snippet in snippetsToRemove)
|
||||||
|
{
|
||||||
|
var path = Path.Combine("Snippets", snippet);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$NewName = $args[0]' || char(13) || char(10), '')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$OldName = \"\"' || char(13) || char(10) || 'if ($args[1]) {' || char(13) || char(10) || char(9) || '$OldName = $args[1]' || char(13) || char(10) || '}' || char(13) || char(10), '')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$InstallDir = $PSScriptRoot' || char(13) || char(10), '')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$InstallDir', '$InstallDirectory')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$NewName', '$NewPlayerAlias')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$OldName', '$OldPlayerAlias')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, 'function Write-ReplaceContentInFile', 'function Write-ReplaceContentInFile-Old')");
|
||||||
|
migrationBuilder.Sql($"UPDATE Scripts SET Contents = REPLACE(Contents, '$args[0]', '$AllocatedKey') WHERE Type = {(int)ScriptType.Install}");
|
||||||
|
migrationBuilder.Sql($"UPDATE Scripts SET Contents = REPLACE(Contents, '$args[0]', '$AllocatedKey') WHERE Type = {(int)ScriptType.KeyChange}");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, 'Add-Type -AssemblyName System.Windows.Forms' || char(13) || char(10), '')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$Display = [System.Windows.Forms.Screen]::AllScreens | Where-Object Primary | Select Bounds', '$Display = Get-PrimaryDisplay')");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,82 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPlaySessions : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PlaySessions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
GameId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
UserId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Start = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
End = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
CreatedById = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PlaySessions", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaySessions_Games_GameId",
|
||||||
|
column: x => x.GameId,
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PlaySessions_CreatedById",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PlaySessions_GameId",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "GameId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PlaySessions_UpdatedById",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "UpdatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PlaySessions_UserId",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PlaySessions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,975 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class FixDeletionBehaviors : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_CreatedById",
|
||||||
|
table: "Actions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_UpdatedById",
|
||||||
|
table: "Actions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_CreatedById",
|
||||||
|
table: "Archive");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_UpdatedById",
|
||||||
|
table: "Archive");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_CreatedById",
|
||||||
|
table: "Categories");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_UpdatedById",
|
||||||
|
table: "Categories");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_CreatedById",
|
||||||
|
table: "Companies");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_UpdatedById",
|
||||||
|
table: "Companies");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_CreatedById",
|
||||||
|
table: "Games");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_UpdatedById",
|
||||||
|
table: "Games");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_CreatedById",
|
||||||
|
table: "GameSaves");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_UpdatedById",
|
||||||
|
table: "GameSaves");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_GameSaves_Games_GameId",
|
||||||
|
table: "GameSaves");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_CreatedById",
|
||||||
|
table: "Genres");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_UpdatedById",
|
||||||
|
table: "Genres");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_CreatedById",
|
||||||
|
table: "Keys");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_UpdatedById",
|
||||||
|
table: "Keys");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_CreatedById",
|
||||||
|
table: "Media");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_UpdatedById",
|
||||||
|
table: "Media");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_CreatedById",
|
||||||
|
table: "MultiplayerModes");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_UpdatedById",
|
||||||
|
table: "MultiplayerModes");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_CreatedById",
|
||||||
|
table: "PlaySessions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_UpdatedById",
|
||||||
|
table: "PlaySessions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PlaySessions_Games_GameId",
|
||||||
|
table: "PlaySessions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_CreatedById",
|
||||||
|
table: "Redistributables");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_UpdatedById",
|
||||||
|
table: "Redistributables");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_CreatedById",
|
||||||
|
table: "SavePaths");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_UpdatedById",
|
||||||
|
table: "SavePaths");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SavePaths_Games_GameId",
|
||||||
|
table: "SavePaths");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_CreatedById",
|
||||||
|
table: "Scripts");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_UpdatedById",
|
||||||
|
table: "Scripts");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerConsoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerConsoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerHttpPath");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerHttpPath");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_CreatedById",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_UpdatedById",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Servers_Games_GameId",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_CreatedById",
|
||||||
|
table: "Tags");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_UpdatedById",
|
||||||
|
table: "Tags");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<Guid>(
|
||||||
|
name: "GameId",
|
||||||
|
table: "PlaySessions",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(Guid),
|
||||||
|
oldType: "TEXT");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<Guid>(
|
||||||
|
name: "GameId",
|
||||||
|
table: "GameSaves",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(Guid),
|
||||||
|
oldType: "TEXT");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_CreatedById",
|
||||||
|
table: "Actions",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_UpdatedById",
|
||||||
|
table: "Actions",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_CreatedById",
|
||||||
|
table: "Archive",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_UpdatedById",
|
||||||
|
table: "Archive",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_CreatedById",
|
||||||
|
table: "Categories",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_UpdatedById",
|
||||||
|
table: "Categories",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_CreatedById",
|
||||||
|
table: "Companies",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_UpdatedById",
|
||||||
|
table: "Companies",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_CreatedById",
|
||||||
|
table: "Games",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_UpdatedById",
|
||||||
|
table: "Games",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_CreatedById",
|
||||||
|
table: "GameSaves",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_UpdatedById",
|
||||||
|
table: "GameSaves",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_GameSaves_Games_GameId",
|
||||||
|
table: "GameSaves",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_CreatedById",
|
||||||
|
table: "Genres",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_UpdatedById",
|
||||||
|
table: "Genres",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_CreatedById",
|
||||||
|
table: "Keys",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_UpdatedById",
|
||||||
|
table: "Keys",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_CreatedById",
|
||||||
|
table: "Media",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_UpdatedById",
|
||||||
|
table: "Media",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_CreatedById",
|
||||||
|
table: "MultiplayerModes",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_UpdatedById",
|
||||||
|
table: "MultiplayerModes",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_CreatedById",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_UpdatedById",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PlaySessions_Games_GameId",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_CreatedById",
|
||||||
|
table: "Redistributables",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_UpdatedById",
|
||||||
|
table: "Redistributables",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_CreatedById",
|
||||||
|
table: "SavePaths",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_UpdatedById",
|
||||||
|
table: "SavePaths",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SavePaths_Games_GameId",
|
||||||
|
table: "SavePaths",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_CreatedById",
|
||||||
|
table: "Scripts",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_UpdatedById",
|
||||||
|
table: "Scripts",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerConsoles",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerConsoles",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_CreatedById",
|
||||||
|
table: "Servers",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_UpdatedById",
|
||||||
|
table: "Servers",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Servers_Games_GameId",
|
||||||
|
table: "Servers",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_CreatedById",
|
||||||
|
table: "Tags",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_UpdatedById",
|
||||||
|
table: "Tags",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_CreatedById",
|
||||||
|
table: "Actions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_UpdatedById",
|
||||||
|
table: "Actions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_CreatedById",
|
||||||
|
table: "Archive");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_UpdatedById",
|
||||||
|
table: "Archive");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_CreatedById",
|
||||||
|
table: "Categories");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_UpdatedById",
|
||||||
|
table: "Categories");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_CreatedById",
|
||||||
|
table: "Companies");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_UpdatedById",
|
||||||
|
table: "Companies");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_CreatedById",
|
||||||
|
table: "Games");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_UpdatedById",
|
||||||
|
table: "Games");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_CreatedById",
|
||||||
|
table: "GameSaves");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_UpdatedById",
|
||||||
|
table: "GameSaves");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_GameSaves_Games_GameId",
|
||||||
|
table: "GameSaves");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_CreatedById",
|
||||||
|
table: "Genres");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_UpdatedById",
|
||||||
|
table: "Genres");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_CreatedById",
|
||||||
|
table: "Keys");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_UpdatedById",
|
||||||
|
table: "Keys");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_CreatedById",
|
||||||
|
table: "Media");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_UpdatedById",
|
||||||
|
table: "Media");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_CreatedById",
|
||||||
|
table: "MultiplayerModes");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_UpdatedById",
|
||||||
|
table: "MultiplayerModes");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_CreatedById",
|
||||||
|
table: "PlaySessions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_UpdatedById",
|
||||||
|
table: "PlaySessions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PlaySessions_Games_GameId",
|
||||||
|
table: "PlaySessions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_CreatedById",
|
||||||
|
table: "Redistributables");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_UpdatedById",
|
||||||
|
table: "Redistributables");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_CreatedById",
|
||||||
|
table: "SavePaths");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_UpdatedById",
|
||||||
|
table: "SavePaths");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SavePaths_Games_GameId",
|
||||||
|
table: "SavePaths");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_CreatedById",
|
||||||
|
table: "Scripts");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_UpdatedById",
|
||||||
|
table: "Scripts");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerConsoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerConsoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerHttpPath");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerHttpPath");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_CreatedById",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_UpdatedById",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Servers_Games_GameId",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_CreatedById",
|
||||||
|
table: "Tags");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_UpdatedById",
|
||||||
|
table: "Tags");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<Guid>(
|
||||||
|
name: "GameId",
|
||||||
|
table: "PlaySessions",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||||
|
oldClrType: typeof(Guid),
|
||||||
|
oldType: "TEXT",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<Guid>(
|
||||||
|
name: "GameId",
|
||||||
|
table: "GameSaves",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||||
|
oldClrType: typeof(Guid),
|
||||||
|
oldType: "TEXT",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_CreatedById",
|
||||||
|
table: "Actions",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Actions_AspNetUsers_UpdatedById",
|
||||||
|
table: "Actions",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_CreatedById",
|
||||||
|
table: "Archive",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Archive_AspNetUsers_UpdatedById",
|
||||||
|
table: "Archive",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_CreatedById",
|
||||||
|
table: "Categories",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Categories_AspNetUsers_UpdatedById",
|
||||||
|
table: "Categories",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_CreatedById",
|
||||||
|
table: "Companies",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Companies_AspNetUsers_UpdatedById",
|
||||||
|
table: "Companies",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_CreatedById",
|
||||||
|
table: "Games",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Games_AspNetUsers_UpdatedById",
|
||||||
|
table: "Games",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_CreatedById",
|
||||||
|
table: "GameSaves",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_GameSaves_AspNetUsers_UpdatedById",
|
||||||
|
table: "GameSaves",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_GameSaves_Games_GameId",
|
||||||
|
table: "GameSaves",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_CreatedById",
|
||||||
|
table: "Genres",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Genres_AspNetUsers_UpdatedById",
|
||||||
|
table: "Genres",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_CreatedById",
|
||||||
|
table: "Keys",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Keys_AspNetUsers_UpdatedById",
|
||||||
|
table: "Keys",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_CreatedById",
|
||||||
|
table: "Media",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Media_AspNetUsers_UpdatedById",
|
||||||
|
table: "Media",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_CreatedById",
|
||||||
|
table: "MultiplayerModes",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MultiplayerModes_AspNetUsers_UpdatedById",
|
||||||
|
table: "MultiplayerModes",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_CreatedById",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PlaySessions_AspNetUsers_UpdatedById",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PlaySessions_Games_GameId",
|
||||||
|
table: "PlaySessions",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_CreatedById",
|
||||||
|
table: "Redistributables",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Redistributables_AspNetUsers_UpdatedById",
|
||||||
|
table: "Redistributables",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_CreatedById",
|
||||||
|
table: "SavePaths",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SavePaths_AspNetUsers_UpdatedById",
|
||||||
|
table: "SavePaths",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SavePaths_Games_GameId",
|
||||||
|
table: "SavePaths",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_CreatedById",
|
||||||
|
table: "Scripts",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Scripts_AspNetUsers_UpdatedById",
|
||||||
|
table: "Scripts",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerConsoles",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerConsoles_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerConsoles",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_CreatedById",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ServerHttpPath_AspNetUsers_UpdatedById",
|
||||||
|
table: "ServerHttpPath",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_CreatedById",
|
||||||
|
table: "Servers",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Servers_AspNetUsers_UpdatedById",
|
||||||
|
table: "Servers",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Servers_Games_GameId",
|
||||||
|
table: "Servers",
|
||||||
|
column: "GameId",
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_CreatedById",
|
||||||
|
table: "Tags",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Tags_AspNetUsers_UpdatedById",
|
||||||
|
table: "Tags",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,29 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddSavePathRegexFlag : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsRegex",
|
||||||
|
table: "SavePaths",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsRegex",
|
||||||
|
table: "SavePaths");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1807
LANCommander/Migrations/20231203202813_FixScriptDisplayBounds.Designer.cs
generated
Normal file
1807
LANCommander/Migrations/20231203202813_FixScriptDisplayBounds.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class FixScriptDisplayBounds : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$Display.Width', '$Display.Bounds.Width')");
|
||||||
|
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$Display.Height', '$Display.Bounds.Height')");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,124 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddCollections : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Collections",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
CreatedById = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Collections", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Collections_AspNetUsers_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Collections_AspNetUsers_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "CollectionGame",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
CollectionId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
GameId = table.Column<Guid>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_CollectionGame", x => new { x.CollectionId, x.GameId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_CollectionGame_Collections_CollectionId",
|
||||||
|
column: x => x.CollectionId,
|
||||||
|
principalTable: "Collections",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_CollectionGame_Games_GameId",
|
||||||
|
column: x => x.GameId,
|
||||||
|
principalTable: "Games",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "RoleCollection",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
CollectionId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
RoleId = table.Column<Guid>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_RoleCollection", x => new { x.CollectionId, x.RoleId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_RoleCollection_AspNetRoles_RoleId",
|
||||||
|
column: x => x.RoleId,
|
||||||
|
principalTable: "AspNetRoles",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_RoleCollection_Collections_CollectionId",
|
||||||
|
column: x => x.CollectionId,
|
||||||
|
principalTable: "Collections",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CollectionGame_GameId",
|
||||||
|
table: "CollectionGame",
|
||||||
|
column: "GameId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Collections_CreatedById",
|
||||||
|
table: "Collections",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Collections_UpdatedById",
|
||||||
|
table: "Collections",
|
||||||
|
column: "UpdatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_RoleCollection_RoleId",
|
||||||
|
table: "RoleCollection",
|
||||||
|
column: "RoleId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "CollectionGame");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "RoleCollection");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Collections");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "7.0.11")
|
.HasAnnotation("ProductVersion", "8.0.0")
|
||||||
.HasAnnotation("Proxies:ChangeTracking", false)
|
.HasAnnotation("Proxies:ChangeTracking", false)
|
||||||
.HasAnnotation("Proxies:CheckEquality", false)
|
.HasAnnotation("Proxies:CheckEquality", false)
|
||||||
.HasAnnotation("Proxies:LazyLoading", true);
|
.HasAnnotation("Proxies:LazyLoading", true);
|
||||||
|
@ -36,6 +36,21 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("CategoryGame");
|
b.ToTable("CategoryGame");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CollectionGame", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("CollectionId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("GameId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("CollectionId", "GameId");
|
||||||
|
|
||||||
|
b.HasIndex("GameId");
|
||||||
|
|
||||||
|
b.ToTable("CollectionGame");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameDeveloper", b =>
|
modelBuilder.Entity("GameDeveloper", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("DeveloperId")
|
b.Property<Guid>("DeveloperId")
|
||||||
|
@ -257,6 +272,37 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("Categories");
|
b.ToTable("Categories");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CreatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UpdatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.HasIndex("UpdatedById");
|
||||||
|
|
||||||
|
b.ToTable("Collections");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
@ -355,7 +401,7 @@ namespace LANCommander.Migrations
|
||||||
b.Property<DateTime>("CreatedOn")
|
b.Property<DateTime>("CreatedOn")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<Guid>("GameId")
|
b.Property<Guid?>("GameId")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<Guid?>("UpdatedById")
|
b.Property<Guid?>("UpdatedById")
|
||||||
|
@ -570,6 +616,49 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("MultiplayerModes");
|
b.ToTable("MultiplayerModes");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.PlaySession", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CreatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("GameId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UpdatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.HasIndex("GameId");
|
||||||
|
|
||||||
|
b.HasIndex("UpdatedById");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("PlaySessions");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
@ -649,6 +738,9 @@ namespace LANCommander.Migrations
|
||||||
b.Property<Guid?>("GameId")
|
b.Property<Guid?>("GameId")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRegex")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("Path")
|
b.Property<string>("Path")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
@ -749,16 +841,9 @@ namespace LANCommander.Migrations
|
||||||
b.Property<DateTime>("CreatedOn")
|
b.Property<DateTime>("CreatedOn")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<bool>("EnableHTTP")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<Guid?>("GameId")
|
b.Property<Guid?>("GameId")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("HTTPRootPath")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
@ -859,6 +944,51 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("ServerConsoles");
|
b.ToTable("ServerConsoles");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.ServerHttpPath", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CreatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LocalPath")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Path")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ServerId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ServerId1")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UpdatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId1");
|
||||||
|
|
||||||
|
b.HasIndex("UpdatedById");
|
||||||
|
|
||||||
|
b.ToTable("ServerHttpPath");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Tag", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Tag", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
@ -1073,6 +1203,21 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("AspNetUserTokens", (string)null);
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RoleCollection", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("CollectionId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("RoleId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("CollectionId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("RoleCollection");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("CategoryGame", b =>
|
modelBuilder.Entity("CategoryGame", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.Category", null)
|
b.HasOne("LANCommander.Data.Models.Category", null)
|
||||||
|
@ -1088,6 +1233,21 @@ namespace LANCommander.Migrations
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CollectionGame", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.Collection", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.Game", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameDeveloper", b =>
|
modelBuilder.Entity("GameDeveloper", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.Company", null)
|
b.HasOne("LANCommander.Data.Models.Company", null)
|
||||||
|
@ -1167,7 +1327,8 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("Actions")
|
.WithMany("Actions")
|
||||||
|
@ -1177,7 +1338,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1190,7 +1352,8 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("Archives")
|
.WithMany("Archives")
|
||||||
|
@ -1208,7 +1371,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1225,7 +1389,8 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Category", "Parent")
|
b.HasOne("LANCommander.Data.Models.Category", "Parent")
|
||||||
.WithMany("Children")
|
.WithMany("Children")
|
||||||
|
@ -1233,7 +1398,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1242,15 +1408,34 @@ namespace LANCommander.Migrations
|
||||||
b.Navigation("UpdatedBy");
|
b.Navigation("UpdatedBy");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
b.Navigation("UpdatedBy");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1261,11 +1446,13 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1276,17 +1463,18 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("GameSaves")
|
.WithMany("GameSaves")
|
||||||
.HasForeignKey("GameId")
|
.HasForeignKey("GameId")
|
||||||
.OnDelete(DeleteBehavior.NoAction)
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "User")
|
b.HasOne("LANCommander.Data.Models.User", "User")
|
||||||
.WithMany("GameSaves")
|
.WithMany("GameSaves")
|
||||||
|
@ -1307,11 +1495,13 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1326,7 +1516,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("Keys")
|
.WithMany("Keys")
|
||||||
|
@ -1336,7 +1527,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("ClaimedByUser");
|
b.Navigation("ClaimedByUser");
|
||||||
|
|
||||||
|
@ -1351,7 +1543,8 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("Media")
|
.WithMany("Media")
|
||||||
|
@ -1361,7 +1554,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1374,7 +1568,8 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("MultiplayerModes")
|
.WithMany("MultiplayerModes")
|
||||||
|
@ -1384,7 +1579,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1393,15 +1589,49 @@ namespace LANCommander.Migrations
|
||||||
b.Navigation("UpdatedBy");
|
b.Navigation("UpdatedBy");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.PlaySession", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
|
.WithMany("PlaySessions")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "User")
|
||||||
|
.WithMany("PlaySessions")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
|
||||||
|
b.Navigation("UpdatedBy");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1412,15 +1642,18 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("SavePaths")
|
.WithMany("SavePaths")
|
||||||
.HasForeignKey("GameId");
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1433,7 +1666,8 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("Scripts")
|
.WithMany("Scripts")
|
||||||
|
@ -1447,7 +1681,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1462,16 +1697,18 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||||
.WithMany("Servers")
|
.WithMany("Servers")
|
||||||
.HasForeignKey("GameId")
|
.HasForeignKey("GameId")
|
||||||
.OnDelete(DeleteBehavior.NoAction);
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1484,7 +1721,8 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.Server", "Server")
|
b.HasOne("LANCommander.Data.Models.Server", "Server")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
|
@ -1498,7 +1736,37 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
b.Navigation("Server");
|
||||||
|
|
||||||
|
b.Navigation("UpdatedBy");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.ServerHttpPath", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.Server", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.Server", null)
|
||||||
|
.WithMany("HttpPaths")
|
||||||
|
.HasForeignKey("ServerId1");
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1511,11 +1779,13 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CreatedById");
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UpdatedById");
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
@ -1573,6 +1843,21 @@ namespace LANCommander.Migrations
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RoleCollection", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.Collection", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CollectionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.Role", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Category", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Category", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Children");
|
b.Navigation("Children");
|
||||||
|
@ -1592,6 +1877,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.Navigation("MultiplayerModes");
|
b.Navigation("MultiplayerModes");
|
||||||
|
|
||||||
|
b.Navigation("PlaySessions");
|
||||||
|
|
||||||
b.Navigation("SavePaths");
|
b.Navigation("SavePaths");
|
||||||
|
|
||||||
b.Navigation("Scripts");
|
b.Navigation("Scripts");
|
||||||
|
@ -1608,12 +1895,16 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Server", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Server", b =>
|
||||||
{
|
{
|
||||||
|
b.Navigation("HttpPaths");
|
||||||
|
|
||||||
b.Navigation("ServerConsoles");
|
b.Navigation("ServerConsoles");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("GameSaves");
|
b.Navigation("GameSaves");
|
||||||
|
|
||||||
|
b.Navigation("PlaySessions");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace LANCommander.Models
|
||||||
|
{
|
||||||
|
public class AddToCollectionOptions
|
||||||
|
{
|
||||||
|
public IEnumerable<Guid> GameIds { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace LANCommander.Models
|
||||||
|
{
|
||||||
|
public class RoleViewModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Users { get; set; }
|
||||||
|
public int Collections { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using LANCommander.Data.Enums;
|
||||||
|
|
||||||
|
namespace LANCommander.Models
|
||||||
|
{
|
||||||
|
public class ScriptEditorOptions
|
||||||
|
{
|
||||||
|
public Guid ScriptId { get; set; }
|
||||||
|
public Guid GameId { get; set; }
|
||||||
|
public Guid RedistributableId { get; set; }
|
||||||
|
public Guid ArchiveId { get; set; }
|
||||||
|
public IEnumerable<ScriptType> AllowedTypes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
@page "/Collections/{id:guid}"
|
||||||
|
@page "/Collections/Add"
|
||||||
|
@using LANCommander.Data.Enums;
|
||||||
|
@using LANCommander.Extensions
|
||||||
|
@attribute [Authorize(Roles = "Administrator")]
|
||||||
|
@inject CollectionService CollectionService
|
||||||
|
@inject IMessageService MessageService
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
|
<PageHeader>
|
||||||
|
<PageHeaderTitle>
|
||||||
|
<Input Size="@InputSize.Large" @bind-Value="@Collection.Name" />
|
||||||
|
</PageHeaderTitle>
|
||||||
|
<PageHeaderExtra>
|
||||||
|
<Button Type="@ButtonType.Primary" OnClick="Save">Save</Button>
|
||||||
|
</PageHeaderExtra>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<Table TItem="Game" DataSource="@Collection.Games" Responsive>
|
||||||
|
<Column TData="string" Title="Icon">
|
||||||
|
<Image Src="@GetIcon(context)" Height="32" Width="32" Preview="false"></Image>
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<PropertyColumn Property="g => g.Title" Sortable Filterable />
|
||||||
|
|
||||||
|
<PropertyColumn Property="g => g.ReleasedOn" Format="MM/dd/yyyy" Sortable Filterable />
|
||||||
|
|
||||||
|
<PropertyColumn Property="g => g.Singleplayer" Sortable Filterable>
|
||||||
|
<Checkbox Disabled="true" Checked="context.Singleplayer" />
|
||||||
|
</PropertyColumn>
|
||||||
|
|
||||||
|
<Column TData="bool" Title="Multiplayer">
|
||||||
|
<Checkbox Disabled="true" Checked="context.MultiplayerModes?.Count > 0" />
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<Column TData="string[]" Title="Developers">
|
||||||
|
@foreach (var dev in context.Developers)
|
||||||
|
{
|
||||||
|
<Tag>@dev.Name</Tag>
|
||||||
|
}
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<Column TData="string[]" Title="Publishers">
|
||||||
|
@foreach (var pub in context.Publishers)
|
||||||
|
{
|
||||||
|
<Tag>@pub.Name</Tag>
|
||||||
|
}
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<Column TData="string[]" Title="Genres">
|
||||||
|
@foreach (var genre in context.Genres)
|
||||||
|
{
|
||||||
|
<Tag>@genre.Name</Tag>
|
||||||
|
}
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<Column TData="Data.Enums.MultiplayerType[]" Title="Multiplayer Modes">
|
||||||
|
@foreach (var mode in context.MultiplayerModes.Select(mm => mm.Type).Distinct())
|
||||||
|
{
|
||||||
|
<Tag>@mode.GetDisplayName()</Tag>
|
||||||
|
}
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<ActionColumn Title="" Style="text-align: right">
|
||||||
|
<ChildContent>
|
||||||
|
<Space Direction="DirectionVHType.Horizontal">
|
||||||
|
<SpaceItem>
|
||||||
|
<Popconfirm OnConfirm="() => RemoveGame(context)" Title="Are you sure you want to remove this game from the collection?">
|
||||||
|
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
|
||||||
|
</Popconfirm>
|
||||||
|
</SpaceItem>
|
||||||
|
</Space>
|
||||||
|
</ChildContent>
|
||||||
|
</ActionColumn>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter] public Guid Id { get; set; }
|
||||||
|
|
||||||
|
Collection Collection;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (Id == Guid.Empty)
|
||||||
|
Collection = new Collection();
|
||||||
|
else
|
||||||
|
Collection = await CollectionService.Get(Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Save()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Collection.Id != Guid.Empty)
|
||||||
|
{
|
||||||
|
Collection = await CollectionService.Update(Collection);
|
||||||
|
|
||||||
|
await MessageService.Success("Collection updated!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Collection = await CollectionService.Add(Collection);
|
||||||
|
|
||||||
|
NavigationManager.LocationChanged += NotifyCollectionAdded;
|
||||||
|
|
||||||
|
NavigationManager.NavigateTo($"/Collections/{Collection.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await MessageService.Error("Could not save!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyCollectionAdded(object? sender, LocationChangedEventArgs e)
|
||||||
|
{
|
||||||
|
NavigationManager.LocationChanged -= NotifyCollectionAdded;
|
||||||
|
|
||||||
|
MessageService.Success("Collection added!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RemoveGame(Game game)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Collection.Games.Remove(game);
|
||||||
|
|
||||||
|
await CollectionService.Update(Collection);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageService.Error("Game could not be removed from the collection!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetIcon(Game game)
|
||||||
|
{
|
||||||
|
var media = game?.Media?.FirstOrDefault(m => m.Type == Data.Enums.MediaType.Icon);
|
||||||
|
|
||||||
|
if (media != null)
|
||||||
|
return $"/api/Media/{media.Id}/Download?fileId={media.FileId}";
|
||||||
|
else
|
||||||
|
return "/favicon.ico";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
@page "/Collections"
|
||||||
|
@using Microsoft.EntityFrameworkCore;
|
||||||
|
@attribute [Authorize(Roles = "Administrator")]
|
||||||
|
@inject CollectionService CollectionService
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject IMessageService MessageService
|
||||||
|
|
||||||
|
<PageHeader Title="Collections">
|
||||||
|
<PageHeaderExtra>
|
||||||
|
<Space Direction="DirectionVHType.Horizontal">
|
||||||
|
<SpaceItem>
|
||||||
|
<Search Placeholder="Search" @bind-Value="Search" BindOnInput DebounceMilliseconds="150" OnChange="() => LoadData()" />
|
||||||
|
</SpaceItem>
|
||||||
|
</Space>
|
||||||
|
</PageHeaderExtra>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<TableColumnPicker @ref="Picker" Key="Collections" @bind-Visible="ColumnPickerVisible" />
|
||||||
|
|
||||||
|
<Table TItem="Collection" DataSource="@Collections" Loading="@Loading" PageSize="25" Responsive>
|
||||||
|
<PropertyColumn Property="r => r.Name" Sortable Hidden="@(Picker.IsColumnHidden("Name"))" />
|
||||||
|
<PropertyColumn Property="s => s.CreatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Created On"))" />
|
||||||
|
<PropertyColumn Property="s => s.CreatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Created By"))">
|
||||||
|
@context.CreatedBy?.UserName
|
||||||
|
</PropertyColumn>
|
||||||
|
<PropertyColumn Property="g => g.UpdatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Updated On"))" />
|
||||||
|
<PropertyColumn Property="g => g.UpdatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Updated By"))">
|
||||||
|
@context.UpdatedBy?.UserName
|
||||||
|
</PropertyColumn>
|
||||||
|
<Column Title="Games" TData="int">
|
||||||
|
@context.Games.Count
|
||||||
|
</Column>
|
||||||
|
<ActionColumn Title="" Style="text-align: right; white-space: nowrap">
|
||||||
|
<TitleTemplate>
|
||||||
|
<div style="text-align: right">
|
||||||
|
<Button Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" OnClick="() => OpenColumnPicker()" />
|
||||||
|
</div>
|
||||||
|
</TitleTemplate>
|
||||||
|
<ChildContent>
|
||||||
|
<Space Direction="DirectionVHType.Horizontal">
|
||||||
|
<SpaceItem>
|
||||||
|
<a href="/Collections/@(context.Id)" class="ant-btn ant-btn-primary">Edit</a>
|
||||||
|
</SpaceItem>
|
||||||
|
<SpaceItem>
|
||||||
|
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this Collection?">
|
||||||
|
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
|
||||||
|
</Popconfirm>
|
||||||
|
</SpaceItem>
|
||||||
|
</Space>
|
||||||
|
</ChildContent>
|
||||||
|
</ActionColumn>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
IEnumerable<Collection> Collections { get; set; } = new List<Collection>();
|
||||||
|
|
||||||
|
bool Loading = true;
|
||||||
|
|
||||||
|
string Search = "";
|
||||||
|
|
||||||
|
TableColumnPicker Picker;
|
||||||
|
bool ColumnPickerVisible = false;
|
||||||
|
|
||||||
|
protected override void OnAfterRender(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
LoadData();
|
||||||
|
|
||||||
|
Loading = false;
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadData()
|
||||||
|
{
|
||||||
|
var fuzzySearch = Search.ToLower().Trim();
|
||||||
|
|
||||||
|
Collections = await CollectionService.Get(r => r.Name.ToLower().Contains(fuzzySearch)).OrderBy(r => r.Name).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Add()
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo("/Collections/Add");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Delete(Collection Collection)
|
||||||
|
{
|
||||||
|
Collections = new List<Collection>();
|
||||||
|
|
||||||
|
Loading = true;
|
||||||
|
|
||||||
|
await CollectionService.Delete(Collection);
|
||||||
|
|
||||||
|
Collections = await CollectionService.Get(x => true).OrderBy(r => r.Name).ToListAsync();
|
||||||
|
|
||||||
|
Loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenColumnPicker()
|
||||||
|
{
|
||||||
|
ColumnPickerVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CloseColumnPicker()
|
||||||
|
{
|
||||||
|
ColumnPickerVisible = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,94 +0,0 @@
|
||||||
@using System.Diagnostics;
|
|
||||||
@using LANCommander.Extensions;
|
|
||||||
@using AntDesign.Charts;
|
|
||||||
@using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
<Spin Spinning="Loading">
|
|
||||||
<Area @ref="Chart" Config="Config" />
|
|
||||||
</Spin>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
[Parameter] public int TimerHistory { get; set; }
|
|
||||||
[Parameter] public int TimerInterval { get; set; }
|
|
||||||
|
|
||||||
IChartComponent? Chart;
|
|
||||||
System.Timers.Timer Timer;
|
|
||||||
bool Loading = true;
|
|
||||||
|
|
||||||
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
|
|
||||||
|
|
||||||
ConcurrentDictionary<string, PerformanceCounter> PerformanceCounters = new ConcurrentDictionary<string, PerformanceCounter>();
|
|
||||||
|
|
||||||
string JsConfig = @"{
|
|
||||||
meta: {
|
|
||||||
value: {
|
|
||||||
alias: 'Speed',
|
|
||||||
formatter: (v) => humanFileSize(v, true) + '/s'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}";
|
|
||||||
|
|
||||||
AreaConfig Config = new AreaConfig
|
|
||||||
{
|
|
||||||
Name = "Network Download Rate",
|
|
||||||
Padding = "auto",
|
|
||||||
SeriesField = "series",
|
|
||||||
YField = "value",
|
|
||||||
XField = "index",
|
|
||||||
Animation = false,
|
|
||||||
XAxis = new ValueCatTimeAxis
|
|
||||||
{
|
|
||||||
Visible = false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
||||||
{
|
|
||||||
if (firstRender)
|
|
||||||
{
|
|
||||||
if (Timer == null)
|
|
||||||
{
|
|
||||||
Timer = new System.Timers.Timer();
|
|
||||||
|
|
||||||
Timer.Interval = TimerInterval;
|
|
||||||
|
|
||||||
Timer.Elapsed += async (s, e) =>
|
|
||||||
{
|
|
||||||
await RefreshData();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await Chart.UpdateChart(Config, null, null, JsConfig);
|
|
||||||
|
|
||||||
Timer.Start();
|
|
||||||
|
|
||||||
Loading = false;
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RefreshData()
|
|
||||||
{
|
|
||||||
#if WINDOWS
|
|
||||||
var category = new PerformanceCounterCategory("Network Interface");
|
|
||||||
|
|
||||||
foreach (var instance in category.GetInstanceNames())
|
|
||||||
{
|
|
||||||
if (!Data.ContainsKey(instance))
|
|
||||||
Data[instance] = new double[TimerHistory];
|
|
||||||
|
|
||||||
if (!PerformanceCounters.ContainsKey(instance))
|
|
||||||
PerformanceCounters[instance] = new PerformanceCounter("Network Interface", "Bytes Received/sec", instance);
|
|
||||||
|
|
||||||
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { value = y, index = i, series = x.Key })), true);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
@using System.Diagnostics;
|
|
||||||
@using LANCommander.Extensions;
|
|
||||||
@using AntDesign.Charts;
|
|
||||||
@using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
<Spin Spinning="Loading">
|
|
||||||
<Area @ref="Chart" Config="Config" />
|
|
||||||
</Spin>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
[Parameter] public int TimerHistory { get; set; }
|
|
||||||
[Parameter] public int TimerInterval { get; set; }
|
|
||||||
|
|
||||||
IChartComponent? Chart;
|
|
||||||
System.Timers.Timer Timer;
|
|
||||||
bool Loading = true;
|
|
||||||
|
|
||||||
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
|
|
||||||
|
|
||||||
ConcurrentDictionary<string, PerformanceCounter> PerformanceCounters = new ConcurrentDictionary<string, PerformanceCounter>();
|
|
||||||
|
|
||||||
string JsConfig = @"{
|
|
||||||
meta: {
|
|
||||||
value: {
|
|
||||||
alias: 'Speed',
|
|
||||||
formatter: (v) => humanFileSize(v, true) + '/s'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}";
|
|
||||||
|
|
||||||
AreaConfig Config = new AreaConfig
|
|
||||||
{
|
|
||||||
Name = "Network Upload Rate",
|
|
||||||
Padding = "auto",
|
|
||||||
SeriesField = "series",
|
|
||||||
YField = "value",
|
|
||||||
XField = "index",
|
|
||||||
Animation = false,
|
|
||||||
XAxis = new ValueCatTimeAxis
|
|
||||||
{
|
|
||||||
Visible = false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
||||||
{
|
|
||||||
if (firstRender)
|
|
||||||
{
|
|
||||||
if (Timer == null)
|
|
||||||
{
|
|
||||||
Timer = new System.Timers.Timer();
|
|
||||||
|
|
||||||
Timer.Interval = TimerInterval;
|
|
||||||
|
|
||||||
Timer.Elapsed += async (s, e) =>
|
|
||||||
{
|
|
||||||
await RefreshData();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await Chart.UpdateChart(Config, null, null, JsConfig);
|
|
||||||
Timer.Start();
|
|
||||||
|
|
||||||
Loading = false;
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RefreshData()
|
|
||||||
{
|
|
||||||
#if WINDOWS
|
|
||||||
var category = new PerformanceCounterCategory("Network Interface");
|
|
||||||
|
|
||||||
foreach (var instance in category.GetInstanceNames())
|
|
||||||
{
|
|
||||||
if (!Data.ContainsKey(instance))
|
|
||||||
Data[instance] = new double[TimerHistory];
|
|
||||||
|
|
||||||
if (!PerformanceCounters.ContainsKey(instance))
|
|
||||||
PerformanceCounters[instance] = new PerformanceCounter("Network Interface", "Bytes Sent/sec", instance);
|
|
||||||
|
|
||||||
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { value = y, index = i, series = x.Key })), true);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
@using AntDesign.Charts
|
||||||
|
@using ByteSizeLib
|
||||||
|
@inject PlaySessionService PlaySessionService
|
||||||
|
|
||||||
|
<Spin Spinning="Loading">
|
||||||
|
<Pie Data="Data" Config="Config" JsConfig="@JsConfig" />
|
||||||
|
</Spin>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
object[] Data;
|
||||||
|
|
||||||
|
bool Loading = true;
|
||||||
|
|
||||||
|
string JsConfig = @"{
|
||||||
|
meta: {
|
||||||
|
value: {
|
||||||
|
alias: 'Overall Playtime',
|
||||||
|
formatter: (v) => new Date(v * 1000).toISOString().slice(11, 19)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
visible: true,
|
||||||
|
type: 'outer-center'
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
PieConfig Config = new PieConfig
|
||||||
|
{
|
||||||
|
Radius = 0.8,
|
||||||
|
AngleField = "value",
|
||||||
|
ColorField = "type",
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
Dictionary<string, TimeSpan> playtimes = new Dictionary<string, TimeSpan>();
|
||||||
|
|
||||||
|
var sessions = await PlaySessionService.Get();
|
||||||
|
|
||||||
|
foreach (var gameSessions in sessions.Where(s => s.GameId.HasValue && s.GameId.Value != Guid.Empty).GroupBy(s => s.GameId))
|
||||||
|
{
|
||||||
|
var total = new TimeSpan();
|
||||||
|
|
||||||
|
foreach (var session in gameSessions.Where(gs => gs.Start != null && gs.End != null))
|
||||||
|
{
|
||||||
|
total = total.Add(session.End.Value.Subtract(session.Start.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
playtimes[gameSessions.First().Game.Title] = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data = playtimes.Select(pt => new
|
||||||
|
{
|
||||||
|
type = pt.Key,
|
||||||
|
value = (int)pt.Value.TotalSeconds
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
Loading = false;
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue