2025-04-10 20:39:04 +08:00
|
|
|
|
using MongoDB.Bson.Serialization.Attributes;
|
|
|
|
|
|
using MongoDB.Driver;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
|
|
|
|
|
|
|
|
namespace AssetDependencyGraph
|
|
|
|
|
|
{
|
|
|
|
|
|
[BsonIgnoreExtraElements]
|
|
|
|
|
|
public class AssetIdentify
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Path;
|
|
|
|
|
|
public string AssetType;
|
|
|
|
|
|
[AllowNull]
|
|
|
|
|
|
public string Guid;
|
|
|
|
|
|
[AllowNull]
|
|
|
|
|
|
public string Md5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[BsonIgnoreExtraElements]
|
|
|
|
|
|
public class AssetNode
|
|
|
|
|
|
{
|
|
|
|
|
|
public AssetIdentify Self;
|
|
|
|
|
|
public string AssetType;
|
|
|
|
|
|
public HashSet<AssetIdentify> Dependencies = new();
|
|
|
|
|
|
public HashSet<AssetIdentify> Dependent = new();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[BsonIgnoreExtraElements]
|
|
|
|
|
|
public sealed class FolderNode : AssetNode
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[BsonIgnoreExtraElements]
|
|
|
|
|
|
public sealed class PackageNode : AssetNode
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class AssetDependencyGraphDB
|
|
|
|
|
|
{
|
|
|
|
|
|
MongoClient client;
|
|
|
|
|
|
IMongoCollection<FolderNode> FolderNodes;
|
|
|
|
|
|
IMongoCollection<PackageNode> PackageNodes;
|
|
|
|
|
|
IMongoCollection<AssetNode> AssetNodes;
|
|
|
|
|
|
Dictionary<string, AssetNode> findCacheDic = new();
|
|
|
|
|
|
|
|
|
|
|
|
public AssetDependencyGraphDB(string user, string passwd, string ip)
|
|
|
|
|
|
{
|
2025-04-15 16:49:22 +08:00
|
|
|
|
MongoClientSettings settings;
|
|
|
|
|
|
if(string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(ip))
|
|
|
|
|
|
{
|
|
|
|
|
|
settings = MongoClientSettings.FromUrl(new MongoUrl($"mongodb://{ip}:27017/"));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
settings = MongoClientSettings.FromUrl(new MongoUrl($"mongodb://{user}:{passwd}@{ip}:27017/"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-10 20:39:04 +08:00
|
|
|
|
settings.ConnectTimeout = TimeSpan.FromSeconds(5);
|
|
|
|
|
|
settings.MinConnectionPoolSize = 1;
|
|
|
|
|
|
settings.MaxConnectionPoolSize = 25;
|
|
|
|
|
|
client = new MongoClient(settings);
|
|
|
|
|
|
var db = client.GetDatabase("assetgraph");
|
|
|
|
|
|
FolderNodes = db.GetCollection<FolderNode>("folder_nodes");
|
|
|
|
|
|
PackageNodes = db.GetCollection<PackageNode>("package_nodes");
|
|
|
|
|
|
AssetNodes = db.GetCollection<AssetNode>("asset_nodes");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Clean()
|
|
|
|
|
|
{
|
|
|
|
|
|
client.DropDatabase("assetgraph");
|
|
|
|
|
|
var db = client.GetDatabase("assetgraph");
|
|
|
|
|
|
FolderNodes = db.GetCollection<FolderNode>("folder_nodes");
|
|
|
|
|
|
PackageNodes = db.GetCollection<PackageNode>("package_nodes");
|
|
|
|
|
|
AssetNodes = db.GetCollection<AssetNode>("asset_nodes");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void UpdateOrInsert<T>(T node) where T : AssetNode
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (node)
|
|
|
|
|
|
{
|
|
|
|
|
|
case FolderNode folderNode:
|
|
|
|
|
|
{
|
|
|
|
|
|
var filter = Builders<FolderNode>.Filter.And(
|
|
|
|
|
|
Builders<FolderNode>.Filter.Eq(fn=>fn.Self.Path,node.Self.Path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found = FolderNodes.Find(filter);
|
|
|
|
|
|
if (found == null || found.CountDocuments() == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
FolderNodes.InsertOne(folderNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = FolderNodes.UpdateOne(filter, Builders<FolderNode>.Update.Combine(
|
|
|
|
|
|
Builders<FolderNode>.Update.Set(fn => fn.Self, folderNode.Self),
|
|
|
|
|
|
Builders<FolderNode>.Update.Set(fn => fn.AssetType, folderNode.AssetType),
|
|
|
|
|
|
Builders<FolderNode>.Update.Set(fn => fn.Dependencies, folderNode.Dependencies),
|
|
|
|
|
|
Builders<FolderNode>.Update.Set(fn => fn.Dependent, folderNode.Dependent)
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case PackageNode packageNode:
|
|
|
|
|
|
{
|
|
|
|
|
|
var filter = Builders<PackageNode>.Filter.And(
|
|
|
|
|
|
Builders<PackageNode>.Filter.Eq(fn => fn.Self.Path, node.Self.Path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found = PackageNodes.Find(filter);
|
|
|
|
|
|
if (found == null || found.CountDocuments() == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
PackageNodes.InsertOne(packageNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = PackageNodes.UpdateOne(filter, Builders<PackageNode>.Update.Combine(
|
|
|
|
|
|
Builders<PackageNode>.Update.Set(fn => fn.Self, packageNode.Self),
|
|
|
|
|
|
Builders<PackageNode>.Update.Set(fn => fn.AssetType, packageNode.AssetType),
|
|
|
|
|
|
Builders<PackageNode>.Update.Set(fn => fn.Dependencies, packageNode.Dependencies),
|
|
|
|
|
|
Builders<PackageNode>.Update.Set(fn => fn.Dependent, packageNode.Dependent)
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case AssetNode assetNode:
|
|
|
|
|
|
{
|
|
|
|
|
|
var filter = Builders<AssetNode>.Filter.And(
|
|
|
|
|
|
Builders<AssetNode>.Filter.Eq(fn => fn.Self.Path, node.Self.Path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found = AssetNodes.Find(filter);
|
|
|
|
|
|
if (found == null || found.CountDocuments() == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
AssetNodes.InsertOne(assetNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = AssetNodes.UpdateOne(filter, Builders<AssetNode>.Update.Combine(
|
|
|
|
|
|
Builders<AssetNode>.Update.Set(fn => fn.Self, assetNode.Self),
|
|
|
|
|
|
Builders<AssetNode>.Update.Set(fn => fn.AssetType, assetNode.AssetType),
|
|
|
|
|
|
Builders<AssetNode>.Update.Set(fn => fn.Dependencies, assetNode.Dependencies),
|
|
|
|
|
|
Builders<AssetNode>.Update.Set(fn => fn.Dependent, assetNode.Dependent)
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Delete<T>(T node) where T : AssetNode
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (node)
|
|
|
|
|
|
{
|
|
|
|
|
|
case FolderNode folderNode:
|
|
|
|
|
|
{
|
|
|
|
|
|
var filter = Builders<FolderNode>.Filter.And(
|
|
|
|
|
|
Builders<FolderNode>.Filter.Eq(fn => fn.Self.Path, node.Self.Path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found = FolderNodes.Find(filter);
|
|
|
|
|
|
if (found != null && found.CountDocuments() == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// TODO: del ref dep
|
|
|
|
|
|
FolderNodes.DeleteOne(filter);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case PackageNode packageNode:
|
|
|
|
|
|
{
|
|
|
|
|
|
var filter = Builders<PackageNode>.Filter.And(
|
|
|
|
|
|
Builders<PackageNode>.Filter.Eq(fn => fn.Self.Path, node.Self.Path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found = PackageNodes.Find(filter);
|
|
|
|
|
|
if (found != null && found.CountDocuments() == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// TODO: del ref dep
|
|
|
|
|
|
PackageNodes.DeleteOne(filter);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case AssetNode assetNode:
|
|
|
|
|
|
{
|
|
|
|
|
|
var filter = Builders<AssetNode>.Filter.And(
|
|
|
|
|
|
Builders<AssetNode>.Filter.Eq(fn => fn.Self.Path, node.Self.Path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found = AssetNodes.Find(filter);
|
|
|
|
|
|
if (found != null && found.CountDocuments() == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// TODO: del ref dep
|
|
|
|
|
|
AssetNodes.DeleteOne(filter);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public AssetNode Find(string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(findCacheDic.TryGetValue(path, out var assetNode))
|
|
|
|
|
|
{
|
|
|
|
|
|
return assetNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var filter = Builders<AssetNode>.Filter.And(
|
|
|
|
|
|
Builders<AssetNode>.Filter.Eq(fn => fn.Self.Path, path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found = AssetNodes.Find(filter);
|
|
|
|
|
|
if (found != null && found.CountDocuments() != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
assetNode = found.First();
|
|
|
|
|
|
findCacheDic[path] = assetNode;
|
|
|
|
|
|
return assetNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var filter1 = Builders<PackageNode>.Filter.And(
|
|
|
|
|
|
Builders<PackageNode>.Filter.Eq(fn => fn.Self.Path, path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found1 = PackageNodes.Find(filter1);
|
|
|
|
|
|
if (found1 != null && found1.CountDocuments() != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
assetNode = found1.First();
|
|
|
|
|
|
findCacheDic[path] = assetNode;
|
|
|
|
|
|
return assetNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var filter2 = Builders<FolderNode>.Filter.And(
|
|
|
|
|
|
Builders<FolderNode>.Filter.Eq(fn => fn.Self.Path, path)
|
|
|
|
|
|
);
|
|
|
|
|
|
var found2 = FolderNodes.Find(filter2);
|
|
|
|
|
|
if (found2 != null && found2.CountDocuments() != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
assetNode = found2.First();
|
|
|
|
|
|
findCacheDic[path] = assetNode;
|
|
|
|
|
|
return assetNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|