emo-client/Saradomin/Infrastructure/Services/PluginDownloadService.cs

207 lines
7.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using GitLabApiClient;
using GitLabApiClient.Models.Trees.Responses;
using Saradomin.Model;
using Saradomin.View.Windows;
namespace Saradomin.Infrastructure.Services
{
public class PluginDownloadService : IPluginDownloadService
{
private const string GroupName = "2009scape";
private const string ProjectName = "Tools/client-plugins";
private const string BranchName = "master";
private readonly GitLabClient _gitLabClient;
private static IList<Tree> _cachedQuery;
public PluginDownloadService()
{
_gitLabClient = new GitLabClient("https://gitlab.com");
}
private async Task PerformInitialQuery()
{
_cachedQuery = await _gitLabClient.Trees.GetAsync($"{GroupName}/{ProjectName}", o =>
{
o.Recursive = true;
o.Reference = BranchName;
}
);
}
public async Task<List<string>> FetchPluginMetadataPaths()
{
if (_cachedQuery == null) await PerformInitialQuery();
return _cachedQuery
.Where(x => x.Type == "blob" && x.Path.Contains("properties"))
.Select(x => x.Path)
.ToList();
}
public async Task<List<string>> FetchFileListForPlugin(string pluginName)
{
if (_cachedQuery == null) await PerformInitialQuery();
return _cachedQuery
.Where(x => x.Path.Contains(pluginName) && x.Type == "blob")
.Select(x => x.Path)
.ToList();
}
public async Task DownloadPluginFiles(string pluginName, string pluginRepositoryPath)
{
var directoryPath = Path.Combine(pluginRepositoryPath, pluginName);
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
else
{
foreach (var file in Directory.EnumerateFiles(directoryPath))
{
File.Delete(file);
}
}
var pluginFiles = await FetchFileListForPlugin(pluginName);
foreach (var filePath in pluginFiles)
{
var file = await _gitLabClient.Files.GetAsync($"{GroupName}/{ProjectName}", filePath, BranchName);
var downloadDirectoryPath = Path.Combine(pluginRepositoryPath, Path.GetDirectoryName(filePath)!);
var downloadFilePath = Path.Combine(pluginRepositoryPath, filePath);
Directory.CreateDirectory(downloadDirectoryPath);
await File.WriteAllBytesAsync(
downloadFilePath,
Convert.FromBase64String(file.Content)
);
}
}
public async Task <List<PluginInfo>> GetAllMetadata (string pluginRepositoryPath, bool isUpdateCheck, bool writePersistentUpdateFlag)
{
try
{
var metadataPaths = await FetchPluginMetadataPaths();
var infos = new List<PluginInfo>();
foreach (var path in metadataPaths)
{
infos.Add(await ProcessMetadataPath(path, pluginRepositoryPath, isUpdateCheck,
writePersistentUpdateFlag));
}
return isUpdateCheck ? infos.Where(x => x.UpdateAvailable).ToList() : infos;
}
catch (HttpRequestException e)
{
return new List<PluginInfo>();
}
}
private async Task<PluginInfo> ProcessMetadataPath(string path, string pluginRepositoryPath, bool isUpdateCheck, bool writePersistentUpdateFlag)
{
var pluginName = path.Split("/")[0];
var pluginFolder = Path.Combine(pluginRepositoryPath, pluginName);
if (!Directory.Exists(pluginFolder))
Directory.CreateDirectory(pluginFolder);
var filePath = Path.Combine(pluginFolder, "plugin.properties");
var fileContent = "";
var updateContent = "";
if (!File.Exists(filePath) || isUpdateCheck)
{
var file = await _gitLabClient.Files.GetAsync($"{GroupName}/{ProjectName}", path, BranchName);
if (isUpdateCheck && File.Exists(filePath))
{
fileContent = await File.ReadAllTextAsync(filePath);
updateContent = file.ContentDecoded;
}
else if (isUpdateCheck)
fileContent = updateContent = file.ContentDecoded;
else
fileContent = file.ContentDecoded;
if (!isUpdateCheck)
{
await File.WriteAllBytesAsync(
filePath,
Convert.FromBase64String(file.Content)
);
}
}
else if (File.Exists(filePath))
{
fileContent = await File.ReadAllTextAsync(filePath);
}
var info = ParseInfo(pluginName, fileContent);
var updatedInfo = !string.IsNullOrEmpty(updateContent) ? ParseInfo(pluginName, updateContent) : info;
if (isUpdateCheck && updatedInfo.Version != info.Version)
{
if (writePersistentUpdateFlag)
await File.WriteAllTextAsync(filePath, fileContent + "\r\nUPDATEAVAILABLE=1");
info.UpdateAvailable = true;
}
info.Installed = File.Exists(Path.Combine(pluginFolder, "plugin.class"));
return info;
}
public static PluginInfo ParseInfo(string pluginName, string text)
{
var lines = new Regex("\r\n|\r|\n").Split(text);
var parsedData = new Dictionary<string, string>();
var lastKey = "";
foreach (var lineInfo in lines.Select(t => t.Split("=")))
{
if (lineInfo.Length > 1)
{
parsedData.Add (lineInfo[0], lineInfo[1].Trim('\'').Trim());
lastKey = lineInfo[0];
}
else
{
parsedData[lastKey] += lineInfo[0];
}
}
var info = new PluginInfo(pluginName);
foreach (var (key, value) in parsedData)
{
switch (key.ToLower())
{
case "author":
info.Author = value;
break;
case "description":
info.Description = value.Replace("\\", System.Environment.NewLine);
break;
case "version":
info.Version = value;
break;
case "updateavailable":
info.UpdateAvailable = true;
break;
}
}
return info;
}
}
}