2020-05-19 03:46:33 +00:00
|
|
|
|
using System;
|
2020-05-20 12:18:47 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2020-05-19 03:46:33 +00:00
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Dapper;
|
|
|
|
|
using Wabbajack.Common;
|
2020-05-20 12:18:47 +00:00
|
|
|
|
using Wabbajack.Lib;
|
2020-05-19 03:46:33 +00:00
|
|
|
|
using Wabbajack.Server.DTOs;
|
|
|
|
|
|
|
|
|
|
namespace Wabbajack.Server.DataLayer
|
|
|
|
|
{
|
|
|
|
|
public partial class SqlService
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a patch record
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="patch"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task AddPatch(Patch patch)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
await conn.ExecuteAsync("INSERT INTO dbo.Patches (SrcId, DestId) VALUES (@SrcId, @DestId)",
|
|
|
|
|
new {SrcId = patch.Src.Id, DestId = patch.Dest.Id});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a patch record
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="patch"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task FinializePatch(Patch patch)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
2020-05-20 03:25:41 +00:00
|
|
|
|
await conn.ExecuteAsync("UPDATE dbo.Patches SET PatchSize = @PatchSize, Finished = @Finished, IsFailed = @IsFailed, FailMessage = @FailMessage WHERE SrcId = @SrcId AND DestID = @DestId",
|
2020-05-19 03:46:33 +00:00
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
SrcId = patch.Src.Id,
|
|
|
|
|
DestId = patch.Dest.Id,
|
|
|
|
|
PatchSize = patch.PatchSize,
|
2020-05-20 03:25:41 +00:00
|
|
|
|
Finished = patch.Finished,
|
|
|
|
|
IsFailed = patch.IsFailed,
|
|
|
|
|
FailMessage = patch.FailMessage
|
2020-05-19 03:46:33 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<Patch> FindPatch(Guid src, Guid dest)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
2020-05-20 03:25:41 +00:00
|
|
|
|
var patch = await conn.QueryFirstOrDefaultAsync<(long, DateTime?, bool?, string)>(
|
2020-07-13 22:10:05 +00:00
|
|
|
|
@"SELECT p.PatchSize, p.Finished, p.IsFailed, p.FailMessage
|
2020-05-20 03:25:41 +00:00
|
|
|
|
FROM dbo.Patches p
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads src ON p.SrcId = src.Id
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads dest ON p.SrcId = dest.Id
|
|
|
|
|
WHERE SrcId = @SrcId
|
|
|
|
|
AND DestId = @DestId
|
|
|
|
|
AND src.DownloadFinished IS NOT NULL
|
|
|
|
|
AND dest.DownloadFinished IS NOT NULL",
|
2020-05-19 03:46:33 +00:00
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
SrcId = src,
|
|
|
|
|
DestId = dest
|
|
|
|
|
});
|
|
|
|
|
if (patch == default)
|
2020-05-20 03:25:41 +00:00
|
|
|
|
return default;
|
2020-05-19 03:46:33 +00:00
|
|
|
|
|
|
|
|
|
return new Patch {
|
|
|
|
|
Src = await GetArchiveDownload(src),
|
|
|
|
|
Dest = await GetArchiveDownload(dest),
|
2020-05-20 03:25:41 +00:00
|
|
|
|
PatchSize = patch.Item1,
|
|
|
|
|
Finished = patch.Item2,
|
|
|
|
|
IsFailed = patch.Item3,
|
|
|
|
|
FailMessage = patch.Item4
|
2020-05-19 03:46:33 +00:00
|
|
|
|
};
|
2020-05-20 03:25:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<Patch> FindOrEnqueuePatch(Guid src, Guid dest)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
var trans = await conn.BeginTransactionAsync();
|
2020-05-21 02:15:23 +00:00
|
|
|
|
var patch = await conn.QueryFirstOrDefaultAsync<(Guid, Guid, long, DateTime?, bool?, string)>(
|
|
|
|
|
"SELECT SrcId, DestId, PatchSize, Finished, IsFailed, FailMessage FROM dbo.Patches WHERE SrcId = @SrcId AND DestId = @DestId",
|
2020-05-20 03:25:41 +00:00
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
SrcId = src,
|
|
|
|
|
DestId = dest
|
|
|
|
|
}, trans);
|
|
|
|
|
if (patch == default)
|
|
|
|
|
{
|
|
|
|
|
await conn.ExecuteAsync("INSERT INTO dbo.Patches (SrcId, DestId) VALUES (@SrcId, @DestId)",
|
|
|
|
|
new {SrcId = src, DestId = dest}, trans);
|
|
|
|
|
await trans.CommitAsync();
|
|
|
|
|
return new Patch {Src = await GetArchiveDownload(src), Dest = await GetArchiveDownload(dest),};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return new Patch {
|
|
|
|
|
Src = await GetArchiveDownload(src),
|
|
|
|
|
Dest = await GetArchiveDownload(dest),
|
2020-05-21 02:15:23 +00:00
|
|
|
|
PatchSize = patch.Item3,
|
|
|
|
|
Finished = patch.Item4,
|
|
|
|
|
IsFailed = patch.Item5,
|
|
|
|
|
FailMessage = patch.Item6
|
2020-05-20 03:25:41 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
2020-05-19 03:46:33 +00:00
|
|
|
|
|
|
|
|
|
}
|
2020-05-20 03:25:41 +00:00
|
|
|
|
|
|
|
|
|
public async Task<Patch> GetPendingPatch()
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
var patch = await conn.QueryFirstOrDefaultAsync<(Guid, Guid, long, DateTime?, bool?, string)>(
|
2020-06-06 21:44:30 +00:00
|
|
|
|
@"SELECT p.SrcId, p.DestId, p.PatchSize, p.Finished, p.IsFailed, p.FailMessage FROM dbo.Patches p
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads src ON src.Id = p.SrcId
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads dest ON dest.Id = p.DestId
|
|
|
|
|
WHERE p.Finished is NULL AND src.IsFailed = 0 AND dest.IsFailed = 0 ");
|
2020-05-20 03:25:41 +00:00
|
|
|
|
if (patch == default)
|
|
|
|
|
return default(Patch);
|
|
|
|
|
|
|
|
|
|
return new Patch {
|
|
|
|
|
Src = await GetArchiveDownload(patch.Item1),
|
|
|
|
|
Dest = await GetArchiveDownload(patch.Item2),
|
|
|
|
|
PatchSize = patch.Item3,
|
|
|
|
|
Finished = patch.Item4,
|
|
|
|
|
IsFailed = patch.Item5,
|
|
|
|
|
FailMessage = patch.Item6
|
|
|
|
|
};
|
|
|
|
|
}
|
2020-05-20 12:18:47 +00:00
|
|
|
|
|
|
|
|
|
public async Task<List<Patch>> PatchesForSource(Guid sourceDownload)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
var patches = await conn.QueryAsync<(Guid, Guid, long, DateTime?, bool?, string)>(
|
|
|
|
|
"SELECT SrcId, DestId, PatchSize, Finished, IsFailed, FailMessage FROM dbo.Patches WHERE SrcId = @SrcId", new {SrcId = sourceDownload});
|
|
|
|
|
|
2020-07-13 22:10:05 +00:00
|
|
|
|
return await AsPatches(patches);
|
|
|
|
|
}
|
|
|
|
|
public async Task<List<Patch>> PatchesForSource(Hash sourceHash)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
var patches = await conn.QueryAsync<(Guid, Guid, long, DateTime?, bool?, string)>(
|
|
|
|
|
@"SELECT p.SrcId, p.DestId, p.PatchSize, p.Finished, p.IsFailed, p.FailMessage
|
|
|
|
|
FROM dbo.Patches p
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads a ON p.SrcId = a.Id
|
|
|
|
|
|
|
|
|
|
WHERE a.Hash = @Hash AND p.Finished IS NOT NULL AND p.IsFailed = 0", new {Hash = sourceHash});
|
|
|
|
|
|
|
|
|
|
return await AsPatches(patches);
|
2020-05-20 12:18:47 +00:00
|
|
|
|
}
|
2020-06-06 21:44:30 +00:00
|
|
|
|
|
|
|
|
|
public async Task MarkPatchUsage(Guid srcId, Guid destId)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
await conn.ExecuteAsync(
|
|
|
|
|
@"UPDATE dbo.Patches SET Downloads = Downloads + 1, LastUsed = GETUTCDATE() WHERE SrcId = @srcId AND DestID = @destId",
|
|
|
|
|
new {SrcId = srcId, DestId = destId});
|
|
|
|
|
|
|
|
|
|
}
|
2020-06-29 21:57:09 +00:00
|
|
|
|
|
|
|
|
|
public async Task<List<Patch>> GetOldPatches()
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
var patches = await conn.QueryAsync<(Guid, Guid, long, DateTime?, bool?, string)>(
|
|
|
|
|
@"SELECT p.SrcId, p.DestId, p.PatchSize, p.Finished, p.IsFailed, p.FailMessage
|
|
|
|
|
FROM dbo.Patches p
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads a ON p.SrcId = a.Id
|
2020-07-19 23:09:59 +00:00
|
|
|
|
WHERE a.Hash not in (SELECT Hash FROM dbo.ModListArchives)");
|
2020-06-29 21:57:09 +00:00
|
|
|
|
|
2020-07-13 22:10:05 +00:00
|
|
|
|
return await AsPatches(patches);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<List<Patch>> AsPatches(IEnumerable<(Guid, Guid, long, DateTime?, bool?, string)> patches)
|
|
|
|
|
{
|
2020-06-29 21:57:09 +00:00
|
|
|
|
List<Patch> results = new List<Patch>();
|
|
|
|
|
foreach (var (srcId, destId, patchSize, finished, isFailed, failMessage) in patches)
|
|
|
|
|
{
|
2020-07-13 22:10:05 +00:00
|
|
|
|
results.Add(new Patch
|
|
|
|
|
{
|
|
|
|
|
Src = await GetArchiveDownload(srcId),
|
2020-06-29 21:57:09 +00:00
|
|
|
|
Dest = await GetArchiveDownload(destId),
|
|
|
|
|
PatchSize = patchSize,
|
|
|
|
|
Finished = finished,
|
|
|
|
|
IsFailed = isFailed,
|
|
|
|
|
FailMessage = failMessage
|
|
|
|
|
});
|
2020-07-13 22:10:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 21:57:09 +00:00
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-13 22:10:05 +00:00
|
|
|
|
|
2020-06-29 21:57:09 +00:00
|
|
|
|
public async Task DeletePatch(Patch patch)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
await conn.ExecuteAsync(@"DELETE FROM dbo.Patches WHERE SrcId = @SrcId AND DestId = @DestID",
|
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
SrcId = patch.Src.Id,
|
|
|
|
|
DestId = patch.Dest.Id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
2020-07-10 11:38:30 +00:00
|
|
|
|
|
|
|
|
|
public async Task<HashSet<(Hash, Hash)>> AllPatchHashes()
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
return (await conn.QueryAsync<(Hash, Hash)>(@"SELECT a1.Hash, a2.Hash
|
|
|
|
|
FROM dbo.Patches p
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads a1 ON a1.Id = p.SrcId
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads a2 on a2.Id = p.DestId")).ToHashSet();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task DeletePatchesForHashPair((Hash, Hash) sqlFile)
|
|
|
|
|
{
|
|
|
|
|
await using var conn = await Open();
|
|
|
|
|
await conn.ExecuteAsync(@"DELETE p
|
|
|
|
|
FROM dbo.Patches p
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads a1 ON a1.Id = p.SrcId
|
|
|
|
|
LEFT JOIN dbo.ArchiveDownloads a2 on a2.Id = p.DestId
|
|
|
|
|
WHERE a1.Hash = @SrcHash
|
|
|
|
|
AND a2.Hash = @DestHash", new
|
|
|
|
|
{
|
|
|
|
|
SrcHash = sqlFile.Item1,
|
|
|
|
|
DestHash = sqlFile.Item2
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
2020-07-13 22:10:05 +00:00
|
|
|
|
|
2020-05-19 03:46:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|