BGPLite/BGPLite.Api/PeerStore.cs
Mikhail Movchan f2e9d82083 feat: add custom ASN support for peers
- Introduce `PeerCustomAsn` entity and database schema for managing peer-specific custom ASNs.
- Update `PeerStore` with CRUD methods for custom ASNs.
- Enhance `BgpSession` to load and process custom ASN prefixes.
- Extend API to handle custom ASN retrieval and updates in peer operations.
2026-06-11 20:18:08 +03:00

197 lines
6.4 KiB
C#

using BGPLite.Api.Entities;
using BGPLite.Server;
using Microsoft.EntityFrameworkCore;
namespace BGPLite.Api;
public sealed class PeerStore : IPeerStore
{
private readonly IDbContextFactory<BgpDbContext> _dbFactory;
public PeerStore(IDbContextFactory<BgpDbContext> dbFactory) => _dbFactory = dbFactory;
public string CreatePeer(string ip, uint asn, string? description)
{
using var db = _dbFactory.CreateDbContext();
var existing = db.Peers.FirstOrDefault(p => p.Ip == ip);
if (existing is not null)
{
existing.Asn = asn;
existing.Description = description;
db.SaveChanges();
return existing.Id;
}
var peer = new Peer { Ip = ip, Asn = asn, Description = description };
db.Peers.Add(peer);
db.SaveChanges();
return peer.Id;
}
public void UpsertPeer(string ip, uint asn)
{
using var db = _dbFactory.CreateDbContext();
var peer = db.Peers.FirstOrDefault(p => p.Ip == ip);
if (peer is null)
{
db.Peers.Add(new Peer { Ip = ip, Asn = asn, Status = "active", LastSessionAt = DateTime.UtcNow });
}
else
{
peer.Asn = asn;
peer.Status = "active";
peer.LastSessionAt = DateTime.UtcNow;
}
db.SaveChanges();
}
public void UpdateSessionStatus(string ip, bool active)
{
using var db = _dbFactory.CreateDbContext();
var peer = db.Peers.FirstOrDefault(p => p.Ip == ip);
if (peer is null) return;
peer.Status = active ? "active" : "inactive";
if (active) peer.LastSessionAt = DateTime.UtcNow;
db.SaveChanges();
}
public void DeletePeer(string id)
{
using var db = _dbFactory.CreateDbContext();
db.Peers.Where(p => p.Id == id).ExecuteDelete();
}
public List<Peer> GetAllPeers()
{
using var db = _dbFactory.CreateDbContext();
return db.Peers.Include(p => p.Communities).ToList();
}
public Peer? GetDbPeerById(string id)
{
using var db = _dbFactory.CreateDbContext();
return db.Peers.Include(p => p.Communities).FirstOrDefault(p => p.Id == id);
}
PeerInfo? IPeerStore.GetPeerById(string id)
{
using var db = _dbFactory.CreateDbContext();
var peer = db.Peers.Include(p => p.Communities).FirstOrDefault(p => p.Id == id);
return peer is null ? null : MapToInfo(peer);
}
public PeerInfo? GetPeerByIp(string ip)
{
using var db = _dbFactory.CreateDbContext();
var peer = db.Peers.Include(p => p.Communities).FirstOrDefault(p => p.Ip == ip);
return peer is null ? null : MapToInfo(peer);
}
public void SetDescription(string id, string description)
{
using var db = _dbFactory.CreateDbContext();
db.Peers.Where(p => p.Id == id).ExecuteUpdate(
s => s.SetProperty(p => p.Description, description));
}
public HashSet<uint> GetCommunities(string peerId)
{
using var db = _dbFactory.CreateDbContext();
return db.Peers.Include(p => p.Communities)
.Where(p => p.Id == peerId)
.SelectMany(p => p.Communities)
.Select(c => (uint)c.Community)
.ToHashSet();
}
public HashSet<uint> GetCommunitiesByIp(string ip)
{
using var db = _dbFactory.CreateDbContext();
return db.Peers.Include(p => p.Communities)
.Where(p => p.Ip == ip)
.SelectMany(p => p.Communities)
.Select(c => (uint)c.Community)
.ToHashSet();
}
public void SetCommunities(string peerId, HashSet<uint> communities)
{
using var db = _dbFactory.CreateDbContext();
db.Set<PeerCommunity>().Where(c => c.PeerId == peerId).ExecuteDelete();
db.Set<PeerCommunity>().AddRange(
communities.Select(c => new PeerCommunity { PeerId = peerId, Community = c }));
db.SaveChanges();
}
public void ClearCommunities(string peerId)
{
using var db = _dbFactory.CreateDbContext();
db.Set<PeerCommunity>().Where(c => c.PeerId == peerId).ExecuteDelete();
}
public List<string> GetSubscriptions(string peerId)
{
using var db = _dbFactory.CreateDbContext();
return db.Set<PeerSubscription>()
.Where(s => s.PeerId == peerId)
.Select(s => s.AsnListName)
.ToList();
}
public void SetSubscriptions(string peerId, List<string> asnListNames)
{
using var db = _dbFactory.CreateDbContext();
db.Set<PeerSubscription>().Where(s => s.PeerId == peerId).ExecuteDelete();
db.Set<PeerSubscription>().AddRange(
asnListNames.Select(n => new PeerSubscription { PeerId = peerId, AsnListName = n }));
db.SaveChanges();
}
public List<string> GetCustomPrefixes(string peerId)
{
using var db = _dbFactory.CreateDbContext();
return db.Set<PeerCustomPrefix>()
.Where(c => c.PeerId == peerId)
.Select(c => c.Prefix + "/" + c.PrefixLength)
.ToList();
}
public void SetCustomPrefixes(string peerId, List<(string Prefix, byte Length)> prefixes)
{
using var db = _dbFactory.CreateDbContext();
db.Set<PeerCustomPrefix>().Where(c => c.PeerId == peerId).ExecuteDelete();
db.Set<PeerCustomPrefix>().AddRange(
prefixes.Select(p => new PeerCustomPrefix { PeerId = peerId, Prefix = p.Prefix, PrefixLength = p.Length }));
db.SaveChanges();
}
public List<uint> GetCustomAsns(string peerId)
{
using var db = _dbFactory.CreateDbContext();
return db.Set<PeerCustomAsn>()
.Where(c => c.PeerId == peerId)
.Select(c => c.Asn)
.ToList();
}
public void SetCustomAsns(string peerId, List<uint> asns)
{
using var db = _dbFactory.CreateDbContext();
db.Set<PeerCustomAsn>().Where(c => c.PeerId == peerId).ExecuteDelete();
db.Set<PeerCustomAsn>().AddRange(
asns.Select(a => new PeerCustomAsn { PeerId = peerId, Asn = a }));
db.SaveChanges();
}
private static PeerInfo MapToInfo(Peer peer) => new()
{
Id = peer.Id,
Ip = peer.Ip,
Asn = peer.Asn,
Description = peer.Description,
Status = peer.Status,
CreatedAt = peer.CreatedAt.ToString("O"),
LastSessionAt = peer.LastSessionAt?.ToString("O")
};
}