mirror of
https://gitlab.com/buildfeed/BuildFeed.git
synced 2024-03-22 21:10:34 +08:00
386 lines
16 KiB
C#
386 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using BuildFeed.Model.View;
|
|
using MongoDB.Bson;
|
|
using MongoDB.Driver;
|
|
|
|
namespace BuildFeed.Model
|
|
{
|
|
public partial class BuildRepository
|
|
{
|
|
public const int CURRENT_LONG_TERM = (int)ProjectFamily.Redstone5;
|
|
public const int CURRENT_RELEASE = (int)ProjectFamily.Redstone5;
|
|
public const int CURRENT_XBOX = (int)ProjectFamily.Redstone5;
|
|
|
|
private const string BUILD_COLLECTION_NAME = "builds";
|
|
private static readonly BsonDocument sortByAddedDate = new BsonDocument(nameof(Build.Added), -1);
|
|
private static readonly BsonDocument sortByCompileDate = new BsonDocument(nameof(Build.BuildTime), -1);
|
|
private static readonly BsonDocument sortByLeakedDate = new BsonDocument(nameof(Build.LeakDate), -1);
|
|
|
|
private static readonly BsonDocument sortByOrder = new BsonDocument
|
|
{
|
|
new BsonElement(nameof(Build.MajorVersion), -1),
|
|
new BsonElement(nameof(Build.MinorVersion), -1),
|
|
new BsonElement(nameof(Build.Number), -1),
|
|
new BsonElement(nameof(Build.Revision), -1),
|
|
new BsonElement(nameof(Build.BuildTime), -1)
|
|
};
|
|
|
|
private readonly IMongoCollection<Build> _buildCollection;
|
|
|
|
public BuildRepository(MongoConfig config)
|
|
{
|
|
var settings = new MongoClientSettings
|
|
{
|
|
Server = new MongoServerAddress(config.Host, config.Port)
|
|
};
|
|
|
|
if (!string.IsNullOrEmpty(config.Username) && !string.IsNullOrEmpty(config.Password))
|
|
{
|
|
settings.Credential =
|
|
MongoCredential.CreateCredential(config.Database, config.Username, config.Password);
|
|
}
|
|
|
|
var dbClient = new MongoClient(settings);
|
|
|
|
IMongoDatabase buildDatabase = dbClient.GetDatabase(config.Database);
|
|
_buildCollection = buildDatabase.GetCollection<Build>(BUILD_COLLECTION_NAME);
|
|
}
|
|
|
|
public async void SetupIndexes() => await SetupIndexesAsync();
|
|
|
|
private async Task SetupIndexesAsync()
|
|
{
|
|
var indexes = await (await _buildCollection.Indexes.ListAsync()).ToListAsync();
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_group"))
|
|
{
|
|
await
|
|
_buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Combine(
|
|
Builders<Build>.IndexKeys.Descending(b => b.MajorVersion),
|
|
Builders<Build>.IndexKeys.Descending(b => b.MinorVersion),
|
|
Builders<Build>.IndexKeys.Descending(b => b.Number),
|
|
Builders<Build>.IndexKeys.Descending(b => b.Revision)),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_group"
|
|
}));
|
|
}
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_legacy"))
|
|
{
|
|
await _buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Ascending(b => b.LegacyId),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_legacy"
|
|
}));
|
|
}
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_lab"))
|
|
{
|
|
await _buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Ascending(b => b.Lab),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_lab"
|
|
}));
|
|
}
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_date"))
|
|
{
|
|
await _buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Descending(b => b.BuildTime),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_date"
|
|
}));
|
|
}
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_bstr"))
|
|
{
|
|
await _buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Ascending(b => b.FullBuildString),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_bstr"
|
|
}));
|
|
}
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_alt_bstr"))
|
|
{
|
|
await _buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(
|
|
Builders<Build>.IndexKeys.Ascending(b => b.AlternateBuildString),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_alt_bstr"
|
|
}));
|
|
}
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_source"))
|
|
{
|
|
await _buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Ascending(b => b.SourceType),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_source"
|
|
}));
|
|
}
|
|
|
|
if (indexes.All(i => i["name"] != "_idx_family"))
|
|
{
|
|
await _buildCollection.Indexes.CreateOneAsync(new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Ascending(b => b.Family),
|
|
new CreateIndexOptions
|
|
{
|
|
Name = "_idx_family"
|
|
}));
|
|
}
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<Build>> Select() => await _buildCollection.Find(new BsonDocument()).ToListAsync();
|
|
|
|
public async Task<Build> SelectById(Guid id)
|
|
=> await _buildCollection.Find(Builders<Build>.Filter.Eq(b => b.Id, id)).SingleOrDefaultAsync();
|
|
|
|
public async Task<Build> SelectByLegacyId(long id) => await _buildCollection
|
|
.Find(Builders<Build>.Filter.Eq(b => b.LegacyId, id))
|
|
.SingleOrDefaultAsync();
|
|
|
|
public async Task<IReadOnlyCollection<Build>> SelectBuildsByOrder(int limit = -1, int skip = 0)
|
|
{
|
|
var query = _buildCollection.Find(new BsonDocument()).Sort(sortByOrder).Skip(skip);
|
|
|
|
if (limit > 0)
|
|
{
|
|
query = query.Limit(limit);
|
|
}
|
|
|
|
return await query.ToListAsync();
|
|
}
|
|
|
|
public async Task<IReadOnlyDictionary<ProjectFamily, FrontPage>> SelectFrontPage()
|
|
{
|
|
var families = new Dictionary<ProjectFamily, FrontPage>();
|
|
|
|
var query = _buildCollection.Aggregate(new AggregateOptions
|
|
{
|
|
AllowDiskUse = true
|
|
})
|
|
.Match(new BsonDocument
|
|
{
|
|
{
|
|
"$or", new BsonArray
|
|
{
|
|
new BsonDocument
|
|
{
|
|
{
|
|
nameof(Build.Family), new BsonDocument
|
|
{
|
|
{ "$gte", CURRENT_RELEASE }
|
|
}
|
|
}
|
|
},
|
|
new BsonDocument
|
|
{
|
|
{ nameof(Build.Family), CURRENT_LONG_TERM }
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.Group(new BsonDocument
|
|
{
|
|
{
|
|
"_id", new BsonDocument
|
|
{
|
|
{ nameof(Build.Family), $"${nameof(Build.Family)}" },
|
|
{ nameof(Build.LabUrl), $"${nameof(Build.LabUrl)}" },
|
|
{ nameof(Build.SourceType), $"${nameof(Build.SourceType)}" }
|
|
}
|
|
},
|
|
{
|
|
"items", new BsonDocument
|
|
{
|
|
{
|
|
"$push", new BsonDocument
|
|
{
|
|
{ nameof(Build.Id), "$_id" },
|
|
{ nameof(Build.MajorVersion), $"${nameof(Build.MajorVersion)}" },
|
|
{ nameof(Build.MinorVersion), $"${nameof(Build.MinorVersion)}" },
|
|
{ nameof(Build.Number), $"${nameof(Build.Number)}" },
|
|
{ nameof(Build.Revision), $"${nameof(Build.Revision)}" },
|
|
{ nameof(Build.Lab), $"${nameof(Build.Lab)}" },
|
|
{ nameof(Build.BuildTime), $"${nameof(Build.BuildTime)}" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var dbResults = await query.ToListAsync();
|
|
|
|
var results = (from g in dbResults
|
|
select new
|
|
{
|
|
Key = new
|
|
{
|
|
Family = (ProjectFamily)g["_id"].AsBsonDocument[nameof(Build.Family)].AsInt32,
|
|
LabUrl = g["_id"].AsBsonDocument[nameof(Build.LabUrl)].AsString,
|
|
SourceType = (TypeOfSource)g["_id"].AsBsonDocument[nameof(Build.SourceType)].AsInt32
|
|
},
|
|
|
|
Items = from i in g["items"].AsBsonArray
|
|
select new FrontPageBuild
|
|
{
|
|
Id = i[nameof(Build.Id)].AsGuid,
|
|
MajorVersion = (uint)i[nameof(Build.MajorVersion)].AsInt32,
|
|
MinorVersion = (uint)i[nameof(Build.MinorVersion)].AsInt32,
|
|
Number = (uint)i[nameof(Build.Number)].AsInt32,
|
|
Revision = (uint?)i[nameof(Build.Revision)].AsNullableInt32,
|
|
Lab = i[nameof(Build.Lab)].AsString,
|
|
BuildTime = i[nameof(Build.BuildTime)].ToNullableUniversalTime()
|
|
}
|
|
}).ToArray();
|
|
|
|
IEnumerable<ProjectFamily> listOfFamilies =
|
|
results.GroupBy(g => g.Key.Family).Select(g => g.Key).OrderByDescending(k => k);
|
|
|
|
foreach (ProjectFamily family in listOfFamilies)
|
|
{
|
|
var fp = new FrontPage
|
|
{
|
|
CurrentCanary = results.Where(g => g.Key.Family == family
|
|
&& !g.Key.LabUrl.Contains("xbox")
|
|
&& !g.Key.LabUrl.Contains("analog"))
|
|
.SelectMany(g => g.Items)
|
|
.OrderByDescending(b => b.BuildTime)
|
|
.FirstOrDefault(),
|
|
CurrentInsider = results
|
|
.Where(g => g.Key.Family == family
|
|
&& !g.Key.LabUrl.Contains("xbox")
|
|
&& !g.Key.LabUrl.Contains("analog")
|
|
&& (g.Key.SourceType == TypeOfSource.PublicRelease
|
|
|| g.Key.SourceType == TypeOfSource.UpdateGDR))
|
|
.SelectMany(g => g.Items)
|
|
.OrderByDescending(b => b.BuildTime)
|
|
.FirstOrDefault(),
|
|
CurrentRelease = results
|
|
.Where(g => (int)g.Key.Family <= CURRENT_RELEASE
|
|
&& g.Key.Family == family
|
|
&& g.Key.LabUrl.Contains("_release")
|
|
&& !g.Key.LabUrl.Contains("xbox")
|
|
&& !g.Key.LabUrl.Contains("analog")
|
|
&& (g.Key.SourceType == TypeOfSource.PublicRelease
|
|
|| g.Key.SourceType == TypeOfSource.UpdateGDR))
|
|
.SelectMany(g => g.Items)
|
|
.OrderByDescending(b => b.BuildTime)
|
|
.FirstOrDefault(),
|
|
CurrentXbox =
|
|
results.Where(g
|
|
=> (int)g.Key.Family >= CURRENT_XBOX
|
|
&& g.Key.Family == family
|
|
&& g.Key.LabUrl.Contains("xbox"))
|
|
.SelectMany(g => g.Items)
|
|
.OrderByDescending(b => b.BuildTime)
|
|
.FirstOrDefault(),
|
|
CurrentAnalog =
|
|
results.Where(g
|
|
=> (int)g.Key.Family >= CURRENT_RELEASE
|
|
&& g.Key.Family == family
|
|
&& g.Key.LabUrl.Contains("analog"))
|
|
.SelectMany(g => g.Items)
|
|
.OrderByDescending(b => b.BuildTime)
|
|
.FirstOrDefault()
|
|
};
|
|
|
|
families.Add(family, fp);
|
|
}
|
|
|
|
return families;
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<Build>> SelectBuildsByStringSearch(string term, int limit = -1)
|
|
{
|
|
var query = _buildCollection.Aggregate()
|
|
.Match(b => b.FullBuildString != null)
|
|
.Match(b => b.FullBuildString != "")
|
|
.Match(b => b.FullBuildString.ToLower().Contains(term.ToLower()));
|
|
|
|
if (limit > 0)
|
|
{
|
|
query = query.Limit(limit);
|
|
}
|
|
|
|
return await query.ToListAsync();
|
|
}
|
|
|
|
public async Task<Build> SelectBuildByFullBuildString(string build) => await _buildCollection
|
|
.Find(Builders<Build>.Filter.Eq(b => b.FullBuildString, build))
|
|
.SingleOrDefaultAsync();
|
|
|
|
private async Task<IReadOnlyCollection<Build>> SelectBuildsBySortOption(BsonDocument sort, int limit, int skip)
|
|
{
|
|
var query = _buildCollection.Find(new BsonDocument()).Sort(sort).Skip(skip);
|
|
|
|
if (limit > 0)
|
|
{
|
|
query = query.Limit(limit);
|
|
}
|
|
|
|
return await query.ToListAsync();
|
|
}
|
|
|
|
public Task<IReadOnlyCollection<Build>> SelectBuildsByCompileDate(int limit = -1, int skip = 0)
|
|
=> SelectBuildsBySortOption(sortByCompileDate, limit, skip);
|
|
|
|
public Task<IReadOnlyCollection<Build>> SelectBuildsByAddedDate(int limit = -1, int skip = 0)
|
|
=> SelectBuildsBySortOption(sortByAddedDate, limit, skip);
|
|
|
|
public Task<IReadOnlyCollection<Build>> SelectBuildsByLeakedDate(int limit = -1, int skip = 0)
|
|
=> SelectBuildsBySortOption(sortByLeakedDate, limit, skip);
|
|
|
|
public async Task Insert(Build item)
|
|
{
|
|
item.Id = Guid.NewGuid();
|
|
item.RegenerateCachedProperties();
|
|
|
|
await _buildCollection.InsertOneAsync(item);
|
|
}
|
|
|
|
public async Task InsertAll(IEnumerable<Build> items)
|
|
{
|
|
var generatedItems = new List<Build>();
|
|
foreach (Build item in items)
|
|
{
|
|
item.Id = Guid.NewGuid();
|
|
item.RegenerateCachedProperties();
|
|
|
|
generatedItems.Add(item);
|
|
}
|
|
|
|
await _buildCollection.InsertManyAsync(generatedItems);
|
|
}
|
|
|
|
public async Task Update(Build item)
|
|
{
|
|
Build old = await SelectById(item.Id);
|
|
item.Added = old.Added;
|
|
item.Modified = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc);
|
|
item.RegenerateCachedProperties();
|
|
|
|
await _buildCollection.ReplaceOneAsync(Builders<Build>.Filter.Eq(b => b.Id, item.Id), item);
|
|
}
|
|
|
|
public async Task RegenerateCachedProperties()
|
|
{
|
|
var builds = await Select();
|
|
foreach (Build bd in builds)
|
|
{
|
|
bd.RegenerateCachedProperties();
|
|
await _buildCollection.ReplaceOneAsync(Builders<Build>.Filter.Eq(b => b.Id, bd.Id), bd);
|
|
}
|
|
}
|
|
|
|
public async Task DeleteById(Guid id)
|
|
{
|
|
await _buildCollection.DeleteOneAsync(Builders<Build>.Filter.Eq(b => b.Id, id));
|
|
}
|
|
}
|
|
} |