Force downlaod/upload, download dialog
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,18 +3,24 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.2.32505.173
|
VisualStudioVersion = 17.2.32505.173
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSaveCloudClient", "OpenSaveCloudClient\OpenSaveCloudClient.csproj", "{5BD9E525-B234-4AE2-9780-86E959592258}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenSaveCloudClient", "OpenSaveCloudClient\OpenSaveCloudClient.csproj", "{5BD9E525-B234-4AE2-9780-86E959592258}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{5BD9E525-B234-4AE2-9780-86E959592258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{5BD9E525-B234-4AE2-9780-86E959592258}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Debug|x64.Build.0 = Debug|x64
|
||||||
{5BD9E525-B234-4AE2-9780-86E959592258}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{5BD9E525-B234-4AE2-9780-86E959592258}.Release|Any CPU.Build.0 = Release|Any CPU
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{5BD9E525-B234-4AE2-9780-86E959592258}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ namespace OpenSaveCloudClient
|
|||||||
{
|
{
|
||||||
NameBox.Text = LocationBox.Text.Split(Path.DirectorySeparatorChar).Last();
|
NameBox.Text = LocationBox.Text.Split(Path.DirectorySeparatorChar).Last();
|
||||||
}
|
}
|
||||||
if (NameWarningLabel.Enabled)
|
if (NameWarningLabel.Visible)
|
||||||
{
|
{
|
||||||
if (MessageBox.Show(
|
if (MessageBox.Show(
|
||||||
"There is already a game with this name in the library. Would you like to add it anyway?",
|
"There is already a game with this name in the library. Would you like to add it anyway?",
|
||||||
|
|||||||
83
OpenSaveCloudClient/Core/HashTool.cs
Normal file
83
OpenSaveCloudClient/Core/HashTool.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace OpenSaveCloudClient.Core
|
||||||
|
{
|
||||||
|
internal class HashTool
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>HashDirectory</c> walk through a directory and make a hash of all the files
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to the folder</param>
|
||||||
|
/// <returns>The hash of the folder</returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
public static byte[]? HashDirectory(string path)
|
||||||
|
{
|
||||||
|
DirectoryInfo dir = new(path);
|
||||||
|
using HashAlgorithm? sha = HashAlgorithm.Create("SHA-512");
|
||||||
|
if (sha == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("HashDirectory: SHA-512 algorithm does not exist");
|
||||||
|
}
|
||||||
|
using (var stream = new CryptoStream(Stream.Null, sha, CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
using var writer = new BinaryWriter(stream);
|
||||||
|
FileSystemInfo[] infos = dir.GetFileSystemInfos();
|
||||||
|
Array.Sort(infos, (a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
|
||||||
|
foreach (FileSystemInfo info in infos)
|
||||||
|
{
|
||||||
|
writer.Write(info.Name);
|
||||||
|
if ((info.Attributes & FileAttributes.Directory) == 0)
|
||||||
|
{
|
||||||
|
byte[]? hash = HashFile(info as FileInfo);
|
||||||
|
if (hash == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("HashDirectory: hash of the file is null");
|
||||||
|
}
|
||||||
|
writer.Write((byte)'F');
|
||||||
|
writer.Write(hash);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[]? hash = HashDirectory(info.FullName);
|
||||||
|
if (hash == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("HashDirectory: hash of the directory is null");
|
||||||
|
}
|
||||||
|
writer.Write((byte)'D');
|
||||||
|
writer.Write(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sha.Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>HashFile</c> make a hash SHA-512 of a file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileInfo">The file information</param>
|
||||||
|
/// <returns>The file's hash</returns>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
private static byte[]? HashFile(FileInfo? fileInfo)
|
||||||
|
{
|
||||||
|
if (fileInfo == null)
|
||||||
|
{
|
||||||
|
throw new Exception("HashFile: invalid file information");
|
||||||
|
}
|
||||||
|
using HashAlgorithm? sha = HashAlgorithm.Create("SHA-512");
|
||||||
|
if (sha == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("HashFile: SHA-512 algorithm does not exist");
|
||||||
|
}
|
||||||
|
using var inputStream = fileInfo.OpenRead();
|
||||||
|
return sha.ComputeHash(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,16 +27,21 @@ namespace OpenSaveCloudClient.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void AddError(Exception ex)
|
public void AddError(Exception ex)
|
||||||
|
{
|
||||||
|
AddError(ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddError(string message)
|
||||||
{
|
{
|
||||||
Log log = new()
|
Log log = new()
|
||||||
{
|
{
|
||||||
Message = ex.Message,
|
Message = message,
|
||||||
Severity = LogSeverity.Error,
|
Severity = LogSeverity.Error,
|
||||||
};
|
};
|
||||||
messages.Add(log);
|
messages.Add(log);
|
||||||
NewMessageEventArgs args = new()
|
NewMessageEventArgs args = new()
|
||||||
{
|
{
|
||||||
Message = ex.Message,
|
Message = message,
|
||||||
Severity = LogSeverity.Error,
|
Severity = LogSeverity.Error,
|
||||||
};
|
};
|
||||||
OnNewMessage(args);
|
OnNewMessage(args);
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ using System.IO.Compression;
|
|||||||
|
|
||||||
namespace OpenSaveCloudClient.Core
|
namespace OpenSaveCloudClient.Core
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class is a connector to the remote Open Save Cloud server, it contains all the function that are mapped to the server endpoint
|
||||||
|
/// This is a singleton, to get the instance, call <c>GetInstance()</c>
|
||||||
|
/// </summary>
|
||||||
public class ServerConnector
|
public class ServerConnector
|
||||||
{
|
{
|
||||||
private static ServerConnector? instance;
|
private static ServerConnector? instance;
|
||||||
@@ -51,6 +55,11 @@ namespace OpenSaveCloudClient.Core
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>BindNewServer</c> set the hostname (or ip) and the port of the server and try to connect
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host">hostname or IP of the server</param>
|
||||||
|
/// <param name="port">port of the server</param>
|
||||||
public void BindNewServer(string host, int port)
|
public void BindNewServer(string host, int port)
|
||||||
{
|
{
|
||||||
Logout();
|
Logout();
|
||||||
@@ -64,6 +73,11 @@ namespace OpenSaveCloudClient.Core
|
|||||||
GetServerInformation();
|
GetServerInformation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>Login</c> connect a user and save the token to <c>token</c>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">Username of the user</param>
|
||||||
|
/// <param name="password">Password of the user</param>
|
||||||
public void Login(string username, string password)
|
public void Login(string username, string password)
|
||||||
{
|
{
|
||||||
logManager.AddInformation("Loging in to the server");
|
logManager.AddInformation("Loging in to the server");
|
||||||
@@ -102,6 +116,9 @@ namespace OpenSaveCloudClient.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>Reconnect</c> try to reconnect with the token, hostname and port saved in the configuration file
|
||||||
|
/// </summary>
|
||||||
public void Reconnect()
|
public void Reconnect()
|
||||||
{
|
{
|
||||||
string? uuidTask = null;
|
string? uuidTask = null;
|
||||||
@@ -147,6 +164,9 @@ namespace OpenSaveCloudClient.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>Logout</c> disconnect the current user and remove all the server's information of the config file
|
||||||
|
/// </summary>
|
||||||
public void Logout()
|
public void Logout()
|
||||||
{
|
{
|
||||||
serverInformation = null;
|
serverInformation = null;
|
||||||
@@ -159,6 +179,11 @@ namespace OpenSaveCloudClient.Core
|
|||||||
configuration.Flush();
|
configuration.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>CreateGame</c> create a new game entry in the server database
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the game</param>
|
||||||
|
/// <returns>The game that was created by the server</returns>
|
||||||
public Game? CreateGame(string name)
|
public Game? CreateGame(string name)
|
||||||
{
|
{
|
||||||
logManager.AddInformation("Creating game to server database");
|
logManager.AddInformation("Creating game to server database");
|
||||||
@@ -178,7 +203,7 @@ namespace OpenSaveCloudClient.Core
|
|||||||
return JsonSerializer.Deserialize<Game>(responseText);
|
return JsonSerializer.Deserialize<Game>(responseText);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
logManager.AddError(new Exception(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString())));
|
logManager.AddError(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString()));
|
||||||
}
|
}
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
}
|
}
|
||||||
@@ -190,86 +215,143 @@ namespace OpenSaveCloudClient.Core
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>Synchronize</c> is the method that upload and download the files from the server
|
||||||
|
/// If there is conflict, a warning is generated and the files are keep untouched
|
||||||
|
/// </summary>
|
||||||
public async void Synchronize()
|
public async void Synchronize()
|
||||||
{
|
{
|
||||||
string appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "osc");
|
|
||||||
string cachePath = Path.Combine(appdata, "cache");
|
|
||||||
logManager.AddInformation("Starting synchronization");
|
logManager.AddInformation("Starting synchronization");
|
||||||
List<GameSave> games = saveManager.Saves;
|
List<GameSave> games = saveManager.Saves;
|
||||||
string uuidTask = taskManager.StartTask("Synchronizing games", true, games.Count);
|
string uuidTask = taskManager.StartTask("Synchronizing games", true, games.Count);
|
||||||
List<GameSave> toUpload = new();
|
List<GameSave> toUpload = new();
|
||||||
List<GameSave> toDownload = new();
|
List<GameSave> toDownload = new();
|
||||||
foreach (GameSave game in games)
|
foreach (GameSave localCopy in games)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
game.Archive();
|
// Get the current information that are stored in the server
|
||||||
Game? g = GetGameInfoByID(game.Id);
|
Game? remoteCopy = GetGameInfoByID(localCopy.Id);
|
||||||
if (g != null)
|
if (remoteCopy == null)
|
||||||
{
|
{
|
||||||
if (g.Available)
|
logManager.AddWarning(String.Format("'{0}' is not found on this server, force upload it from the game detail screen", localCopy.Name));
|
||||||
{
|
continue;
|
||||||
if (g.Revision > game.Revision)
|
|
||||||
{
|
|
||||||
toDownload.Add(game);
|
|
||||||
}
|
}
|
||||||
else if (g.Revision < game.Revision)
|
|
||||||
|
// Check if available on the server
|
||||||
|
if (!remoteCopy.Available)
|
||||||
{
|
{
|
||||||
logManager.AddWarning(String.Format("Revision are the same, maybe uploaded by another computer ({0})", game.Name));
|
logManager.AddInformation(String.Format("'{0}' does not exist in the server", localCopy.Name));
|
||||||
|
localCopy.DetectChanges();
|
||||||
|
toUpload.Add(localCopy);
|
||||||
|
}
|
||||||
|
else if (localCopy.DetectChanges() || !localCopy.Synced)
|
||||||
|
{
|
||||||
|
// Create an archive of the folder
|
||||||
|
localCopy.Archive();
|
||||||
|
|
||||||
|
// Upload only if the revision is the same
|
||||||
|
if (remoteCopy.Revision != localCopy.Revision)
|
||||||
|
{
|
||||||
|
logManager.AddWarning(String.Format("There revision of the local copy is not equal with the copy on the server ({0})", localCopy.Name));
|
||||||
logManager.AddInformation("To resolve this conflict, force download or force upload from the game detail screen");
|
logManager.AddInformation("To resolve this conflict, force download or force upload from the game detail screen");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toUpload.Add(localCopy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
toUpload.Add(game);
|
if (remoteCopy.Revision > localCopy.Revision)
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
{
|
||||||
logManager.AddInformation(String.Format("First upload of '{0}'", game.Name));
|
toDownload.Add(localCopy);
|
||||||
toUpload.Add(game);
|
|
||||||
}
|
}
|
||||||
} else
|
else if (remoteCopy.Revision < localCopy.Revision)
|
||||||
{
|
{
|
||||||
logManager.AddWarning(String.Format("'{0}' is not found on this server, force upload it from the game detail screen", game.Name));
|
logManager.AddWarning(String.Format("There revision of the local copy is not equal with the copy on the server ({0})", localCopy.Name));
|
||||||
|
logManager.AddInformation("To resolve this conflict, force download or force upload from the game detail screen");
|
||||||
}
|
}
|
||||||
} catch (Exception ex)
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logManager.AddError(ex);
|
logManager.AddError(ex);
|
||||||
}
|
}
|
||||||
taskManager.UpdateTaskProgress(uuidTask, 1);
|
taskManager.UpdateTaskProgress(uuidTask, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upload files
|
||||||
|
UploadGames(toUpload);
|
||||||
|
|
||||||
|
// Download new version of files
|
||||||
|
await DownloadGamesAsync(toDownload);
|
||||||
|
|
||||||
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>UploadGames</c> upload the game saves to the server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="toUpload">A list of GameSaves</param>
|
||||||
|
public void UploadGames(List<GameSave> toUpload)
|
||||||
|
{
|
||||||
|
string cachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "osc", "cache");
|
||||||
foreach (GameSave game in toUpload)
|
foreach (GameSave game in toUpload)
|
||||||
{
|
{
|
||||||
GameUploadToken? gut = LockGameToUpload(game.Id);
|
GameUploadToken? gut = LockGameToUpload(game.Id);
|
||||||
if (gut != null)
|
if (gut != null)
|
||||||
{
|
{
|
||||||
string archivePath = Path.Combine(cachePath, game.Uuid + ".bin");
|
string archivePath = Path.Combine(cachePath, game.Uuid + ".bin");
|
||||||
UploadSave(gut.UploadToken, archivePath);
|
if (UploadSave(gut.UploadToken, archivePath, game.CurrentHash))
|
||||||
UpdateCache(game.Id, game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (GameSave game in toDownload)
|
|
||||||
{
|
{
|
||||||
GameUploadToken? gut = LockGameToUpload(game.Id);
|
game.UpdateHash();
|
||||||
if (gut != null)
|
UpdateCache(game);
|
||||||
{
|
|
||||||
string archivePath = Path.Combine(cachePath, game.Uuid + ".bin");
|
|
||||||
if (await DownloadSaveAsync(gut.UploadToken, archivePath, game.FolderPath))
|
|
||||||
{
|
|
||||||
UpdateCache(game.Id, game);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveManager.Save();
|
saveManager.Save();
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Game? GetGameInfoByID(int gameId)
|
/// <summary>
|
||||||
|
/// method <c>DownloadGamesAsync</c> download the game saves from the server
|
||||||
|
/// This method is async because of <c>DownloadSaveAsync</c> that are async too
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="toDownload">A list of GameSaves</param>
|
||||||
|
/// <returns>A task</returns>
|
||||||
|
public async Task DownloadGamesAsync(List<GameSave> toDownload)
|
||||||
|
{
|
||||||
|
string cachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "osc", "cache");
|
||||||
|
string archivePath;
|
||||||
|
GameUploadToken? gut;
|
||||||
|
foreach (GameSave game in toDownload)
|
||||||
|
{
|
||||||
|
gut = LockGameToUpload(game.Id);
|
||||||
|
if (gut != null)
|
||||||
|
{
|
||||||
|
archivePath = Path.Combine(cachePath, game.Uuid + ".bin");
|
||||||
|
if (await DownloadSaveAsync(gut.UploadToken, archivePath, game.FolderPath))
|
||||||
|
{
|
||||||
|
game.DetectChanges();
|
||||||
|
game.UpdateHash();
|
||||||
|
UpdateCache(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveManager.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>GetGameInfoByID</c> get the game save information from the server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameId">A game id</param>
|
||||||
|
/// <returns>A remote object of a game save</returns>
|
||||||
|
public Game? GetGameInfoByID(long gameId)
|
||||||
{
|
{
|
||||||
logManager.AddInformation("Getting game information from the server database");
|
logManager.AddInformation("Getting game information from the server database");
|
||||||
string uuidTask = taskManager.StartTask("Getting game information", true, 1);
|
string uuidTask = taskManager.StartTask("Getting game information", true, 1);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpClient client = new HttpClient();
|
using (HttpClient client = new HttpClient())
|
||||||
|
{
|
||||||
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
||||||
HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/info/{2}", host, port, gameId)).Result;
|
HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/info/{2}", host, port, gameId)).Result;
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
@@ -280,10 +362,11 @@ namespace OpenSaveCloudClient.Core
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logManager.AddError(new Exception(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString())));
|
logManager.AddError(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString()));
|
||||||
}
|
}
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logManager.AddError(ex);
|
logManager.AddError(ex);
|
||||||
@@ -292,7 +375,49 @@ namespace OpenSaveCloudClient.Core
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UploadSave(string uploadToken, string filePath)
|
/// <summary>
|
||||||
|
/// method <c>GetGamesInfo</c> get all the save registered on the server of the current user
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameId">A game id</param>
|
||||||
|
/// <returns>A list of remote object of a game save</returns>
|
||||||
|
public List<Game>? GetGamesInfo()
|
||||||
|
{
|
||||||
|
logManager.AddInformation("Getting game information from the server database");
|
||||||
|
string uuidTask = taskManager.StartTask("Getting game information", true, 1);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (HttpClient client = new HttpClient())
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
||||||
|
HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/all", host, port)).Result;
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
string responseText = response.Content.ReadAsStringAsync().Result;
|
||||||
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
|
||||||
|
return JsonSerializer.Deserialize<List<Game>>(responseText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logManager.AddError(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString()));
|
||||||
|
}
|
||||||
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logManager.AddError(ex);
|
||||||
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>UploadSave</c> upload a file to the server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uploadToken">The Lock token that a provided by the server</param>
|
||||||
|
/// <param name="filePath">The path of the file</param>
|
||||||
|
/// <param name="newHash">The new hash of the folder</param>
|
||||||
|
public bool UploadSave(string uploadToken, string filePath, string newHash)
|
||||||
{
|
{
|
||||||
logManager.AddInformation("Uploading save");
|
logManager.AddInformation("Uploading save");
|
||||||
string uuidTask = taskManager.StartTask("Uploading", true, 1);
|
string uuidTask = taskManager.StartTask("Uploading", true, 1);
|
||||||
@@ -304,21 +429,24 @@ namespace OpenSaveCloudClient.Core
|
|||||||
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
||||||
multipartFormContent.Add(fileStreamContent, name: "file", fileName: "file.bin");
|
multipartFormContent.Add(fileStreamContent, name: "file", fileName: "file.bin");
|
||||||
|
|
||||||
HttpClient client = new HttpClient();
|
using (HttpClient client = new HttpClient())
|
||||||
|
{
|
||||||
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
||||||
client.DefaultRequestHeaders.Add("X-Upload-Key", uploadToken);
|
client.DefaultRequestHeaders.Add("X-Upload-Key", uploadToken);
|
||||||
|
client.DefaultRequestHeaders.Add("X-Game-Save-Hash", newHash);
|
||||||
HttpResponseMessage response = client.PostAsync(string.Format("{0}:{1}/api/v1/game/upload", host, port), multipartFormContent).Result;
|
HttpResponseMessage response = client.PostAsync(string.Format("{0}:{1}/api/v1/game/upload", host, port), multipartFormContent).Result;
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logManager.AddError(new Exception(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString())));
|
logManager.AddError(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString()));
|
||||||
}
|
}
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logManager.AddError(ex);
|
logManager.AddError(ex);
|
||||||
@@ -327,15 +455,24 @@ namespace OpenSaveCloudClient.Core
|
|||||||
{
|
{
|
||||||
stream.Close();
|
stream.Close();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uploadToken">The Lock token that a provided by the server</param>
|
||||||
|
/// <param name="filePath">The path where the downloaded archive will be stored</param>
|
||||||
|
/// <param name="unzipPath">The path is stored the save</param>
|
||||||
|
/// <returns>If the save is successfully downloaded and unpacked</returns>
|
||||||
public async Task<bool> DownloadSaveAsync(string uploadToken, string filePath, string unzipPath)
|
public async Task<bool> DownloadSaveAsync(string uploadToken, string filePath, string unzipPath)
|
||||||
{
|
{
|
||||||
logManager.AddInformation("Downloading save");
|
logManager.AddInformation("Downloading save");
|
||||||
string uuidTask = taskManager.StartTask("Downloading", true, 1);
|
string uuidTask = taskManager.StartTask("Downloading", true, 1);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpClient client = new HttpClient();
|
using (HttpClient client = new HttpClient())
|
||||||
|
{
|
||||||
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
||||||
client.DefaultRequestHeaders.Add("X-Upload-Key", uploadToken);
|
client.DefaultRequestHeaders.Add("X-Upload-Key", uploadToken);
|
||||||
HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/download", host, port)).Result;
|
HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/download", host, port)).Result;
|
||||||
@@ -355,10 +492,11 @@ namespace OpenSaveCloudClient.Core
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logManager.AddError(new Exception(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString())));
|
logManager.AddError(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString()));
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logManager.AddError(ex);
|
logManager.AddError(ex);
|
||||||
@@ -367,31 +505,41 @@ namespace OpenSaveCloudClient.Core
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCache(int gameId, GameSave gameSave)
|
/// <summary>
|
||||||
|
/// method <c>UpdateCache</c> update the GameSave object with the server data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameSave">A GameSave object</param>
|
||||||
|
private void UpdateCache(GameSave gameSave)
|
||||||
{
|
{
|
||||||
string uuidTask = taskManager.StartTask("Updating cache", true, 1);
|
string uuidTask = taskManager.StartTask("Updating cache", true, 1);
|
||||||
Game? game = GetGameInfoByID(gameId);
|
Game? game = GetGameInfoByID(gameSave.Id);
|
||||||
if (game != null)
|
if (game != null)
|
||||||
{
|
{
|
||||||
gameSave.Revision = game.Revision;
|
gameSave.Revision = game.Revision;
|
||||||
gameSave.LocalOnly = false;
|
|
||||||
gameSave.Synced = true;
|
gameSave.Synced = true;
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logManager.AddError(new Exception("Failed to get game information"));
|
logManager.AddError("Failed to get game information");
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GameUploadToken? LockGameToUpload(int gameId)
|
/// <summary>
|
||||||
|
/// method <c>LockGameToUpload</c> lock a game save on the server
|
||||||
|
/// This method is useful to avoid competing uploads/downloads
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameId">A game id</param>
|
||||||
|
/// <returns>A token to give to the upload/download method</returns>
|
||||||
|
private GameUploadToken? LockGameToUpload(long gameId)
|
||||||
{
|
{
|
||||||
logManager.AddInformation("Locking game in the server");
|
logManager.AddInformation("Locking game in the server");
|
||||||
string uuidTask = taskManager.StartTask("Locking game", true, 1);
|
string uuidTask = taskManager.StartTask("Locking game", true, 1);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpClient client = new HttpClient();
|
using (HttpClient client = new HttpClient())
|
||||||
|
{
|
||||||
string json = JsonSerializer.Serialize(new UploadGameInfo { GameId = gameId });
|
string json = JsonSerializer.Serialize(new UploadGameInfo { GameId = gameId });
|
||||||
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
|
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
|
||||||
@@ -405,10 +553,11 @@ namespace OpenSaveCloudClient.Core
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logManager.AddError(new Exception(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString())));
|
logManager.AddError(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString()));
|
||||||
}
|
}
|
||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logManager.AddError(ex);
|
logManager.AddError(ex);
|
||||||
@@ -417,6 +566,10 @@ namespace OpenSaveCloudClient.Core
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>ReloadFromConfiguration</c> load the server information (host, port and token) from the configuration file
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The configuration is valid</returns>
|
||||||
private bool ReloadFromConfiguration()
|
private bool ReloadFromConfiguration()
|
||||||
{
|
{
|
||||||
string newHost = configuration.GetString("authentication.host", "");
|
string newHost = configuration.GetString("authentication.host", "");
|
||||||
@@ -447,6 +600,9 @@ namespace OpenSaveCloudClient.Core
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>GetServerInformation</c> get information about the connected server
|
||||||
|
/// </summary>
|
||||||
private void GetServerInformation()
|
private void GetServerInformation()
|
||||||
{
|
{
|
||||||
logManager.AddInformation("Getting server information");
|
logManager.AddInformation("Getting server information");
|
||||||
@@ -475,6 +631,9 @@ namespace OpenSaveCloudClient.Core
|
|||||||
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// method <c>SaveToConfig</c> save the server connection information to the configuration file
|
||||||
|
/// </summary>
|
||||||
private void SaveToConfig()
|
private void SaveToConfig()
|
||||||
{
|
{
|
||||||
configuration.SetValue("authentication.host", host);
|
configuration.SetValue("authentication.host", host);
|
||||||
@@ -482,5 +641,6 @@ namespace OpenSaveCloudClient.Core
|
|||||||
configuration.SetValue("authentication.token", token);
|
configuration.SetValue("authentication.token", token);
|
||||||
configuration.Flush();
|
configuration.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
194
OpenSaveCloudClient/DetailForm.Designer.cs
generated
Normal file
194
OpenSaveCloudClient/DetailForm.Designer.cs
generated
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
namespace OpenSaveCloudClient
|
||||||
|
{
|
||||||
|
partial class DetailForm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DetailForm));
|
||||||
|
this.TitleLabel = new System.Windows.Forms.Label();
|
||||||
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.RevisionLabel = new System.Windows.Forms.Label();
|
||||||
|
this.PathLabel = new System.Windows.Forms.Label();
|
||||||
|
this.SyncedLabel = new System.Windows.Forms.Label();
|
||||||
|
this.label8 = new System.Windows.Forms.Label();
|
||||||
|
this.ChecksumBox = new System.Windows.Forms.TextBox();
|
||||||
|
this.UploadButton = new System.Windows.Forms.Button();
|
||||||
|
this.DownloadButton = new System.Windows.Forms.Button();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// TitleLabel
|
||||||
|
//
|
||||||
|
this.TitleLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.TitleLabel.AutoEllipsis = true;
|
||||||
|
this.TitleLabel.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||||
|
this.TitleLabel.ForeColor = System.Drawing.SystemColors.Highlight;
|
||||||
|
this.TitleLabel.Location = new System.Drawing.Point(12, 9);
|
||||||
|
this.TitleLabel.Name = "TitleLabel";
|
||||||
|
this.TitleLabel.Size = new System.Drawing.Size(941, 48);
|
||||||
|
this.TitleLabel.TabIndex = 0;
|
||||||
|
this.TitleLabel.Text = "_";
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
this.label2.AutoSize = true;
|
||||||
|
this.label2.Location = new System.Drawing.Point(12, 95);
|
||||||
|
this.label2.Name = "label2";
|
||||||
|
this.label2.Size = new System.Drawing.Size(77, 25);
|
||||||
|
this.label2.TabIndex = 1;
|
||||||
|
this.label2.Text = "Revision";
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(12, 120);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(46, 25);
|
||||||
|
this.label3.TabIndex = 2;
|
||||||
|
this.label3.Text = "Path";
|
||||||
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Location = new System.Drawing.Point(12, 145);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(68, 25);
|
||||||
|
this.label4.TabIndex = 3;
|
||||||
|
this.label4.Text = "Synced";
|
||||||
|
//
|
||||||
|
// RevisionLabel
|
||||||
|
//
|
||||||
|
this.RevisionLabel.AutoSize = true;
|
||||||
|
this.RevisionLabel.Location = new System.Drawing.Point(125, 95);
|
||||||
|
this.RevisionLabel.Name = "RevisionLabel";
|
||||||
|
this.RevisionLabel.Size = new System.Drawing.Size(16, 25);
|
||||||
|
this.RevisionLabel.TabIndex = 4;
|
||||||
|
this.RevisionLabel.Text = ".";
|
||||||
|
//
|
||||||
|
// PathLabel
|
||||||
|
//
|
||||||
|
this.PathLabel.AutoSize = true;
|
||||||
|
this.PathLabel.Location = new System.Drawing.Point(125, 120);
|
||||||
|
this.PathLabel.Name = "PathLabel";
|
||||||
|
this.PathLabel.Size = new System.Drawing.Size(16, 25);
|
||||||
|
this.PathLabel.TabIndex = 5;
|
||||||
|
this.PathLabel.Text = ".";
|
||||||
|
//
|
||||||
|
// SyncedLabel
|
||||||
|
//
|
||||||
|
this.SyncedLabel.AutoSize = true;
|
||||||
|
this.SyncedLabel.Location = new System.Drawing.Point(125, 145);
|
||||||
|
this.SyncedLabel.Name = "SyncedLabel";
|
||||||
|
this.SyncedLabel.Size = new System.Drawing.Size(16, 25);
|
||||||
|
this.SyncedLabel.TabIndex = 6;
|
||||||
|
this.SyncedLabel.Text = ".";
|
||||||
|
//
|
||||||
|
// label8
|
||||||
|
//
|
||||||
|
this.label8.AutoSize = true;
|
||||||
|
this.label8.Location = new System.Drawing.Point(12, 176);
|
||||||
|
this.label8.Name = "label8";
|
||||||
|
this.label8.Size = new System.Drawing.Size(93, 25);
|
||||||
|
this.label8.TabIndex = 7;
|
||||||
|
this.label8.Text = "Checksum";
|
||||||
|
//
|
||||||
|
// ChecksumBox
|
||||||
|
//
|
||||||
|
this.ChecksumBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.ChecksumBox.Location = new System.Drawing.Point(125, 173);
|
||||||
|
this.ChecksumBox.Name = "ChecksumBox";
|
||||||
|
this.ChecksumBox.ReadOnly = true;
|
||||||
|
this.ChecksumBox.Size = new System.Drawing.Size(828, 31);
|
||||||
|
this.ChecksumBox.TabIndex = 8;
|
||||||
|
//
|
||||||
|
// UploadButton
|
||||||
|
//
|
||||||
|
this.UploadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.UploadButton.Location = new System.Drawing.Point(12, 244);
|
||||||
|
this.UploadButton.Name = "UploadButton";
|
||||||
|
this.UploadButton.Size = new System.Drawing.Size(112, 34);
|
||||||
|
this.UploadButton.TabIndex = 9;
|
||||||
|
this.UploadButton.Text = "Upload";
|
||||||
|
this.UploadButton.UseVisualStyleBackColor = true;
|
||||||
|
this.UploadButton.Click += new System.EventHandler(this.UploadButton_Click);
|
||||||
|
//
|
||||||
|
// DownloadButton
|
||||||
|
//
|
||||||
|
this.DownloadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.DownloadButton.Location = new System.Drawing.Point(130, 244);
|
||||||
|
this.DownloadButton.Name = "DownloadButton";
|
||||||
|
this.DownloadButton.Size = new System.Drawing.Size(112, 34);
|
||||||
|
this.DownloadButton.TabIndex = 10;
|
||||||
|
this.DownloadButton.Text = "Download";
|
||||||
|
this.DownloadButton.UseVisualStyleBackColor = true;
|
||||||
|
this.DownloadButton.Click += new System.EventHandler(this.DownloadButton_Click);
|
||||||
|
//
|
||||||
|
// DetailForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(965, 290);
|
||||||
|
this.Controls.Add(this.DownloadButton);
|
||||||
|
this.Controls.Add(this.UploadButton);
|
||||||
|
this.Controls.Add(this.ChecksumBox);
|
||||||
|
this.Controls.Add(this.label8);
|
||||||
|
this.Controls.Add(this.SyncedLabel);
|
||||||
|
this.Controls.Add(this.PathLabel);
|
||||||
|
this.Controls.Add(this.RevisionLabel);
|
||||||
|
this.Controls.Add(this.label4);
|
||||||
|
this.Controls.Add(this.label3);
|
||||||
|
this.Controls.Add(this.label2);
|
||||||
|
this.Controls.Add(this.TitleLabel);
|
||||||
|
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||||
|
this.MinimumSize = new System.Drawing.Size(987, 346);
|
||||||
|
this.Name = "DetailForm";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.Text = "Detail of";
|
||||||
|
this.Load += new System.EventHandler(this.DetailForm_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private Label TitleLabel;
|
||||||
|
private Label label2;
|
||||||
|
private Label label3;
|
||||||
|
private Label label4;
|
||||||
|
private Label RevisionLabel;
|
||||||
|
private Label PathLabel;
|
||||||
|
private Label SyncedLabel;
|
||||||
|
private Label label8;
|
||||||
|
private TextBox ChecksumBox;
|
||||||
|
private Button UploadButton;
|
||||||
|
private Button DownloadButton;
|
||||||
|
}
|
||||||
|
}
|
||||||
75
OpenSaveCloudClient/DetailForm.cs
Normal file
75
OpenSaveCloudClient/DetailForm.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
using OpenSaveCloudClient.Core;
|
||||||
|
using OpenSaveCloudClient.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace OpenSaveCloudClient
|
||||||
|
{
|
||||||
|
public enum ForcedSyncResult
|
||||||
|
{
|
||||||
|
Upload,
|
||||||
|
Download
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class DetailForm : Form
|
||||||
|
{
|
||||||
|
|
||||||
|
private ForcedSyncResult? result;
|
||||||
|
private GameSave gameSave;
|
||||||
|
|
||||||
|
public ForcedSyncResult? Result { get { return result; } }
|
||||||
|
|
||||||
|
public DetailForm(GameSave gameSave)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.gameSave = gameSave;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UploadButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (MessageBox.Show(
|
||||||
|
"Forcing upload will overwrite the save on the server, do you really want to forcing the upload of the save?",
|
||||||
|
"Warning: Forcing upload",
|
||||||
|
MessageBoxButtons.YesNo,
|
||||||
|
MessageBoxIcon.Warning) == DialogResult.No)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = ForcedSyncResult.Upload;
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetailForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
TitleLabel.Text = gameSave.Name;
|
||||||
|
Text = "Detail of " + gameSave.Name;
|
||||||
|
RevisionLabel.Text = Convert.ToString(gameSave.Revision);
|
||||||
|
PathLabel.Text = gameSave.FolderPath;
|
||||||
|
SyncedLabel.Text = gameSave.Synced ? "Yes" : "No";
|
||||||
|
ChecksumBox.Text = gameSave.CurrentHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DownloadButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (MessageBox.Show(
|
||||||
|
"Forcing download will overwrite the local save, do you really want to forcing the download of the save?",
|
||||||
|
"Warning: Forcing download",
|
||||||
|
MessageBoxButtons.YesNo,
|
||||||
|
MessageBoxIcon.Warning) == DialogResult.No)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = ForcedSyncResult.Download;
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2280
OpenSaveCloudClient/DetailForm.resx
Normal file
2280
OpenSaveCloudClient/DetailForm.resx
Normal file
File diff suppressed because it is too large
Load Diff
184
OpenSaveCloudClient/DownloadGameForm.Designer.cs
generated
Normal file
184
OpenSaveCloudClient/DownloadGameForm.Designer.cs
generated
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
namespace OpenSaveCloudClient
|
||||||
|
{
|
||||||
|
partial class DownloadGameForm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DownloadGameForm));
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.LoadingIndicator = new System.Windows.Forms.PictureBox();
|
||||||
|
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.pathButton = new System.Windows.Forms.Button();
|
||||||
|
this.LocationBox = new System.Windows.Forms.TextBox();
|
||||||
|
this.DownloadButton = new System.Windows.Forms.Button();
|
||||||
|
this.RemoteList = new System.Windows.Forms.ListView();
|
||||||
|
this.GameName = new System.Windows.Forms.ColumnHeader();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.LoadingIndicator)).BeginInit();
|
||||||
|
this.groupBox1.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||||
|
this.label1.ForeColor = System.Drawing.SystemColors.Highlight;
|
||||||
|
this.label1.Location = new System.Drawing.Point(12, 9);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(387, 48);
|
||||||
|
this.label1.TabIndex = 0;
|
||||||
|
this.label1.Text = "Download a game save";
|
||||||
|
//
|
||||||
|
// LoadingIndicator
|
||||||
|
//
|
||||||
|
this.LoadingIndicator.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.LoadingIndicator.Image = ((System.Drawing.Image)(resources.GetObject("LoadingIndicator.Image")));
|
||||||
|
this.LoadingIndicator.Location = new System.Drawing.Point(854, 12);
|
||||||
|
this.LoadingIndicator.Name = "LoadingIndicator";
|
||||||
|
this.LoadingIndicator.Size = new System.Drawing.Size(48, 48);
|
||||||
|
this.LoadingIndicator.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||||
|
this.LoadingIndicator.TabIndex = 7;
|
||||||
|
this.LoadingIndicator.TabStop = false;
|
||||||
|
//
|
||||||
|
// groupBox1
|
||||||
|
//
|
||||||
|
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.groupBox1.Controls.Add(this.label3);
|
||||||
|
this.groupBox1.Controls.Add(this.pathButton);
|
||||||
|
this.groupBox1.Controls.Add(this.LocationBox);
|
||||||
|
this.groupBox1.Location = new System.Drawing.Point(396, 83);
|
||||||
|
this.groupBox1.Name = "groupBox1";
|
||||||
|
this.groupBox1.Size = new System.Drawing.Size(506, 516);
|
||||||
|
this.groupBox1.TabIndex = 8;
|
||||||
|
this.groupBox1.TabStop = false;
|
||||||
|
this.groupBox1.Text = "Set up the save";
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(6, 76);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(311, 25);
|
||||||
|
this.label3.TabIndex = 7;
|
||||||
|
this.label3.Text = "Where will the save folder be located?";
|
||||||
|
//
|
||||||
|
// pathButton
|
||||||
|
//
|
||||||
|
this.pathButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.pathButton.Enabled = false;
|
||||||
|
this.pathButton.Location = new System.Drawing.Point(453, 101);
|
||||||
|
this.pathButton.Name = "pathButton";
|
||||||
|
this.pathButton.Size = new System.Drawing.Size(47, 34);
|
||||||
|
this.pathButton.TabIndex = 6;
|
||||||
|
this.pathButton.Text = "...";
|
||||||
|
this.pathButton.UseVisualStyleBackColor = true;
|
||||||
|
this.pathButton.Click += new System.EventHandler(this.pathButton_Click);
|
||||||
|
//
|
||||||
|
// LocationBox
|
||||||
|
//
|
||||||
|
this.LocationBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.LocationBox.Enabled = false;
|
||||||
|
this.LocationBox.Location = new System.Drawing.Point(6, 104);
|
||||||
|
this.LocationBox.Name = "LocationBox";
|
||||||
|
this.LocationBox.Size = new System.Drawing.Size(441, 31);
|
||||||
|
this.LocationBox.TabIndex = 5;
|
||||||
|
this.LocationBox.TextChanged += new System.EventHandler(this.LocationBox_TextChanged);
|
||||||
|
//
|
||||||
|
// DownloadButton
|
||||||
|
//
|
||||||
|
this.DownloadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.DownloadButton.Enabled = false;
|
||||||
|
this.DownloadButton.Location = new System.Drawing.Point(790, 605);
|
||||||
|
this.DownloadButton.Name = "DownloadButton";
|
||||||
|
this.DownloadButton.Size = new System.Drawing.Size(112, 34);
|
||||||
|
this.DownloadButton.TabIndex = 9;
|
||||||
|
this.DownloadButton.Text = "Download";
|
||||||
|
this.DownloadButton.UseVisualStyleBackColor = true;
|
||||||
|
this.DownloadButton.Click += new System.EventHandler(this.DownloadButton_Click);
|
||||||
|
//
|
||||||
|
// RemoteList
|
||||||
|
//
|
||||||
|
this.RemoteList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.RemoteList.CheckBoxes = true;
|
||||||
|
this.RemoteList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||||
|
this.GameName});
|
||||||
|
this.RemoteList.Location = new System.Drawing.Point(12, 83);
|
||||||
|
this.RemoteList.Name = "RemoteList";
|
||||||
|
this.RemoteList.Size = new System.Drawing.Size(378, 516);
|
||||||
|
this.RemoteList.TabIndex = 10;
|
||||||
|
this.RemoteList.UseCompatibleStateImageBehavior = false;
|
||||||
|
this.RemoteList.View = System.Windows.Forms.View.Details;
|
||||||
|
this.RemoteList.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.RemoteList_ItemChecked);
|
||||||
|
this.RemoteList.SelectedIndexChanged += new System.EventHandler(this.RemoteList_SelectedIndexChanged);
|
||||||
|
//
|
||||||
|
// GameName
|
||||||
|
//
|
||||||
|
this.GameName.Text = "Game name";
|
||||||
|
this.GameName.Width = 373;
|
||||||
|
//
|
||||||
|
// DownloadGameForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.BackColor = System.Drawing.SystemColors.Window;
|
||||||
|
this.ClientSize = new System.Drawing.Size(914, 651);
|
||||||
|
this.Controls.Add(this.RemoteList);
|
||||||
|
this.Controls.Add(this.DownloadButton);
|
||||||
|
this.Controls.Add(this.groupBox1);
|
||||||
|
this.Controls.Add(this.LoadingIndicator);
|
||||||
|
this.Controls.Add(this.label1);
|
||||||
|
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||||
|
this.MinimumSize = new System.Drawing.Size(936, 707);
|
||||||
|
this.Name = "DownloadGameForm";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.Text = "Download a game save";
|
||||||
|
this.Load += new System.EventHandler(this.DownloadGameForm_Load);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.LoadingIndicator)).EndInit();
|
||||||
|
this.groupBox1.ResumeLayout(false);
|
||||||
|
this.groupBox1.PerformLayout();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private Label label1;
|
||||||
|
private PictureBox LoadingIndicator;
|
||||||
|
private GroupBox groupBox1;
|
||||||
|
private Button DownloadButton;
|
||||||
|
private ListView RemoteList;
|
||||||
|
private ColumnHeader GameName;
|
||||||
|
private Label label3;
|
||||||
|
private Button pathButton;
|
||||||
|
private TextBox LocationBox;
|
||||||
|
}
|
||||||
|
}
|
||||||
157
OpenSaveCloudClient/DownloadGameForm.cs
Normal file
157
OpenSaveCloudClient/DownloadGameForm.cs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
using OpenSaveCloudClient.Core;
|
||||||
|
using OpenSaveCloudClient.Models;
|
||||||
|
using OpenSaveCloudClient.Models.Remote;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace OpenSaveCloudClient
|
||||||
|
{
|
||||||
|
public partial class DownloadGameForm : Form
|
||||||
|
{
|
||||||
|
|
||||||
|
private ServerConnector serverConnector;
|
||||||
|
private SaveManager saveManager;
|
||||||
|
private ListViewItem? selectedItem;
|
||||||
|
|
||||||
|
private List<GameSave> result;
|
||||||
|
|
||||||
|
public List<GameSave> Result { get { return result; } }
|
||||||
|
|
||||||
|
public DownloadGameForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
result = new List<GameSave>();
|
||||||
|
serverConnector = ServerConnector.GetInstance();
|
||||||
|
saveManager = SaveManager.GetInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DownloadGameForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
new Thread(() => {
|
||||||
|
List<Game>? remoteGames = serverConnector.GetGamesInfo();
|
||||||
|
this.Invoke((MethodInvoker)delegate {
|
||||||
|
UpdateRemoteList(remoteGames);
|
||||||
|
});
|
||||||
|
}).Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateRemoteList(List<Game>? remoteGames)
|
||||||
|
{
|
||||||
|
if (remoteGames != null)
|
||||||
|
{
|
||||||
|
foreach (Game game in remoteGames)
|
||||||
|
{
|
||||||
|
ListViewItem lvi = RemoteList.Items.Add(game.Name);
|
||||||
|
lvi.SubItems.Add(Convert.ToString(game.Id));
|
||||||
|
lvi.SubItems.Add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LockControls(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LockControls(bool l)
|
||||||
|
{
|
||||||
|
LoadingIndicator.Visible = l;
|
||||||
|
l = !l;
|
||||||
|
RemoteList.Enabled = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pathButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderBrowserDialog dialog = new();
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
string path = dialog.SelectedPath;
|
||||||
|
LocationBox.Text = path;
|
||||||
|
if (selectedItem != null && selectedItem.Checked)
|
||||||
|
{
|
||||||
|
selectedItem.SubItems[2].Text = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoteList_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
selectedItem = null;
|
||||||
|
if (RemoteList.SelectedItems.Count == 1)
|
||||||
|
{
|
||||||
|
selectedItem = RemoteList.SelectedItems[0];
|
||||||
|
if (selectedItem != null && selectedItem.Checked)
|
||||||
|
{
|
||||||
|
pathButton.Enabled = true;
|
||||||
|
LocationBox.Enabled = true;
|
||||||
|
LocationBox.Text = selectedItem.SubItems[2].Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
pathButton.Enabled = false;
|
||||||
|
LocationBox.Enabled = false;
|
||||||
|
LocationBox.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoteList_ItemChecked(object sender, ItemCheckedEventArgs e)
|
||||||
|
{
|
||||||
|
DownloadButton.Enabled = (RemoteList.CheckedItems.Count > 0);
|
||||||
|
RemoteList_SelectedIndexChanged(sender, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LocationBox_TextChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (selectedItem != null && selectedItem.Checked)
|
||||||
|
{
|
||||||
|
selectedItem.SubItems[2].Text = LocationBox.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DownloadButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
foreach (ListViewItem lvi in RemoteList.CheckedItems)
|
||||||
|
{
|
||||||
|
string path = lvi.SubItems[2].Text;
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
MessageBox.Show("File folder cannot be empty", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Directory.Exists(path))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (saveManager.Saves.Exists(g => g.FolderPath == path))
|
||||||
|
{
|
||||||
|
MessageBox.Show("This directory is already used for another game", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Directory.EnumerateFileSystemEntries(path).Any())
|
||||||
|
{
|
||||||
|
string msg = String.Format("The directory '{0}' contains files, these files will be deleted. Do you want to continue using this folder?", path);
|
||||||
|
if (MessageBox.Show(
|
||||||
|
msg,
|
||||||
|
"Directory not empty",
|
||||||
|
MessageBoxButtons.YesNo,
|
||||||
|
MessageBoxIcon.Question) == DialogResult.No)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameSave gameSave = new(lvi.SubItems[0].Text, "", path, "", 0);
|
||||||
|
gameSave.Id = Int64.Parse(lvi.SubItems[1].Text);
|
||||||
|
result.Add(gameSave);
|
||||||
|
}
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2624
OpenSaveCloudClient/DownloadGameForm.resx
Normal file
2624
OpenSaveCloudClient/DownloadGameForm.resx
Normal file
File diff suppressed because it is too large
Load Diff
28
OpenSaveCloudClient/GameLibraryForm.Designer.cs
generated
28
OpenSaveCloudClient/GameLibraryForm.Designer.cs
generated
@@ -33,9 +33,11 @@
|
|||||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||||
this.toolStripDropDownButton1 = new System.Windows.Forms.ToolStripDropDownButton();
|
this.toolStripDropDownButton1 = new System.Windows.Forms.ToolStripDropDownButton();
|
||||||
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
|
this.toolStripProgressBar1 = new System.Windows.Forms.ToolStripProgressBar();
|
||||||
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
|
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
|
||||||
this.AddButton = new System.Windows.Forms.ToolStripButton();
|
this.AddButton = new System.Windows.Forms.ToolStripButton();
|
||||||
this.SyncButton = new System.Windows.Forms.ToolStripButton();
|
this.SyncButton = new System.Windows.Forms.ToolStripButton();
|
||||||
|
this.DownloadButton = new System.Windows.Forms.ToolStripButton();
|
||||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
this.ConfigButton = new System.Windows.Forms.ToolStripButton();
|
this.ConfigButton = new System.Windows.Forms.ToolStripButton();
|
||||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
@@ -53,7 +55,8 @@
|
|||||||
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
|
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
|
||||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||||
this.toolStripDropDownButton1,
|
this.toolStripDropDownButton1,
|
||||||
this.toolStripStatusLabel1});
|
this.toolStripStatusLabel1,
|
||||||
|
this.toolStripProgressBar1});
|
||||||
this.statusStrip1.Location = new System.Drawing.Point(0, 803);
|
this.statusStrip1.Location = new System.Drawing.Point(0, 803);
|
||||||
this.statusStrip1.Name = "statusStrip1";
|
this.statusStrip1.Name = "statusStrip1";
|
||||||
this.statusStrip1.Size = new System.Drawing.Size(1428, 32);
|
this.statusStrip1.Size = new System.Drawing.Size(1428, 32);
|
||||||
@@ -78,6 +81,14 @@
|
|||||||
this.toolStripStatusLabel1.Size = new System.Drawing.Size(60, 25);
|
this.toolStripStatusLabel1.Size = new System.Drawing.Size(60, 25);
|
||||||
this.toolStripStatusLabel1.Text = "Ready";
|
this.toolStripStatusLabel1.Text = "Ready";
|
||||||
//
|
//
|
||||||
|
// toolStripProgressBar1
|
||||||
|
//
|
||||||
|
this.toolStripProgressBar1.MarqueeAnimationSpeed = 20;
|
||||||
|
this.toolStripProgressBar1.Name = "toolStripProgressBar1";
|
||||||
|
this.toolStripProgressBar1.Size = new System.Drawing.Size(100, 24);
|
||||||
|
this.toolStripProgressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
|
||||||
|
this.toolStripProgressBar1.Visible = false;
|
||||||
|
//
|
||||||
// toolStrip1
|
// toolStrip1
|
||||||
//
|
//
|
||||||
this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||||
@@ -85,6 +96,7 @@
|
|||||||
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||||
this.AddButton,
|
this.AddButton,
|
||||||
this.SyncButton,
|
this.SyncButton,
|
||||||
|
this.DownloadButton,
|
||||||
this.toolStripSeparator1,
|
this.toolStripSeparator1,
|
||||||
this.ConfigButton,
|
this.ConfigButton,
|
||||||
this.toolStripSeparator2,
|
this.toolStripSeparator2,
|
||||||
@@ -119,6 +131,17 @@
|
|||||||
this.SyncButton.Text = "Synchronize";
|
this.SyncButton.Text = "Synchronize";
|
||||||
this.SyncButton.Click += new System.EventHandler(this.SyncButton_Click);
|
this.SyncButton.Click += new System.EventHandler(this.SyncButton_Click);
|
||||||
//
|
//
|
||||||
|
// DownloadButton
|
||||||
|
//
|
||||||
|
this.DownloadButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
|
||||||
|
this.DownloadButton.Enabled = false;
|
||||||
|
this.DownloadButton.Image = ((System.Drawing.Image)(resources.GetObject("DownloadButton.Image")));
|
||||||
|
this.DownloadButton.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||||
|
this.DownloadButton.Name = "DownloadButton";
|
||||||
|
this.DownloadButton.Size = new System.Drawing.Size(34, 28);
|
||||||
|
this.DownloadButton.Text = "Download";
|
||||||
|
this.DownloadButton.Click += new System.EventHandler(this.DownloadButton_Click);
|
||||||
|
//
|
||||||
// toolStripSeparator1
|
// toolStripSeparator1
|
||||||
//
|
//
|
||||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||||
@@ -186,6 +209,7 @@
|
|||||||
this.listView1.Size = new System.Drawing.Size(1428, 764);
|
this.listView1.Size = new System.Drawing.Size(1428, 764);
|
||||||
this.listView1.TabIndex = 2;
|
this.listView1.TabIndex = 2;
|
||||||
this.listView1.UseCompatibleStateImageBehavior = false;
|
this.listView1.UseCompatibleStateImageBehavior = false;
|
||||||
|
this.listView1.DoubleClick += new System.EventHandler(this.listView1_DoubleClick);
|
||||||
//
|
//
|
||||||
// coverList
|
// coverList
|
||||||
//
|
//
|
||||||
@@ -235,5 +259,7 @@
|
|||||||
private ToolStripButton AboutButton;
|
private ToolStripButton AboutButton;
|
||||||
private ToolStripButton ErrorLogButton;
|
private ToolStripButton ErrorLogButton;
|
||||||
private ToolStripDropDownButton toolStripDropDownButton1;
|
private ToolStripDropDownButton toolStripDropDownButton1;
|
||||||
|
private ToolStripButton DownloadButton;
|
||||||
|
private ToolStripProgressBar toolStripProgressBar1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,15 +49,13 @@ namespace OpenSaveCloudClient
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.Invoke((MethodInvoker)delegate {
|
this.Invoke((MethodInvoker)delegate {
|
||||||
LogoutButton.Enabled = true;
|
|
||||||
AboutButton.Enabled = true;
|
AboutButton.Enabled = true;
|
||||||
if (_configuration.GetBoolean("synchronization.at_login", true))
|
if (_configuration.GetBoolean("synchronization.at_login", true))
|
||||||
{
|
{
|
||||||
SyncButton_Click(sender, e);
|
SyncButton_Click(sender, e);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
AddButton.Enabled = true;
|
LockCriticalControls(false);
|
||||||
SyncButton.Enabled = true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -81,7 +79,6 @@ namespace OpenSaveCloudClient
|
|||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
LogoutButton.Enabled = true;
|
|
||||||
AboutButton.Enabled = true;
|
AboutButton.Enabled = true;
|
||||||
if (_configuration.GetBoolean("synchronization.at_login", true))
|
if (_configuration.GetBoolean("synchronization.at_login", true))
|
||||||
{
|
{
|
||||||
@@ -89,8 +86,7 @@ namespace OpenSaveCloudClient
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddButton.Enabled = true;
|
LockCriticalControls(false);
|
||||||
SyncButton.Enabled = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +146,7 @@ namespace OpenSaveCloudClient
|
|||||||
foreach (GameSave game in saveManager.Saves)
|
foreach (GameSave game in saveManager.Saves)
|
||||||
{
|
{
|
||||||
ListViewItem itm = listView1.Items.Add(game.Name);
|
ListViewItem itm = listView1.Items.Add(game.Name);
|
||||||
|
itm.SubItems.Add(game.Uuid);
|
||||||
itm.ImageKey = "unknown_cover.png";
|
itm.ImageKey = "unknown_cover.png";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,25 +198,16 @@ namespace OpenSaveCloudClient
|
|||||||
text = String.Format("Ended: {0}", e.TaskInformation.Label);
|
text = String.Format("Ended: {0}", e.TaskInformation.Label);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (taskManager.TasksInformation.Count > 1)
|
|
||||||
{
|
|
||||||
this.Invoke((MethodInvoker)delegate {
|
|
||||||
toolStripStatusLabel1.Text = String.Format("{0} (and {1} more)", text, taskManager.TasksInformation.Count);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.Invoke((MethodInvoker)delegate {
|
this.Invoke((MethodInvoker)delegate {
|
||||||
|
toolStripProgressBar1.Visible = (taskManager.TasksInformation.Count(ti => ti.Status == AsyncTaskStatus.Running) > 0);
|
||||||
toolStripStatusLabel1.Text = text;
|
toolStripStatusLabel1.Text = text;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void LogoutButton_Click(object sender, EventArgs e)
|
private void LogoutButton_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
serverConnector.Logout();
|
serverConnector.Logout();
|
||||||
AddButton.Enabled = false;
|
LockCriticalControls(true);
|
||||||
LogoutButton.Enabled = false;
|
|
||||||
AboutButton.Enabled = false;
|
AboutButton.Enabled = false;
|
||||||
ShowLoginForm();
|
ShowLoginForm();
|
||||||
}
|
}
|
||||||
@@ -278,15 +266,112 @@ namespace OpenSaveCloudClient
|
|||||||
|
|
||||||
private void SyncButton_Click(object sender, EventArgs e)
|
private void SyncButton_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
AddButton.Enabled = false;
|
LockCriticalControls(true);
|
||||||
SyncButton.Enabled = false;
|
|
||||||
new Thread(() => {
|
new Thread(() => {
|
||||||
serverConnector.Synchronize();
|
serverConnector.Synchronize();
|
||||||
this.Invoke((MethodInvoker)delegate {
|
this.Invoke((MethodInvoker)delegate {
|
||||||
AddButton.Enabled = true;
|
LockCriticalControls(false);
|
||||||
SyncButton.Enabled = true;
|
});
|
||||||
|
}).Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DownloadButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
DownloadGameForm form = new DownloadGameForm();
|
||||||
|
if (form.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
List<GameSave> newGames = form.Result;
|
||||||
|
new Thread(async () =>
|
||||||
|
{
|
||||||
|
string taskUuid = StartTask("Downloading games from server", false, newGames.Count);
|
||||||
|
foreach (GameSave gameSave in newGames)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
saveManager.Saves.Add(gameSave);
|
||||||
|
List<GameSave> l = new()
|
||||||
|
{
|
||||||
|
gameSave
|
||||||
|
};
|
||||||
|
await serverConnector.DownloadGamesAsync(l);
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
logManager.AddError(ex);
|
||||||
|
}
|
||||||
|
taskManager.UpdateTaskProgress(taskUuid, 1);
|
||||||
|
}
|
||||||
|
saveManager.Save();
|
||||||
|
SetTaskEnded(taskUuid);
|
||||||
|
this.Invoke((MethodInvoker)delegate {
|
||||||
|
RefreshList();
|
||||||
});
|
});
|
||||||
}).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LockCriticalControls(bool l)
|
||||||
|
{
|
||||||
|
l = !l;
|
||||||
|
AddButton.Enabled = l;
|
||||||
|
SyncButton.Enabled = l;
|
||||||
|
DownloadButton.Enabled = l;
|
||||||
|
LogoutButton.Enabled = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void listView1_DoubleClick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (listView1.SelectedItems.Count == 1 && SyncButton.Enabled)
|
||||||
|
{
|
||||||
|
GameSave? g = saveManager.Saves.FirstOrDefault(g => g.Uuid == listView1.SelectedItems[0].SubItems[1].Text);
|
||||||
|
if (g != null)
|
||||||
|
{
|
||||||
|
DetailForm detail = new(g);
|
||||||
|
if (detail.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
ForcedSyncResult? r = detail.Result;
|
||||||
|
if (r != null)
|
||||||
|
{
|
||||||
|
LockCriticalControls(true);
|
||||||
|
new Thread(async () =>
|
||||||
|
{
|
||||||
|
List<GameSave> l = new()
|
||||||
|
{
|
||||||
|
g
|
||||||
|
};
|
||||||
|
string taskUuid;
|
||||||
|
switch (r)
|
||||||
|
{
|
||||||
|
case ForcedSyncResult.Download:
|
||||||
|
taskUuid = StartTask("Forcing download of " + g.Name, true, 1);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await serverConnector.DownloadGamesAsync(l);
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
SetTaskEnded(taskUuid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ForcedSyncResult.Upload:
|
||||||
|
taskUuid = StartTask("Forcing upload of " + g.Name, true, 1);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
g.Archive();
|
||||||
|
serverConnector.UploadGames(l);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SetTaskEnded(taskUuid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.Invoke((MethodInvoker)delegate {
|
||||||
|
LockCriticalControls(false);
|
||||||
|
});
|
||||||
|
}).Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -101,6 +101,18 @@
|
|||||||
8NaJQncgBYfJB0E8K2YLaCUfuj70UJc7r5ECaIYt2oqdXnrfUufBqlcAifVey7AbvdcyafSS6BWgHK3q
|
8NaJQncgBYfJB0E8K2YLaCUfuj70UJc7r5ECaIYt2oqdXnrfUufBqlcAifVey7AbvdcyafSS6BWgHK3q
|
||||||
6J3SNDwd2W4vlQSaKYD1ll1RlMX1dE0BdL062TKyC2DO6Tg2uazrFoKS1KiO/PtXkt5sNpvNAKfTD+zV
|
6J3SNDwd2W4vlQSaKYD1ll1RlMX1dE0BdL062TKyC2DO6Tg2uazrFoKS1KiO/PtXkt5sNpvNAKfTD+zV
|
||||||
uLXp5ptQAAAAAElFTkSuQmCC
|
uLXp5ptQAAAAAElFTkSuQmCC
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
|
YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAFPSURBVGhD7ZlhbQMxDIUPwiAMwiAMwiAMwhgMwiAMSiEU
|
||||||
|
QiEUwuavmiXr5HSXnGpfJH/S+5Mq8Xu9NnbVpSiKh/L8pyn5El1FP6JPFmbiSaTmVVM9iVeRNY9Ym4YK
|
||||||
|
kE0FyKYCZFMBspkmACODx9YArf0hfIh03mFws/wXAON22OOsUDBwEVmDJ5FyLwB7v0X2NYKEgglrQKUh
|
||||||
|
WgE884gA4dOqZwQRwgvwJmrtYT0FzHqG1h8vdHbWEGfwZNJohdiidPPKSIjDmFd6QhzOvLIlxGHNK/dC
|
||||||
|
hJp/EdEtUe8d7YXoNc9VPFr/hr32RjqlDTHyzturuLu+14h4Ir3QvLQD97C7vncAa1Hsrl8BdlIBKsBO
|
||||||
|
HhKAhvIeJP5PWNfvCsC9vT4gW93duPUDJEN08m5I7B0WLcaIkSngBhu9wSxK1B42v4YvUaTCxu6iKNJY
|
||||||
|
ll87VrNiCYfhAAAAAABJRU5ErkJggg==
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ConfigButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
@@ -167,7 +179,7 @@
|
|||||||
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
|
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
|
||||||
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
|
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
|
||||||
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA7OMCAAJNU0Z0AUkBTAMBAQAB
|
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA7OMCAAJNU0Z0AUkBTAMBAQAB
|
||||||
iAEAAYgBAAEIAQEBdgEBBP8BGQEACP8BQgFNATYHAAE2AwABKAMAASABBAIAAXYBAQIAAQEBAAEYBQAB
|
+AEAAfgBAAEIAQEBdgEBBP8BGQEACP8BQgFNATYHAAE2AwABKAMAASABBAIAAXYBAQIAAQEBAAEYBQAB
|
||||||
QAEUARIRAANSA1EBUgFRBVICUQNSAlEDUgJRAVIEUQFSBVEBUg1RAVAIUQFQAlEBUAFRAVADUQFQAVEE
|
QAEUARIRAANSA1EBUgFRBVICUQNSAlEDUgJRAVIEUQFSBVEBUg1RAVAIUQFQAlEBUAFRAVADUQFQAVEE
|
||||||
UAFRAVABUQJQAVECUAFRAVABUQ5QAU8BUAFPAlADTwZQAU8BUAFPAVADTwNQAU8CUAZPAVABTwFQBU8B
|
UAFRAVABUQJQAVECUAFRAVABUQ5QAU8BUAFPAlADTwZQAU8BUAFPAVADTwNQAU8CUAZPAVABTwFQBU8B
|
||||||
UAZPAU4ETwFOBE8BTgVPAU4DTwJOBE8CTgJPAU4BTwFOAU8HTgFPCE4BTwdOAU0GTgJNBE4BTQNOAk0B
|
UAZPAU4ETwFOBE8BTgVPAU4DTwJOBE8CTgJPAU4BTwFOAU8HTgFPCE4BTwdOAU0GTgJNBE4BTQNOAk0B
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ namespace OpenSaveCloudClient.Models
|
|||||||
{
|
{
|
||||||
|
|
||||||
private readonly string label;
|
private readonly string label;
|
||||||
private readonly int max;
|
private int max;
|
||||||
private int progress;
|
private int progress;
|
||||||
private AsyncTaskStatus status;
|
private AsyncTaskStatus status;
|
||||||
private readonly string uuid;
|
private readonly string uuid;
|
||||||
private bool undefined;
|
private bool undefined;
|
||||||
|
|
||||||
public string Label { get { return label; } }
|
public string Label { get { return label; } }
|
||||||
public int Max { get { return max; } }
|
public int Max { get { return max; } set { max = value; } }
|
||||||
public int Progress { get { return progress; } set { progress = value; } }
|
public int Progress { get { return progress; } set { progress = value; } }
|
||||||
public AsyncTaskStatus Status { get { return status; } set { status = value; } }
|
public AsyncTaskStatus Status { get { return status; } set { status = value; } }
|
||||||
|
|
||||||
|
|||||||
@@ -6,33 +6,34 @@ using System.Text.Json.Serialization;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using OpenSaveCloudClient.Core;
|
||||||
|
|
||||||
namespace OpenSaveCloudClient.Models
|
namespace OpenSaveCloudClient.Models
|
||||||
{
|
{
|
||||||
public class GameSave
|
public class GameSave
|
||||||
{
|
{
|
||||||
|
|
||||||
private int id;
|
private long id;
|
||||||
private string uuid;
|
private string uuid;
|
||||||
private readonly string name;
|
private readonly string name;
|
||||||
private readonly string folderPath;
|
private readonly string folderPath;
|
||||||
private readonly string description;
|
private readonly string description;
|
||||||
private string hash;
|
private string hash;
|
||||||
|
private string currentHash;
|
||||||
private readonly string? coverPath;
|
private readonly string? coverPath;
|
||||||
private int revision;
|
private long revision;
|
||||||
private bool synced;
|
private bool synced;
|
||||||
private bool localOnly;
|
|
||||||
|
|
||||||
public int Id { get { return id; } set { id = value; } }
|
public long Id { get { return id; } set { id = value; } }
|
||||||
public string Uuid { get { return uuid; } }
|
public string Uuid { get { return uuid; } }
|
||||||
public string Name { get { return name; } }
|
public string Name { get { return name; } }
|
||||||
public string Description { get { return description; } }
|
public string Description { get { return description; } }
|
||||||
public string FolderPath { get { return folderPath; } }
|
public string FolderPath { get { return folderPath; } }
|
||||||
public string Hash { get { return hash; } }
|
public string Hash { get { return hash; } }
|
||||||
|
public string CurrentHash { get { return currentHash; } }
|
||||||
public string? CoverPath { get { return coverPath; } }
|
public string? CoverPath { get { return coverPath; } }
|
||||||
public int Revision { get { return revision; } set { revision = value; } }
|
public long Revision { get { return revision; } set { revision = value; } }
|
||||||
public bool Synced { get { return synced; } set { synced = value; } }
|
public bool Synced { get { return synced; } set { synced = value; } }
|
||||||
public bool LocalOnly { get { return localOnly; } set { localOnly = value; } }
|
|
||||||
|
|
||||||
public GameSave(string name, string description, string folderPath, string? coverPath, int revision)
|
public GameSave(string name, string description, string folderPath, string? coverPath, int revision)
|
||||||
{
|
{
|
||||||
@@ -45,11 +46,10 @@ namespace OpenSaveCloudClient.Models
|
|||||||
this.coverPath = coverPath;
|
this.coverPath = coverPath;
|
||||||
this.revision = revision;
|
this.revision = revision;
|
||||||
synced = false;
|
synced = false;
|
||||||
localOnly = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
public GameSave(int id, string uuid, string name, string folderPath, string description, string hash, string? coverPath, int revision, bool synced, bool localOnly)
|
public GameSave(long id, string uuid, string name, string folderPath, string description, string hash, string currentHash, string? coverPath, long revision, bool synced)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
@@ -57,10 +57,10 @@ namespace OpenSaveCloudClient.Models
|
|||||||
this.folderPath = folderPath;
|
this.folderPath = folderPath;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.hash = hash;
|
this.hash = hash;
|
||||||
|
this.currentHash = currentHash;
|
||||||
this.coverPath = coverPath;
|
this.coverPath = coverPath;
|
||||||
this.revision = revision;
|
this.revision = revision;
|
||||||
this.synced = synced;
|
this.synced = synced;
|
||||||
this.localOnly = localOnly;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Archive()
|
public void Archive()
|
||||||
@@ -90,5 +90,25 @@ namespace OpenSaveCloudClient.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool DetectChanges()
|
||||||
|
{
|
||||||
|
byte[]? hashBytes = HashTool.HashDirectory(FolderPath);
|
||||||
|
if (hashBytes == null)
|
||||||
|
{
|
||||||
|
throw new Exception(String.Format("failed to get hash of directory '{0}'", FolderPath));
|
||||||
|
}
|
||||||
|
currentHash = BitConverter.ToString(hashBytes).Replace("-", "");
|
||||||
|
if (currentHash != hash)
|
||||||
|
{
|
||||||
|
synced = false;
|
||||||
|
}
|
||||||
|
return (currentHash != hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateHash()
|
||||||
|
{
|
||||||
|
hash = currentHash;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ namespace OpenSaveCloudClient.Models.Remote
|
|||||||
{
|
{
|
||||||
|
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
public int Id { get; set; }
|
public long Id { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("name")]
|
[JsonPropertyName("name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("rev")]
|
[JsonPropertyName("rev")]
|
||||||
public int Revision { get; set; }
|
public long Revision { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("hash")]
|
[JsonPropertyName("hash")]
|
||||||
public string Hash { get; set; }
|
public string Hash { get; set; }
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ namespace OpenSaveCloudClient.Models.Remote
|
|||||||
public class UploadGameInfo
|
public class UploadGameInfo
|
||||||
{
|
{
|
||||||
[JsonPropertyName("game_id")]
|
[JsonPropertyName("game_id")]
|
||||||
public int GameId { get; set; }
|
public long GameId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
<PackageIcon>logo.png</PackageIcon>
|
<PackageIcon>logo.png</PackageIcon>
|
||||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||||
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace OpenSaveCloudClient
|
|||||||
pb.Minimum = 0;
|
pb.Minimum = 0;
|
||||||
pb.Maximum = max;
|
pb.Maximum = max;
|
||||||
pb.Value = value;
|
pb.Value = value;
|
||||||
|
pb.MarqueeAnimationSpeed = 20;
|
||||||
if (undefined)
|
if (undefined)
|
||||||
{
|
{
|
||||||
pb.Style = ProgressBarStyle.Marquee;
|
pb.Style = ProgressBarStyle.Marquee;
|
||||||
|
|||||||
Reference in New Issue
Block a user