2023-01-14 15:09:45 -06:00
|
|
|
|
using LANCommander.SDK;
|
|
|
|
|
using LANCommander.SDK.Models;
|
2023-08-21 18:44:20 -05:00
|
|
|
|
using Playnite.SDK;
|
2023-01-04 20:31:02 -06:00
|
|
|
|
using RestSharp;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2023-01-06 22:12:03 -06:00
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.IO;
|
2023-01-04 20:31:02 -06:00
|
|
|
|
using System.Linq;
|
2023-01-05 01:07:17 -06:00
|
|
|
|
using System.Net;
|
2023-01-15 20:45:37 -06:00
|
|
|
|
using System.Net.NetworkInformation;
|
2023-01-04 20:31:02 -06:00
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
2023-01-08 12:09:57 -06:00
|
|
|
|
namespace LANCommander.PlaynitePlugin
|
2023-01-04 20:31:02 -06:00
|
|
|
|
{
|
|
|
|
|
internal class LANCommanderClient
|
|
|
|
|
{
|
2023-08-21 18:44:20 -05:00
|
|
|
|
public static readonly ILogger Logger = LogManager.GetLogger();
|
|
|
|
|
|
2023-01-07 12:34:12 -06:00
|
|
|
|
public readonly RestClient Client;
|
2023-01-06 02:39:00 -06:00
|
|
|
|
public AuthToken Token;
|
2023-01-04 20:31:02 -06:00
|
|
|
|
|
2023-01-07 12:34:12 -06:00
|
|
|
|
public LANCommanderClient(string baseUrl)
|
2023-01-04 20:31:02 -06:00
|
|
|
|
{
|
2023-01-25 21:08:05 -06:00
|
|
|
|
if (!String.IsNullOrWhiteSpace(baseUrl))
|
|
|
|
|
Client = new RestClient(baseUrl);
|
2023-01-04 20:31:02 -06:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-05 01:07:17 -06:00
|
|
|
|
private T PostRequest<T>(string route, object body)
|
|
|
|
|
{
|
|
|
|
|
var request = new RestRequest(route)
|
|
|
|
|
.AddJsonBody(body)
|
|
|
|
|
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
|
|
|
|
|
|
|
|
|
var response = Client.Post<T>(request);
|
|
|
|
|
|
|
|
|
|
return response.Data;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-06 02:39:00 -06:00
|
|
|
|
private T GetRequest<T>(string route)
|
|
|
|
|
{
|
|
|
|
|
var request = new RestRequest(route)
|
|
|
|
|
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
|
|
|
|
|
|
|
|
|
var response = Client.Get<T>(request);
|
|
|
|
|
|
|
|
|
|
return response.Data;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-06 22:12:03 -06:00
|
|
|
|
private string DownloadRequest(string route, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
|
|
|
|
|
{
|
2023-01-14 16:11:28 -06:00
|
|
|
|
route = route.TrimStart('/');
|
|
|
|
|
|
2023-01-06 22:12:03 -06:00
|
|
|
|
var client = new WebClient();
|
|
|
|
|
var tempFile = Path.GetTempFileName();
|
|
|
|
|
|
|
|
|
|
client.Headers.Add("Authorization", $"Bearer {Token.AccessToken}");
|
|
|
|
|
client.DownloadProgressChanged += (s, e) => progressHandler(e);
|
|
|
|
|
client.DownloadFileCompleted += (s, e) => completeHandler(e);
|
|
|
|
|
|
|
|
|
|
client.DownloadFileAsync(new Uri($"{Client.BaseUrl}{route}"), tempFile);
|
|
|
|
|
|
|
|
|
|
return tempFile;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-07 20:08:03 -05:00
|
|
|
|
private TrackableStream StreamRequest(string route)
|
|
|
|
|
{
|
|
|
|
|
route = route.TrimStart('/');
|
|
|
|
|
|
|
|
|
|
var client = new WebClient();
|
|
|
|
|
var tempFile = Path.GetTempFileName();
|
|
|
|
|
|
|
|
|
|
client.Headers.Add("Authorization", $"Bearer {Token.AccessToken}");
|
|
|
|
|
|
|
|
|
|
var ws = client.OpenRead(new Uri($"{Client.BaseUrl}{route}"));
|
|
|
|
|
|
|
|
|
|
return new TrackableStream(ws, true, Convert.ToInt64(client.ResponseHeaders["Content-Length"]));
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-13 17:37:36 -05:00
|
|
|
|
public async Task<AuthResponse> AuthenticateAsync(string username, string password)
|
2023-01-05 01:07:17 -06:00
|
|
|
|
{
|
2023-03-13 17:37:36 -05:00
|
|
|
|
var response = await Client.ExecuteAsync<AuthResponse>(new RestRequest("/api/Auth", Method.POST).AddJsonBody(new AuthRequest()
|
2023-01-05 01:07:17 -06:00
|
|
|
|
{
|
|
|
|
|
UserName = username,
|
|
|
|
|
Password = password
|
|
|
|
|
}));
|
|
|
|
|
|
2023-01-05 18:35:58 -06:00
|
|
|
|
switch (response.StatusCode)
|
|
|
|
|
{
|
|
|
|
|
case HttpStatusCode.OK:
|
|
|
|
|
return response.Data;
|
|
|
|
|
|
|
|
|
|
case HttpStatusCode.Forbidden:
|
|
|
|
|
case HttpStatusCode.BadRequest:
|
2023-03-14 01:10:02 -05:00
|
|
|
|
case HttpStatusCode.Unauthorized:
|
2023-01-05 18:35:58 -06:00
|
|
|
|
throw new WebException("Invalid username or password");
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw new WebException("Could not communicate with the server");
|
|
|
|
|
}
|
2023-01-05 01:07:17 -06:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-14 02:31:42 -05:00
|
|
|
|
public async Task<AuthResponse> RegisterAsync(string username, string password)
|
|
|
|
|
{
|
|
|
|
|
var response = await Client.ExecuteAsync<AuthResponse>(new RestRequest("/api/auth/register", Method.POST).AddJsonBody(new AuthRequest()
|
|
|
|
|
{
|
|
|
|
|
UserName = username,
|
|
|
|
|
Password = password
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
switch (response.StatusCode)
|
|
|
|
|
{
|
|
|
|
|
case HttpStatusCode.OK:
|
|
|
|
|
return response.Data;
|
|
|
|
|
|
|
|
|
|
case HttpStatusCode.BadRequest:
|
|
|
|
|
case HttpStatusCode.Forbidden:
|
|
|
|
|
case HttpStatusCode.Unauthorized:
|
|
|
|
|
throw new WebException(response.Data.Message);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw new WebException("Could not communicate with the server");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<bool> PingAsync()
|
|
|
|
|
{
|
|
|
|
|
var response = await Client.ExecuteAsync(new RestRequest("/api/Ping", Method.GET));
|
|
|
|
|
|
|
|
|
|
return response.StatusCode == HttpStatusCode.OK;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-05 01:07:17 -06:00
|
|
|
|
public AuthResponse RefreshToken(AuthToken token)
|
|
|
|
|
{
|
2023-08-22 18:59:10 -05:00
|
|
|
|
Logger.Trace("Refreshing token...");
|
|
|
|
|
|
2023-01-05 01:07:17 -06:00
|
|
|
|
var request = new RestRequest("/api/Auth/Refresh")
|
|
|
|
|
.AddJsonBody(token);
|
|
|
|
|
|
|
|
|
|
var response = Client.Post<AuthResponse>(request);
|
|
|
|
|
|
2023-01-07 12:34:12 -06:00
|
|
|
|
if (response.StatusCode != HttpStatusCode.OK)
|
|
|
|
|
throw new WebException(response.ErrorMessage);
|
|
|
|
|
|
2023-01-05 01:07:17 -06:00
|
|
|
|
return response.Data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool ValidateToken(AuthToken token)
|
|
|
|
|
{
|
2023-08-21 18:44:20 -05:00
|
|
|
|
Logger.Trace("Validating token...");
|
|
|
|
|
|
2023-03-17 02:07:25 -05:00
|
|
|
|
if (token == null)
|
2023-08-21 18:44:20 -05:00
|
|
|
|
{
|
|
|
|
|
Logger.Trace("Token is null!");
|
2023-03-17 02:07:25 -05:00
|
|
|
|
return false;
|
2023-08-21 18:44:20 -05:00
|
|
|
|
}
|
2023-03-17 02:07:25 -05:00
|
|
|
|
|
2023-01-05 01:07:17 -06:00
|
|
|
|
var request = new RestRequest("/api/Auth/Validate")
|
|
|
|
|
.AddHeader("Authorization", $"Bearer {token.AccessToken}");
|
|
|
|
|
|
2023-03-17 02:07:25 -05:00
|
|
|
|
if (String.IsNullOrEmpty(token.AccessToken) || String.IsNullOrEmpty(token.RefreshToken))
|
2023-08-21 18:44:20 -05:00
|
|
|
|
{
|
|
|
|
|
Logger.Trace("Token is empty!");
|
2023-03-17 02:07:25 -05:00
|
|
|
|
return false;
|
2023-08-21 18:44:20 -05:00
|
|
|
|
}
|
2023-03-17 02:07:25 -05:00
|
|
|
|
|
2023-01-05 01:07:17 -06:00
|
|
|
|
var response = Client.Post(request);
|
|
|
|
|
|
2023-08-21 18:44:20 -05:00
|
|
|
|
var valid = response.StatusCode == HttpStatusCode.OK;
|
|
|
|
|
|
|
|
|
|
if (valid)
|
|
|
|
|
Logger.Trace("Token is valid!");
|
|
|
|
|
else
|
|
|
|
|
Logger.Trace("Token is invalid!");
|
|
|
|
|
|
2023-01-05 01:07:17 -06:00
|
|
|
|
return response.StatusCode == HttpStatusCode.OK;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-04 20:31:02 -06:00
|
|
|
|
public IEnumerable<Game> GetGames()
|
|
|
|
|
{
|
2023-01-06 02:39:00 -06:00
|
|
|
|
return GetRequest<IEnumerable<Game>>("/api/Games");
|
2023-01-05 01:07:17 -06:00
|
|
|
|
}
|
2023-01-06 22:12:03 -06:00
|
|
|
|
|
|
|
|
|
public Game GetGame(Guid id)
|
|
|
|
|
{
|
|
|
|
|
return GetRequest<Game>($"/api/Games/{id}");
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-14 15:09:45 -06:00
|
|
|
|
public GameManifest GetGameManifest(Guid id)
|
|
|
|
|
{
|
|
|
|
|
return GetRequest<GameManifest>($"/api/Games/{id}/Manifest");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string DownloadGame(Guid id, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
|
|
|
|
|
{
|
|
|
|
|
return DownloadRequest($"/api/Games/{id}/Download", progressHandler, completeHandler);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-07 20:08:03 -05:00
|
|
|
|
public TrackableStream StreamGame(Guid id)
|
|
|
|
|
{
|
|
|
|
|
return StreamRequest($"/api/Games/{id}/Download");
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-06 22:12:03 -06:00
|
|
|
|
public string DownloadArchive(Guid id, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
|
|
|
|
|
{
|
2023-01-14 16:11:28 -06:00
|
|
|
|
return DownloadRequest($"/api/Archives/Download/{id}", progressHandler, completeHandler);
|
2023-01-06 22:12:03 -06:00
|
|
|
|
}
|
2023-01-15 20:45:37 -06:00
|
|
|
|
|
2023-03-28 21:30:29 -05:00
|
|
|
|
public string DownloadSave(Guid id, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
|
|
|
|
|
{
|
|
|
|
|
return DownloadRequest($"/api/Saves/Download/{id}", progressHandler, completeHandler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string DownloadLatestSave(Guid gameId, Action<DownloadProgressChangedEventArgs> progressHandler, Action<AsyncCompletedEventArgs> completeHandler)
|
|
|
|
|
{
|
|
|
|
|
return DownloadRequest($"/api/Saves/DownloadLatest/{gameId}", progressHandler, completeHandler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public GameSave UploadSave(string gameId, byte[] data)
|
|
|
|
|
{
|
2023-08-21 18:44:20 -05:00
|
|
|
|
Logger.Trace("Uploading save...");
|
|
|
|
|
|
2023-03-28 21:30:29 -05:00
|
|
|
|
var request = new RestRequest($"/api/Saves/Upload/{gameId}", Method.POST)
|
|
|
|
|
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
|
|
|
|
|
|
|
|
|
request.AddFile(gameId, data, gameId);
|
|
|
|
|
|
|
|
|
|
var response = Client.Post<GameSave>(request);
|
|
|
|
|
|
|
|
|
|
return response.Data;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-15 20:45:37 -06:00
|
|
|
|
public string GetKey(Guid id)
|
|
|
|
|
{
|
2023-08-21 18:44:20 -05:00
|
|
|
|
Logger.Trace("Requesting key allocation...");
|
|
|
|
|
|
2023-01-15 20:45:37 -06:00
|
|
|
|
var macAddress = GetMacAddress();
|
|
|
|
|
|
|
|
|
|
var request = new KeyRequest()
|
|
|
|
|
{
|
|
|
|
|
GameId = id,
|
|
|
|
|
MacAddress = macAddress,
|
|
|
|
|
ComputerName = Environment.MachineName,
|
|
|
|
|
IpAddress = GetIpAddress(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var response = PostRequest<Key>($"/api/Keys/Get", request);
|
|
|
|
|
|
|
|
|
|
return response.Value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-28 17:18:41 -06:00
|
|
|
|
public string GetAllocatedKey(Guid id)
|
|
|
|
|
{
|
2023-08-21 18:44:20 -05:00
|
|
|
|
Logger.Trace("Requesting allocated key...");
|
|
|
|
|
|
2023-01-28 17:18:41 -06:00
|
|
|
|
var macAddress = GetMacAddress();
|
|
|
|
|
|
|
|
|
|
var request = new KeyRequest()
|
|
|
|
|
{
|
|
|
|
|
GameId = id,
|
|
|
|
|
MacAddress = macAddress,
|
|
|
|
|
ComputerName = Environment.MachineName,
|
|
|
|
|
IpAddress = GetIpAddress(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var response = PostRequest<Key>($"/api/Keys/GetAllocated/{id}", request);
|
|
|
|
|
|
|
|
|
|
if (response == null)
|
|
|
|
|
return String.Empty;
|
|
|
|
|
|
|
|
|
|
return response.Value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-15 20:45:37 -06:00
|
|
|
|
public string GetNewKey(Guid id)
|
|
|
|
|
{
|
2023-08-21 18:44:20 -05:00
|
|
|
|
Logger.Trace("Requesting new key allocation...");
|
|
|
|
|
|
2023-01-15 20:45:37 -06:00
|
|
|
|
var macAddress = GetMacAddress();
|
|
|
|
|
|
|
|
|
|
var request = new KeyRequest()
|
|
|
|
|
{
|
|
|
|
|
GameId = id,
|
|
|
|
|
MacAddress = macAddress,
|
|
|
|
|
ComputerName = Environment.MachineName,
|
|
|
|
|
IpAddress = GetIpAddress(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var response = PostRequest<Key>($"/api/Keys/Allocate/{id}", request);
|
|
|
|
|
|
|
|
|
|
if (response == null)
|
|
|
|
|
return String.Empty;
|
|
|
|
|
|
|
|
|
|
return response.Value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 20:48:12 -05:00
|
|
|
|
public User GetProfile()
|
|
|
|
|
{
|
|
|
|
|
Logger.Trace("Requesting player's profile...");
|
|
|
|
|
|
|
|
|
|
return GetRequest<User>("/api/Profile");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string ChangeAlias(string alias)
|
|
|
|
|
{
|
|
|
|
|
Logger.Trace("Requesting to change player alias...");
|
|
|
|
|
|
|
|
|
|
var response = PostRequest<object>("/api/Profile/ChangeAlias", alias);
|
|
|
|
|
|
|
|
|
|
return alias;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-15 20:45:37 -06:00
|
|
|
|
private string GetMacAddress()
|
|
|
|
|
{
|
|
|
|
|
return NetworkInterface.GetAllNetworkInterfaces()
|
|
|
|
|
.Where(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)
|
|
|
|
|
.Select(nic => nic.GetPhysicalAddress().ToString())
|
|
|
|
|
.FirstOrDefault();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetIpAddress()
|
|
|
|
|
{
|
|
|
|
|
return Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();
|
|
|
|
|
}
|
2023-01-04 20:31:02 -06:00
|
|
|
|
}
|
|
|
|
|
}
|