Synchronize saves

This commit is contained in:
Aurélie Delhaie
2022-05-22 19:04:29 +02:00
parent b013815a96
commit 03ceaf3bda
33 changed files with 5751 additions and 81 deletions

View File

@@ -0,0 +1,100 @@
using OpenSaveCloudClient.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenSaveCloudClient.Core
{
public class LogManager
{
private static LogManager? instance;
private readonly List<Log> messages;
public List<Log> Messages { get { return messages; } }
private LogManager() {
messages = new List<Log>();
}
public static LogManager GetInstance()
{
if (instance == null) { instance = new LogManager(); }
return instance;
}
public void AddError(Exception ex)
{
Log log = new()
{
Message = ex.Message,
Severity = LogSeverity.Error,
};
messages.Add(log);
NewMessageEventArgs args = new()
{
Message = ex.Message,
Severity = LogSeverity.Error,
};
OnNewMessage(args);
}
public void AddInformation(string message)
{
Log log = new()
{
Message = message,
Severity = LogSeverity.Information,
};
messages.Add(log);
NewMessageEventArgs args = new()
{
Message = message,
Severity = LogSeverity.Information,
};
OnNewMessage(args);
}
public void Clear()
{
messages.Clear();
OnClear(new ClearEventArgs());
}
protected virtual void OnNewMessage(NewMessageEventArgs e)
{
EventHandler<NewMessageEventArgs> handler = NewMessage;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnClear(ClearEventArgs e)
{
EventHandler<ClearEventArgs> handler = Cleared;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler<NewMessageEventArgs> NewMessage;
public event EventHandler<ClearEventArgs> Cleared;
}
public class NewMessageEventArgs : EventArgs
{
public string Message { get; set; }
public LogSeverity Severity { get; set; }
}
public class ClearEventArgs : EventArgs
{
}
}

View File

@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using System.Text.Json; using System.Text.Json;
using OpenSaveCloudClient.Models.Remote; using OpenSaveCloudClient.Models.Remote;
using OpenSaveCloudClient.Models; using OpenSaveCloudClient.Models;
using System.Net.Http.Headers;
namespace OpenSaveCloudClient.Core namespace OpenSaveCloudClient.Core
{ {
@@ -20,7 +21,11 @@ namespace OpenSaveCloudClient.Core
private bool connected; private bool connected;
private ServerInformation? serverInformation; private ServerInformation? serverInformation;
private LogManager logManager;
private TaskManager taskManager;
private Configuration configuration; private Configuration configuration;
private SaveManager saveManager;
public string? Host { get { return host; } } public string? Host { get { return host; } }
public int Port { get { return port; } } public int Port { get { return port; } }
@@ -31,6 +36,9 @@ namespace OpenSaveCloudClient.Core
private ServerConnector() private ServerConnector()
{ {
configuration = Configuration.GetInstance(); configuration = Configuration.GetInstance();
logManager = LogManager.GetInstance();
taskManager = TaskManager.GetInstance();
saveManager = SaveManager.GetInstance();
} }
public static ServerConnector GetInstance() public static ServerConnector GetInstance()
@@ -49,33 +57,16 @@ namespace OpenSaveCloudClient.Core
{ {
host = "http://" + host; host = "http://" + host;
} }
logManager.AddInformation(String.Format("Binding server {0}:{1}", host, port));
this.host = host; this.host = host;
this.port = port; this.port = port;
GetServerInformation(); GetServerInformation();
} }
private void GetServerInformation()
{
try
{
HttpClient client = new();
HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/system/information", host, port)).Result;
if (response.IsSuccessStatusCode)
{
string responseText = response.Content.ReadAsStringAsync().Result;
serverInformation = JsonSerializer.Deserialize<ServerInformation>(responseText);
if (serverInformation != null)
{
bind = true;
}
}
}
catch (Exception)
{ }
}
public void Login(string username, string password) public void Login(string username, string password)
{ {
logManager.AddInformation("Loging in to the server");
string uuidTask = taskManager.StartTask("Login to the server", true, 1);
try try
{ {
HttpClient client = new HttpClient(); HttpClient client = new HttpClient();
@@ -91,19 +82,33 @@ namespace OpenSaveCloudClient.Core
token = accessToken.Token; token = accessToken.Token;
connected = true; connected = true;
SaveToConfig(); SaveToConfig();
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
}
else
{
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
} }
} }
else
{
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
}
}
catch (Exception ex)
{
logManager.AddError(ex);
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
} }
catch (Exception)
{ }
} }
public void Reconnect() public void Reconnect()
{ {
string? uuidTask = null;
try try
{ {
if (ReloadFromConfiguration()) if (ReloadFromConfiguration())
{ {
uuidTask = taskManager.StartTask("Login to the server", true, 1);
HttpClient client = new HttpClient(); HttpClient client = new HttpClient();
string json = JsonSerializer.Serialize(new AccessToken { Token = token }); string json = JsonSerializer.Serialize(new AccessToken { Token = token });
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json"); HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
@@ -116,16 +121,225 @@ namespace OpenSaveCloudClient.Core
{ {
connected = true; connected = true;
SaveToConfig(); SaveToConfig();
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
} }
else else
{ {
Logout(); Logout();
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
} }
} }
else
{
Logout();
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
}
} }
} }
catch (Exception) catch (Exception ex)
{ } {
logManager.AddError(ex);
if (uuidTask != null)
{
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed);
}
}
}
public void Logout()
{
serverInformation = null;
bind = false;
connected = false;
token = "";
configuration.SetValue("authentication.host", null);
configuration.SetValue("authentication.port", null);
configuration.SetValue("authentication.token", null);
configuration.Flush();
}
public Game? CreateGame(string name)
{
logManager.AddInformation("Creating game to server database");
string uuidTask = taskManager.StartTask("Creating game to server database", true, 1);
try
{
HttpClient client = new HttpClient();
string json = JsonSerializer.Serialize(new NewGameInfo { Name = name });
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
HttpResponseMessage response = client.PostAsync(string.Format("{0}:{1}/api/v1/game/create", host, port), content).Result;
if (response.IsSuccessStatusCode)
{
logManager.AddInformation("Game created!");
string responseText = response.Content.ReadAsStringAsync().Result;
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
return JsonSerializer.Deserialize<Game>(responseText);
} else
{
logManager.AddError(new Exception(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;
}
public void Synchronize()
{
string appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "osc");
string cachePath = Path.Combine(appdata, "cache");
logManager.AddInformation("Starting synchronization");
List<GameSave> games = saveManager.Saves;
string uuidTask = taskManager.StartTask("Synchronizing games", true, games.Count);
foreach (GameSave game in games)
{
try
{
Game? g = GetGameInfoByID(game.Id);
if (g != null)
{
if (g.Available)
{
if (g.Hash != game.Hash)
{
if (g.Revision != game.Revision)
{
logManager.AddInformation(String.Format("'{0}' was updated from another computer", game.Name));
} else
{
logManager.AddInformation(String.Format("'{0} need to be updated'", game.Name));
GameUploadToken? gut = LockGameToUpload(game.Id);
if (gut != null)
{
string archivePath = Path.Combine(cachePath, game.Uuid + ".bin");
UploadSave(gut.UploadToken, archivePath);
}
}
}
else
{
logManager.AddInformation(String.Format("'{0}' is up to date", game.Name));
}
} else
{
logManager.AddInformation(String.Format("First upload of '{0}'", game.Name));
GameUploadToken? gut = LockGameToUpload(game.Id);
if (gut != null)
{
string archivePath = Path.Combine(cachePath, game.Uuid + ".bin");
UploadSave(gut.UploadToken, archivePath);
}
}
} else
{
logManager.AddError(new Exception("Failed to get game information, the save will not be synchronized"));
}
} catch (Exception ex)
{
logManager.AddError(ex);
}
taskManager.UpdateTaskProgress(uuidTask, 1);
}
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
}
public Game? GetGameInfoByID(int gameId)
{
logManager.AddInformation("Getting game information from the server database");
string uuidTask = taskManager.StartTask("Getting game information", true, 1);
try
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/{2}", host, port, gameId)).Result;
if (response.IsSuccessStatusCode)
{
string responseText = response.Content.ReadAsStringAsync().Result;
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
return JsonSerializer.Deserialize<Game>(responseText);
}
else
{
logManager.AddError(new Exception(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;
}
public void UploadSave(string uploadToken, string filePath)
{
logManager.AddInformation("Uploading save");
string uuidTask = taskManager.StartTask("Uploading", true, 1);
try
{
MultipartFormDataContent multipartFormContent = new();
var fileStreamContent = new StreamContent(File.OpenRead(filePath));
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
multipartFormContent.Add(fileStreamContent, name: "file", fileName: "file.bin");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
client.DefaultRequestHeaders.Add("X-UPLOAD-KEY", uploadToken);
HttpResponseMessage response = client.PostAsync(string.Format("{0}:{1}/api/v1/game/upload", host, port), multipartFormContent).Result;
if (response.IsSuccessStatusCode)
{
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
return;
}
else
{
logManager.AddError(new Exception(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);
}
}
private GameUploadToken? LockGameToUpload(int gameId)
{
logManager.AddInformation("Locking game in the server");
string uuidTask = taskManager.StartTask("Locking game", true, 1);
try
{
HttpClient client = new HttpClient();
string json = JsonSerializer.Serialize(new UploadGameInfo { GameId = gameId });
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Add("Authorization", "bearer " + token);
HttpResponseMessage response = client.PostAsync(string.Format("{0}:{1}/api/v1/game/upload/init", host, port), content).Result;
if (response.IsSuccessStatusCode)
{
logManager.AddInformation("Game locked");
string responseText = response.Content.ReadAsStringAsync().Result;
taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended);
return JsonSerializer.Deserialize<GameUploadToken>(responseText);
}
else
{
logManager.AddError(new Exception(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;
} }
private bool ReloadFromConfiguration() private bool ReloadFromConfiguration()
@@ -150,23 +364,36 @@ namespace OpenSaveCloudClient.Core
} }
token = oldToken; token = oldToken;
} }
catch (Exception) catch (Exception ex)
{ {
logManager.AddError(ex);
return false; return false;
} }
return true; return true;
} }
public void Logout() private void GetServerInformation()
{ {
serverInformation = null; logManager.AddInformation("Getting server information");
bind = false; try
connected = false; {
token = ""; HttpClient client = new();
configuration.SetValue("authentication.host", null); HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/system/information", host, port)).Result;
configuration.SetValue("authentication.port", null); if (response.IsSuccessStatusCode)
configuration.SetValue("authentication.token", null); {
configuration.Flush(); string responseText = response.Content.ReadAsStringAsync().Result;
serverInformation = JsonSerializer.Deserialize<ServerInformation>(responseText);
if (serverInformation != null)
{
logManager.AddInformation("Server is connected");
bind = true;
}
}
}
catch (Exception ex)
{
logManager.AddError(ex);
}
} }
private void SaveToConfig() private void SaveToConfig()

View File

@@ -16,13 +16,15 @@ namespace OpenSaveCloudClient.Core
private readonly Dictionary<string, AsyncTaskInformation> _tasks; private readonly Dictionary<string, AsyncTaskInformation> _tasks;
private readonly Mutex mut; private readonly Mutex mut;
public List<AsyncTaskInformation> TasksInformation { get { return _tasks.Values.ToList(); } }
private TaskManager() private TaskManager()
{ {
_tasks = new Dictionary<string, AsyncTaskInformation>(); _tasks = new Dictionary<string, AsyncTaskInformation>();
mut = new Mutex(); mut = new Mutex();
timer = new System.Timers.Timer timer = new System.Timers.Timer
{ {
Interval = 2000 Interval = 10000
}; };
timer.Elapsed += timer_Tick; timer.Elapsed += timer_Tick;
timer.Start(); timer.Start();
@@ -37,16 +39,59 @@ namespace OpenSaveCloudClient.Core
return instance; return instance;
} }
public string StartTask(string label, int progressMax) public string StartTask(string label, bool undefined, int progressMax)
{ {
string uuid = Guid.NewGuid().ToString(); string uuid = Guid.NewGuid().ToString();
_tasks.Add(uuid, new AsyncTaskInformation(label, progressMax)); AsyncTaskInformation ati = new(uuid, label, undefined, progressMax);
_tasks.Add(uuid, ati);
TaskChangedEventArgs args = new()
{
TaskInformation = ati
};
OnTaskChanged(args);
return uuid; return uuid;
} }
public AsyncTaskInformation GetTask(string uuid) public void UpdateTaskProgress(string uuid, int progress)
{ {
return _tasks[uuid]; try
{
AsyncTaskInformation task = _tasks[uuid];
task.Add(progress);
task.Undefined = false;
TaskChangedEventArgs args = new()
{
TaskInformation = task
};
OnTaskChanged(args);
}
catch(Exception)
{
}
}
public void UpdateTaskStatus(string uuid, AsyncTaskStatus status)
{
try
{
AsyncTaskInformation task = _tasks[uuid];
if (status != AsyncTaskStatus.Running)
{
task.Progress = task.Max;
task.Undefined = false;
}
task.Status = status;
TaskChangedEventArgs args = new()
{
TaskInformation = task
};
OnTaskChanged(args);
}
catch (Exception)
{
}
} }
private void timer_Tick(object? sender, EventArgs e) private void timer_Tick(object? sender, EventArgs e)
@@ -66,6 +111,10 @@ namespace OpenSaveCloudClient.Core
{ {
_tasks.Remove(uuid); _tasks.Remove(uuid);
} }
if (toDelete.Count > 0)
{
OnTaskCleared(new TaskClearedEventArgs());
}
} }
finally finally
{ {
@@ -73,5 +122,35 @@ namespace OpenSaveCloudClient.Core
} }
} }
protected virtual void OnTaskChanged(TaskChangedEventArgs e)
{
EventHandler<TaskChangedEventArgs> handler = TaskChanged;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnTaskCleared(TaskClearedEventArgs e)
{
EventHandler<TaskClearedEventArgs> handler = TaskCleared;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler<TaskChangedEventArgs> TaskChanged;
public event EventHandler<TaskClearedEventArgs> TaskCleared;
}
public class TaskChangedEventArgs : EventArgs
{
public AsyncTaskInformation TaskInformation { get; set; }
}
public class TaskClearedEventArgs : EventArgs
{
} }
} }

View File

@@ -31,6 +31,7 @@
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GameLibrary)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GameLibrary));
this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripDropDownButton1 = new System.Windows.Forms.ToolStripDropDownButton();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
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();
@@ -39,9 +40,10 @@
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();
this.LogoutButton = new System.Windows.Forms.ToolStripButton(); this.LogoutButton = new System.Windows.Forms.ToolStripButton();
this.ErrorLogButton = new System.Windows.Forms.ToolStripButton();
this.AboutButton = new System.Windows.Forms.ToolStripButton();
this.listView1 = new System.Windows.Forms.ListView(); this.listView1 = new System.Windows.Forms.ListView();
this.coverList = new System.Windows.Forms.ImageList(this.components); this.coverList = new System.Windows.Forms.ImageList(this.components);
this.AboutButton = new System.Windows.Forms.ToolStripButton();
this.statusStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout();
this.toolStrip1.SuspendLayout(); this.toolStrip1.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
@@ -50,6 +52,7 @@
// //
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.toolStripStatusLabel1}); this.toolStripStatusLabel1});
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";
@@ -57,8 +60,20 @@
this.statusStrip1.TabIndex = 0; this.statusStrip1.TabIndex = 0;
this.statusStrip1.Text = "statusStrip1"; this.statusStrip1.Text = "statusStrip1";
// //
// toolStripDropDownButton1
//
this.toolStripDropDownButton1.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.toolStripDropDownButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripDropDownButton1.Image")));
this.toolStripDropDownButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripDropDownButton1.Name = "toolStripDropDownButton1";
this.toolStripDropDownButton1.ShowDropDownArrow = false;
this.toolStripDropDownButton1.Size = new System.Drawing.Size(28, 29);
this.toolStripDropDownButton1.Text = "toolStripDropDownButton1";
this.toolStripDropDownButton1.Click += new System.EventHandler(this.toolStripDropDownButton1_Click);
//
// toolStripStatusLabel1 // toolStripStatusLabel1
// //
this.toolStripStatusLabel1.BackColor = System.Drawing.SystemColors.Control;
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
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";
@@ -74,6 +89,7 @@
this.ConfigButton, this.ConfigButton,
this.toolStripSeparator2, this.toolStripSeparator2,
this.LogoutButton, this.LogoutButton,
this.ErrorLogButton,
this.AboutButton}); this.AboutButton});
this.toolStrip1.Location = new System.Drawing.Point(0, 0); this.toolStrip1.Location = new System.Drawing.Point(0, 0);
this.toolStrip1.Name = "toolStrip1"; this.toolStrip1.Name = "toolStrip1";
@@ -99,6 +115,7 @@
this.SyncButton.Name = "SyncButton"; this.SyncButton.Name = "SyncButton";
this.SyncButton.Size = new System.Drawing.Size(34, 28); this.SyncButton.Size = new System.Drawing.Size(34, 28);
this.SyncButton.Text = "Synchronize"; this.SyncButton.Text = "Synchronize";
this.SyncButton.Click += new System.EventHandler(this.SyncButton_Click);
// //
// toolStripSeparator1 // toolStripSeparator1
// //
@@ -130,6 +147,26 @@
this.LogoutButton.Text = "Logout"; this.LogoutButton.Text = "Logout";
this.LogoutButton.Click += new System.EventHandler(this.LogoutButton_Click); this.LogoutButton.Click += new System.EventHandler(this.LogoutButton_Click);
// //
// ErrorLogButton
//
this.ErrorLogButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.ErrorLogButton.Image = ((System.Drawing.Image)(resources.GetObject("ErrorLogButton.Image")));
this.ErrorLogButton.ImageTransparentColor = System.Drawing.Color.Magenta;
this.ErrorLogButton.Name = "ErrorLogButton";
this.ErrorLogButton.Size = new System.Drawing.Size(34, 28);
this.ErrorLogButton.Text = "Show log";
this.ErrorLogButton.Click += new System.EventHandler(this.LogButton_Click);
//
// AboutButton
//
this.AboutButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.AboutButton.Image = ((System.Drawing.Image)(resources.GetObject("AboutButton.Image")));
this.AboutButton.ImageTransparentColor = System.Drawing.Color.Magenta;
this.AboutButton.Name = "AboutButton";
this.AboutButton.Size = new System.Drawing.Size(34, 28);
this.AboutButton.Text = "About";
this.AboutButton.Click += new System.EventHandler(this.AboutButton_Click);
//
// listView1 // listView1
// //
this.listView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.listView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
@@ -153,16 +190,6 @@
this.coverList.TransparentColor = System.Drawing.Color.Transparent; this.coverList.TransparentColor = System.Drawing.Color.Transparent;
this.coverList.Images.SetKeyName(0, "unknown_cover.png"); this.coverList.Images.SetKeyName(0, "unknown_cover.png");
// //
// AboutButton
//
this.AboutButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.AboutButton.Image = ((System.Drawing.Image)(resources.GetObject("AboutButton.Image")));
this.AboutButton.ImageTransparentColor = System.Drawing.Color.Magenta;
this.AboutButton.Name = "AboutButton";
this.AboutButton.Size = new System.Drawing.Size(34, 28);
this.AboutButton.Text = "toolStripButton1";
this.AboutButton.Click += new System.EventHandler(this.AboutButton_Click);
//
// GameLibrary // GameLibrary
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F); this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
@@ -202,5 +229,7 @@
private ToolStripSeparator toolStripSeparator2; private ToolStripSeparator toolStripSeparator2;
private ImageList coverList; private ImageList coverList;
private ToolStripButton AboutButton; private ToolStripButton AboutButton;
private ToolStripButton ErrorLogButton;
private ToolStripDropDownButton toolStripDropDownButton1;
} }
} }

View File

@@ -1,6 +1,7 @@
using OpenSaveCloudClient.Models; using OpenSaveCloudClient.Models;
using OpenSaveCloudClient.Core; using OpenSaveCloudClient.Core;
using IGDB; using IGDB;
using OpenSaveCloudClient.Models.Remote;
namespace OpenSaveCloudClient namespace OpenSaveCloudClient
{ {
@@ -12,6 +13,7 @@ namespace OpenSaveCloudClient
private readonly SaveManager saveManager; private readonly SaveManager saveManager;
private readonly TaskManager taskManager; private readonly TaskManager taskManager;
private readonly ServerConnector serverConnector; private readonly ServerConnector serverConnector;
private readonly LogManager logManager;
public GameLibrary() public GameLibrary()
@@ -19,8 +21,10 @@ namespace OpenSaveCloudClient
InitializeComponent(); InitializeComponent();
saveManager = SaveManager.GetInstance(); saveManager = SaveManager.GetInstance();
taskManager = TaskManager.GetInstance(); taskManager = TaskManager.GetInstance();
taskManager.TaskChanged += taskManager_TaskChanged;
serverConnector = ServerConnector.GetInstance(); serverConnector = ServerConnector.GetInstance();
_configuration = Configuration.GetInstance(); _configuration = Configuration.GetInstance();
logManager = LogManager.GetInstance();
if (_configuration.GetBoolean("igdb.enabled", false)) if (_configuration.GetBoolean("igdb.enabled", false))
{ {
string clientId = _configuration.GetString("igdb.client_id", ""); string clientId = _configuration.GetString("igdb.client_id", "");
@@ -78,24 +82,28 @@ namespace OpenSaveCloudClient
string taskUuid = ""; string taskUuid = "";
try try
{ {
this.Invoke((MethodInvoker)delegate { taskUuid = StartTask(String.Format("Archiving \"{0}\"", newGame.Name), true, 1);
taskUuid = StartTask(String.Format("Archiving \"{0}\"", newGame.Name), 1); Game? g = serverConnector.CreateGame(newGame.Name);
}); if (g != null)
newGame.Archive(); {
saveManager.Saves.Add(newGame); newGame.Id = g.Id;
saveManager.Save(); newGame.Archive();
this.Invoke((MethodInvoker)delegate { saveManager.Saves.Add(newGame);
RefreshList(); saveManager.Save();
SetTaskEnded(taskUuid); SetTaskEnded(taskUuid);
});
}
catch (Exception)
{
this.statusStrip1.Invoke((MethodInvoker)delegate {
this.Invoke((MethodInvoker)delegate { this.Invoke((MethodInvoker)delegate {
SetTaskFailed(taskUuid); RefreshList();
}); });
}); } else
{
logManager.AddError(new Exception("Failed to create game on the server"));
SetTaskFailed(taskUuid);
}
}
catch (Exception ex)
{
logManager.AddError(ex);
SetTaskFailed(taskUuid);
} }
} }
@@ -115,24 +123,20 @@ namespace OpenSaveCloudClient
} }
} }
private string StartTask(string label, int maxProgress) private string StartTask(string label, bool undefined, int maxProgress)
{ {
toolStripStatusLabel1.Text = string.Format("{0}...", label); return taskManager.StartTask(label, undefined, maxProgress);
return taskManager.StartTask(label, maxProgress);
} }
private void SetTaskEnded(string uuid) private void SetTaskEnded(string uuid)
{ {
try try
{ {
var task = taskManager.GetTask(uuid); taskManager.UpdateTaskStatus(uuid, AsyncTaskStatus.Ended);
task.Progress = task.Max;
task.Status = AsyncTaskStatus.Ended;
toolStripStatusLabel1.Text = string.Format("{0} finished", task.Label);
} }
catch (Exception ex) catch (Exception ex)
{ {
//todo: catch exception logManager.AddError(ex);
} }
} }
@@ -140,16 +144,35 @@ namespace OpenSaveCloudClient
{ {
try try
{ {
var task = taskManager.GetTask(uuid); taskManager.UpdateTaskStatus(uuid, AsyncTaskStatus.Failed);
task.Status = AsyncTaskStatus.Failed;
toolStripStatusLabel1.Text = string.Format("{0} failed", task.Label);
} }
catch (Exception ex) catch (Exception ex)
{ {
//todo: catch exception logManager.AddError(ex);
} }
} }
private void taskManager_TaskChanged(object? sender, TaskChangedEventArgs e)
{
string text = "";
switch (e.TaskInformation.Status)
{
case AsyncTaskStatus.Running:
text = e.TaskInformation.Label;
break;
case AsyncTaskStatus.Stopped:
text = String.Format("Stopped: {0}", e.TaskInformation.Label);
break;
case AsyncTaskStatus.Failed:
text = String.Format("Failed: {0}", e.TaskInformation.Label);
break;
case AsyncTaskStatus.Ended:
text = String.Format("Ended: {0}", e.TaskInformation.Label);
break;
}
toolStripStatusLabel1.Text = text;
}
private void LogoutButton_Click(object sender, EventArgs e) private void LogoutButton_Click(object sender, EventArgs e)
{ {
serverConnector.Logout(); serverConnector.Logout();
@@ -161,5 +184,22 @@ namespace OpenSaveCloudClient
AboutBox aboutBox = new(); AboutBox aboutBox = new();
aboutBox.ShowDialog(); aboutBox.ShowDialog();
} }
private void LogButton_Click(object sender, EventArgs e)
{
LogsForm form = new();
form.Show();
}
private void toolStripDropDownButton1_Click(object sender, EventArgs e)
{
TasksForm form = new();
form.Show();
}
private void SyncButton_Click(object sender, EventArgs e)
{
new Thread(() => serverConnector.Synchronize()).Start();
}
} }
} }

View File

@@ -60,10 +60,28 @@
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value> <value>17, 17</value>
</metadata> </metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="toolStripDropDownButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAALLSURBVGhD7ZgLTQRBEERPAhKQgAQkIAEJOEACEpCABCQg
AQlIgH7kmgyz1fPfuwuhkgqBnemp/u4sh3/8EVwZb42Pxlfjm/Hd+GH8PP7k9xfjk/HOyJ6zwkU/G11o
L3H23nhyIJwoK1GjJDO7Yw/hKbF9Y8xBtqcz9WAcLZUecsa10YF4eodnQ1nCABvzgxRpVNZCHKZZIdHz
Blf7nIhnvSMV7+T3ZigDOTkUcSr1ERCJs7mdmngngWhCKfIcSJQ5aBTuSI942FRKiFObIRFI63QWafaW
iCcaRCUyMBP1EpaIB1GzNRsYwDLxRF8ZYEZffOQxpF5UlNPFiwdR9BmTe6BXPIOl+EZWxhhze0R/RDyV
wB4JDKrJs0f0R8X7cxnQqHxWznswKx7KMiLS6SJIQ69Er3iQXzmgLCNlWBkcxYh4wAdTvnaJAwji+6AF
o+KBqgyysoFKVWlkeWRqHxoz4oHqTXpiA+UAmxXytEZOzIoH0XDB9i+oEaocUDUJcydWiAeUqdq/gbpC
MMJSIEqtc7oTq8QDbOb7ZQ+oG6h6idWcwOlV4gH2chtyvDePK0PNiYi94gF7cjvyk1ItlN1+RK8TI+KB
qgyCvcHIVaLViVHx2Ff25HSMFueNnKPmxKh4oBqYqgiDqvqgVEaOyIkZ8ZHNqC+/oTyGLVfq/MAZ8UBN
H1jUggj1Ri6mLYE7MSs+0sHfeFZElAWEnQIIjN4jtX78gfIeyvm7GGRPnd0UfUc0UmGxiSaAuEg8lKOz
hOjSBimn5mg0oFQ2cLinov/QOf3yNgqEYyMqWSjfuq3gADWLU3I4zdWTEdZSEjXbSzKNgVomnKwj3cxq
IstdHqEQJ3lWE+3E1rT4FKUGW03OWireQSRL9TpLbM/2VRMoh5WO8Kbv7aMl4NDW/siJaPaeRbgC5UXt
Igp6hhAKaV5mPWORMrkI0f+Yw+HwBfyyJB+LA9gZAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>175, 17</value> <value>175, 17</value>
</metadata> </metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="AddButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="AddButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
@@ -114,6 +132,21 @@
uaSrPGgFRkCeovXc7vLgLWBaHjwFzMuDl8Aq5cFLoDVnuDx4LqFylkl58BQA5pmVB28B4HamGRECpqRA uaSrPGgFRkCeovXc7vLgLWBaHjwFzMuDl8Aq5cFLoDVnuDx4LqFylkl58BQA5pmVB28B4HamGRECpqRA
NC0BTkzcqNXEHXaDWkAbdhd3WC6tMpqECIDVpxAmAPxW2e2ffDWcRbVJkmQ1pukH2yfuhCTOIrwAAAAA NC0BTkzcqNXEHXaDWkAbdhd3WC6tMpqECIDVpxAmAPxW2e2ffDWcRbVJkmQ1pukH2yfuhCTOIrwAAAAA
SUVORK5CYII= SUVORK5CYII=
</value>
</data>
<data name="ErrorLogButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAH1SURBVGhD7ZkNTQQxEIVPAhKQgAQkIAEJOEACEpCABCQg
AQknAeZLbkmzmXb786a7R+4lLxCync5M56/ldMM/x93l5+GBoo/GV+On8ct4Nv5cyO/fxg/jm/HJeAig
NEqlyraQtc/G6UBxvOwp1UNkTTHk3ojXPCUUJPzYIwR4vTdUWsge7CXFi3GG8inZUwIEeRvM4HBePBhn
e37N7nAimfZWHqJDV2JTETyBe5Ay2wQ6pSdoTzZ1b4X3OXrkvCd/GyGjSBVU3qcALGBW8r5pZVVVUnRa
L2bxoPdtC9FtE4qNCJ81FHJhcURXJi+jNWBDZTMshhGbeotGqO4lFIUsIidNFYs94UjNK0cvv/6gSjSI
LHJqubV53/SwaIC3oJdpsqn6wMJsJVImXNrIgPJ0s8PdtRiQhfKiHmUAcrJQJluUAcUyyqOTt6iHUQYU
5yHlKBFlwOa9QJXIUQZsXi9VF5AIA6rG6YgLDVAYUP1WpNgsnRoVTkGn4l0gheoUljuxIq+aH7mUTW2U
OKIZZLsnbDY5vXU+VYNR2BM6k5t1fwt7Pu4yGUgQcVfeoux5fcGscCLmh8MmB5IpsjpRbbpeoluBh1Sz
DcQpw//M6AFx2vuSQaiwFhnVHTYSnApVA6XWp4OyeBkykOHtQyhdg6tR9IZ2nE6/TOo0oh+2u+YAAAAA
SUVORK5CYII=
</value> </value>
</data> </data>
<data name="AboutButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="AboutButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
@@ -137,7 +170,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA7OMCAAJNU0Z0AUkBTAMBAQAB SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA7OMCAAJNU0Z0AUkBTAMBAQAB
OAEAATgBAAEIAQEBdgEBBP8BGQEACP8BQgFNATYHAAE2AwABKAMAASABBAIAAXYBAQIAAQEBAAEYBQAB eAEAAXgBAAEIAQEBdgEBBP8BGQEACP8BQgFNATYHAAE2AwABKAMAASABBAIAAXYBAQIAAQEBAAEYBQAB
QAEUARIRAANSA1EBUgFRBVICUQNSAlEDUgJRAVIEUQFSBVEBUg1RAVAIUQFQAlEBUAFRAVADUQFQAVEE QAEUARIRAANSA1EBUgFRBVICUQNSAlEDUgJRAVIEUQFSBVEBUg1RAVAIUQFQAlEBUAFRAVADUQFQAVEE
UAFRAVABUQJQAVECUAFRAVABUQ5QAU8BUAFPAlADTwZQAU8BUAFPAVADTwNQAU8CUAZPAVABTwFQBU8B UAFRAVABUQJQAVECUAFRAVABUQ5QAU8BUAFPAlADTwZQAU8BUAFPAVADTwNQAU8CUAZPAVABTwFQBU8B
UAZPAU4ETwFOBE8BTgVPAU4DTwJOBE8CTgJPAU4BTwFOAU8HTgFPCE4BTwdOAU0GTgJNBE4BTQNOAk0B UAZPAU4ETwFOBE8BTgVPAU4DTwJOBE8CTgJPAU4BTwFOAU8HTgFPCE4BTwdOAU0GTgJNBE4BTQNOAk0B

View File

@@ -39,8 +39,10 @@
this.label4 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label();
this.PortNumericBox = new System.Windows.Forms.NumericUpDown(); this.PortNumericBox = new System.Windows.Forms.NumericUpDown();
this.LoginButton = new System.Windows.Forms.Button(); this.LoginButton = new System.Windows.Forms.Button();
this.AboutButton = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.PortNumericBox)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.PortNumericBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.AboutButton)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// pictureBox1 // pictureBox1
@@ -150,12 +152,25 @@
this.LoginButton.UseVisualStyleBackColor = true; this.LoginButton.UseVisualStyleBackColor = true;
this.LoginButton.Click += new System.EventHandler(this.LoginButton_Click); this.LoginButton.Click += new System.EventHandler(this.LoginButton_Click);
// //
// AboutButton
//
this.AboutButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.AboutButton.Image = ((System.Drawing.Image)(resources.GetObject("AboutButton.Image")));
this.AboutButton.Location = new System.Drawing.Point(12, 471);
this.AboutButton.Name = "AboutButton";
this.AboutButton.Size = new System.Drawing.Size(25, 25);
this.AboutButton.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.AboutButton.TabIndex = 6;
this.AboutButton.TabStop = false;
this.AboutButton.Click += new System.EventHandler(this.AboutButton_Click);
//
// LoginForm // LoginForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F); this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.Window; this.BackColor = System.Drawing.SystemColors.Window;
this.ClientSize = new System.Drawing.Size(1061, 508); this.ClientSize = new System.Drawing.Size(1061, 508);
this.Controls.Add(this.AboutButton);
this.Controls.Add(this.LoginButton); this.Controls.Add(this.LoginButton);
this.Controls.Add(this.PortNumericBox); this.Controls.Add(this.PortNumericBox);
this.Controls.Add(this.label4); this.Controls.Add(this.label4);
@@ -178,6 +193,7 @@
this.TopMost = true; this.TopMost = true;
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.PortNumericBox)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.PortNumericBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.AboutButton)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -195,5 +211,6 @@
private Label label4; private Label label4;
private NumericUpDown PortNumericBox; private NumericUpDown PortNumericBox;
private Button LoginButton; private Button LoginButton;
private PictureBox AboutButton;
} }
} }

View File

@@ -75,5 +75,11 @@ namespace OpenSaveCloudClient
PasswordTextBox.Enabled = value; PasswordTextBox.Enabled = value;
LoginButton.Enabled = value; LoginButton.Enabled = value;
} }
private void AboutButton_Click(object sender, EventArgs e)
{
LogsForm form = new();
form.Show();
}
} }
} }

View File

@@ -2291,6 +2291,20 @@
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAACw+D//5/8H2LG6Odv8xxUAAAAASUVORK5CYII= AAAAAACw+D//5/8H2LG6Odv8xxUAAAAASUVORK5CYII=
</value>
</data>
<data name="AboutButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAH1SURBVGhD7ZkNTQQxEIVPAhKQgAQkIAEJOEACEpCABCQgAQknAeZLbkmzmXb786a7R+4lLxCy
nc5M56/ldMM/x93l5+GBoo/GV+On8ct4Nv5cyO/fxg/jm/HJeAigNEqlyraQtc/G6UBxvOwp1UNkTTHk
3ojXPCUUJPzYIwR4vTdUWsge7CXFi3GG8inZUwIEeRvM4HBePBhne37N7nAimfZWHqJDV2JTETyBe5Ay
2wQ6pSdoTzZ1b4X3OXrkvCd/GyGjSBVU3qcALGBW8r5pZVVVUnRaL2bxoPdtC9FtE4qNCJ81FHJhcURX
Ji+jNWBDZTMshhGbeotGqO4lFIUsIidNFYs94UjNK0cvv/6gSjSILHJqubV53/SwaIC3oJdpsqn6wMJs
JVImXNrIgPJ0s8PdtRiQhfKiHmUAcrJQJluUAcUyyqOTt6iHUQYU5yHlKBFlwOa9QJXIUQZsXi9VF5AI
A6rG6YgLDVAYUP1WpNgsnRoVTkGn4l0gheoUljuxIq+aH7mUTW2UOKIZZLsnbDY5vXU+VYNR2BM6k5t1
fwt7Pu4yGUgQcVfeoux5fcGscCLmh8MmB5IpsjpRbbpeoluBh1SzDcQpw//M6AFx2vuSQaiwFhnVHTYS
nApVA6XWp4OyeBkykOHtQyhdg6tR9IZ2nE6/TOo0oh+2u+YAAAAASUVORK5CYII=
</value> </value>
</data> </data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

118
OpenSaveCloudClient/LogsForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,118 @@
namespace OpenSaveCloudClient
{
partial class LogsForm
{
/// <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(LogsForm));
this.listView1 = new System.Windows.Forms.ListView();
this.Message = new System.Windows.Forms.ColumnHeader();
this.Severity = new System.Windows.Forms.ColumnHeader();
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.toolStripButton1 = new System.Windows.Forms.ToolStripButton();
this.toolStrip1.SuspendLayout();
this.SuspendLayout();
//
// listView1
//
this.listView1.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.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.Message,
this.Severity});
this.listView1.GridLines = true;
this.listView1.Location = new System.Drawing.Point(0, 36);
this.listView1.MultiSelect = false;
this.listView1.Name = "listView1";
this.listView1.ShowGroups = false;
this.listView1.Size = new System.Drawing.Size(1065, 579);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
//
// Message
//
this.Message.Text = "Message";
this.Message.Width = 900;
//
// Severity
//
this.Severity.Text = "Severity";
this.Severity.Width = 150;
//
// toolStrip1
//
this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
this.toolStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripButton1});
this.toolStrip1.Location = new System.Drawing.Point(0, 0);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(1065, 33);
this.toolStrip1.TabIndex = 1;
this.toolStrip1.Text = "toolStrip1";
//
// toolStripButton1
//
this.toolStripButton1.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image")));
this.toolStripButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton1.Name = "toolStripButton1";
this.toolStripButton1.Size = new System.Drawing.Size(34, 28);
this.toolStripButton1.Text = "Clear";
this.toolStripButton1.Click += new System.EventHandler(this.toolStripButton1_Click);
//
// LogsForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1065, 615);
this.Controls.Add(this.toolStrip1);
this.Controls.Add(this.listView1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MinimumSize = new System.Drawing.Size(717, 316);
this.Name = "LogsForm";
this.Text = "Logs";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.LogForm_FormClosed);
this.Load += new System.EventHandler(this.LogsForm_Load);
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private ListView listView1;
private ToolStrip toolStrip1;
private ToolStripButton toolStripButton1;
private ColumnHeader Message;
private ColumnHeader Severity;
}
}

View File

@@ -0,0 +1,60 @@
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;
using OpenSaveCloudClient.Core;
using OpenSaveCloudClient.Models;
namespace OpenSaveCloudClient
{
public partial class LogsForm : Form
{
private LogManager logManager;
public LogsForm()
{
InitializeComponent();
logManager = LogManager.GetInstance();
logManager.NewMessage += logManager_NewError;
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
logManager.Clear();
listView1.Items.Clear();
}
public void logManager_NewError(object? sender, NewMessageEventArgs e)
{
this.Invoke((MethodInvoker)delegate
{
UpdateList();
});
}
private void UpdateList()
{
listView1.Items.Clear();
foreach (Log l in logManager.Messages)
{
ListViewItem lvi = listView1.Items.Add(l.Message);
lvi.SubItems.Add(l.Severity.ToString());
}
}
private void LogForm_FormClosed(object sender, FormClosedEventArgs e)
{
logManager.NewMessage -= logManager_NewError;
}
private void LogsForm_Load(object sender, EventArgs e)
{
UpdateList();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,15 +13,23 @@ namespace OpenSaveCloudClient.Models
private readonly int max; private readonly int max;
private int progress; private int progress;
private AsyncTaskStatus status; private AsyncTaskStatus status;
private readonly string uuid;
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; } }
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; } }
public AsyncTaskInformation(string label, int max) public bool Undefined { get { return undefined; } set { undefined = value; } }
public string Uuid { get { return uuid; } }
public AsyncTaskInformation(string uuid, string label, bool undefined, int max)
{ {
this.uuid = uuid;
this.label = label; this.label = label;
this.undefined = undefined;
this.max = max; this.max = max;
this.progress = 0; this.progress = 0;
status = AsyncTaskStatus.Running; status = AsyncTaskStatus.Running;

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenSaveCloudClient.Models
{
public enum LogSeverity
{
Error,
Warning,
Information
}
public class Log
{
public string Message { get; set; }
public LogSeverity Severity { get; set; }
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace OpenSaveCloudClient.Models.Remote
{
public class Game
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("revision")]
public int Revision { get; set; }
[JsonPropertyName("hash")]
public string Hash { get; set; }
[JsonPropertyName("last_update")]
public string LastUpdate { get; set; }
[JsonPropertyName("available")]
public bool Available { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace OpenSaveCloudClient.Models.Remote
{
public class GameUploadToken
{
[JsonPropertyName("upload_token")]
public string UploadToken { get; set; }
[JsonPropertyName("expire")]
public string Expire { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace OpenSaveCloudClient.Models.Remote
{
public class LockError
{
[JsonPropertyName("message")]
public string Message { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace OpenSaveCloudClient.Models.Remote
{
public class NewGameInfo
{
[JsonPropertyName("name")]
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace OpenSaveCloudClient.Models.Remote
{
public class UploadGameInfo
{
[JsonPropertyName("game_id")]
public int GameId { get; set; }
}
}

View File

@@ -0,0 +1,99 @@
namespace OpenSaveCloudClient
{
partial class TasksForm
{
/// <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(TasksForm));
this.listView1 = new System.Windows.Forms.ListView();
this.Task = new System.Windows.Forms.ColumnHeader();
this.Status = new System.Windows.Forms.ColumnHeader();
this.Progress = new System.Windows.Forms.ColumnHeader();
this.uuid = new System.Windows.Forms.ColumnHeader();
this.SuspendLayout();
//
// listView1
//
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.Task,
this.Status,
this.Progress,
this.uuid});
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView1.Location = new System.Drawing.Point(0, 0);
this.listView1.MultiSelect = false;
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(800, 450);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
//
// Task
//
this.Task.Text = "Task";
this.Task.Width = 450;
//
// Status
//
this.Status.Text = "Status";
this.Status.Width = 120;
//
// Progress
//
this.Progress.Text = "Progress";
this.Progress.Width = 200;
//
// uuid
//
this.uuid.Text = "UUID";
this.uuid.Width = 0;
//
// TasksForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.listView1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MinimumSize = new System.Drawing.Size(822, 506);
this.Name = "TasksForm";
this.Text = "Tasks";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.TasksForm_FormClosed);
this.Load += new System.EventHandler(this.TasksForm_Load);
this.ResumeLayout(false);
}
#endregion
private ListView listView1;
private ColumnHeader Task;
private ColumnHeader Progress;
private ColumnHeader uuid;
private ColumnHeader Status;
}
}

View File

@@ -0,0 +1,148 @@
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 partial class TasksForm : Form
{
private TaskManager taskManager;
public TasksForm()
{
InitializeComponent();
taskManager = TaskManager.GetInstance();
}
private void AddLVItem(string key, string name, string status, bool undefined, int value, int max)
{
ListViewItem lvi = new();
ProgressBar pb = new();
lvi.SubItems[0].Text = name;
lvi.SubItems.Add(status);
lvi.SubItems.Add("");
lvi.SubItems.Add(key);
listView1.Items.Add(lvi);
Rectangle r = lvi.SubItems[2].Bounds;
pb.SetBounds(r.X, r.Y, r.Width, r.Height);
pb.Minimum = 0;
pb.Maximum = max;
pb.Value = value;
if (undefined)
{
pb.Style = ProgressBarStyle.Marquee;
}
pb.Name = key;
listView1.Controls.Add(pb);
}
private void UpdateItemValue(string key, string status, bool undefined, int value)
{
ListViewItem? lvi;
ProgressBar? pb;
// find the LVI based on the "key" in
lvi = listView1.Items.Cast<ListViewItem>().FirstOrDefault(q => q.SubItems[3].Text == key);
if (lvi != null)
{
lvi.SubItems[1].Text = status;
}
pb = listView1.Controls.OfType<ProgressBar>().FirstOrDefault(q => q.Name == key);
if (pb != null)
{
pb.Value = value;
if (undefined)
{
pb.Style = ProgressBarStyle.Marquee;
} else
{
pb.Style = ProgressBarStyle.Blocks;
}
}
}
private void taskManager_UpdateTask(object? sender, TaskChangedEventArgs e)
{
this.Invoke((MethodInvoker)delegate {
ListViewItem? lvi = listView1.Items.Cast<ListViewItem>().FirstOrDefault(q => q.SubItems[3].Text == e.TaskInformation.Uuid);
if (lvi != null)
{
UpdateItemValue(e.TaskInformation.Uuid, e.TaskInformation.Status.ToString(), e.TaskInformation.Undefined, e.TaskInformation.Progress);
}
else
{
AddLVItem(e.TaskInformation.Uuid, e.TaskInformation.Label, e.TaskInformation.Status.ToString(), e.TaskInformation.Undefined, e.TaskInformation.Progress, e.TaskInformation.Max);
}
});
}
private void taskManager_ClearTask(object? sender, TaskClearedEventArgs e)
{
this.Invoke((MethodInvoker)delegate {
List<ListViewItem> toDelete = new();
List<ProgressBar> toDeletePb = new();
foreach (ListViewItem item in listView1.Items)
{
string uuid = item.SubItems[3].Text;
AsyncTaskInformation? ati = taskManager.TasksInformation.FirstOrDefault(t => t.Uuid == uuid);
if (ati == null)
{
toDelete.Add(item);
ProgressBar? pb = listView1.Controls.OfType<ProgressBar>().FirstOrDefault(q => q.Name == uuid);
if (pb != null)
{
toDeletePb.Add(pb);
}
}
}
foreach (ListViewItem item in toDelete)
{
listView1.Items.Remove(item);
}
foreach (ProgressBar progressBar in toDeletePb)
{
listView1.Controls.Remove(progressBar);
}
foreach (ListViewItem item in listView1.Items.Cast<ListViewItem>())
{
ProgressBar? pb = listView1.Controls.OfType<ProgressBar>().FirstOrDefault(q => q.Name == item.SubItems[3].Text);
if (pb != null)
{
Rectangle r = item.SubItems[2].Bounds;
pb.SetBounds(r.X, r.Y, r.Width, r.Height);
}
}
});
}
private void TasksForm_FormClosed(object sender, FormClosedEventArgs e)
{
taskManager.TaskChanged -= taskManager_UpdateTask;
taskManager.TaskCleared -= taskManager_ClearTask;
}
private void TasksForm_Load(object sender, EventArgs e)
{
foreach (AsyncTaskInformation ati in taskManager.TasksInformation)
{
AddLVItem(ati.Uuid, ati.Label, ati.Status.ToString(), ati.Undefined, ati.Progress, ati.Max);
}
taskManager.TaskChanged += taskManager_UpdateTask;
taskManager.TaskCleared += taskManager_ClearTask;
}
}
}

File diff suppressed because it is too large Load Diff