poe2-bot/src/Nexus.Core/LinkManager.cs
2026-03-06 14:37:05 -05:00

147 lines
4.7 KiB
C#

using Serilog;
namespace Nexus.Core;
public class TradeLink
{
public string Id { get; set; } = "";
public string Url { get; set; } = "";
public string Name { get; set; } = "";
public string Label { get; set; } = "";
public bool Active { get; set; } = true;
public LinkMode Mode { get; set; } = LinkMode.Live;
public PostAction PostAction { get; set; } = PostAction.Stash;
public string AddedAt { get; set; } = DateTime.UtcNow.ToString("o");
}
public class LinkManager
{
private readonly Dictionary<string, TradeLink> _links = new();
private readonly ConfigStore _store;
public LinkManager(ConfigStore store)
{
_store = store;
// Pre-populate from saved config so UI shows links before Start()
foreach (var saved in store.Links)
{
var url = StripLive(saved.Url);
var id = ExtractId(url);
_links[id] = new TradeLink
{
Id = id,
Url = url,
Name = saved.Name,
Label = ExtractLabel(url),
Active = saved.Active,
Mode = saved.Mode,
PostAction = saved.PostAction,
AddedAt = saved.AddedAt,
};
}
}
public TradeLink AddLink(string url, string name = "", LinkMode? mode = null, PostAction? postAction = null)
{
url = StripLive(url);
var id = ExtractId(url);
var label = ExtractLabel(url);
var savedLink = _store.Links.FirstOrDefault(l => l.Url == url);
var resolvedMode = mode ?? savedLink?.Mode ?? LinkMode.Live;
var link = new TradeLink
{
Id = id,
Url = url,
Name = name != "" ? name : savedLink?.Name ?? "",
Label = label,
Active = savedLink?.Active ?? true,
Mode = resolvedMode,
PostAction = postAction ?? savedLink?.PostAction ?? (resolvedMode == LinkMode.Scrap ? PostAction.Salvage : PostAction.Stash),
AddedAt = DateTime.UtcNow.ToString("o")
};
_links[id] = link;
_store.AddLink(url, link.Name, link.Mode, link.PostAction);
Log.Information("Trade link added: {Id} {Url} mode={Mode}", id, url, link.Mode);
return link;
}
public void RemoveLink(string id)
{
if (_links.TryGetValue(id, out var link))
{
_links.Remove(id);
_store.RemoveLink(link.Url);
}
else
{
_store.RemoveLinkById(id);
}
Log.Information("Trade link removed: {Id}", id);
}
public TradeLink? ToggleLink(string id, bool active)
{
if (!_links.TryGetValue(id, out var link)) return null;
link.Active = active;
_store.UpdateLinkById(id, l => l.Active = active);
Log.Information("Trade link {Action}: {Id}", active ? "activated" : "deactivated", id);
return link;
}
public void UpdateName(string id, string name)
{
if (!_links.TryGetValue(id, out var link)) return;
link.Name = name;
_store.UpdateLinkById(id, l => l.Name = name);
}
public TradeLink? UpdateMode(string id, LinkMode mode)
{
if (!_links.TryGetValue(id, out var link)) return null;
link.Mode = mode;
_store.UpdateLinkById(id, l => l.Mode = mode);
return link;
}
public TradeLink? UpdatePostAction(string id, PostAction postAction)
{
if (!_links.TryGetValue(id, out var link)) return null;
link.PostAction = postAction;
_store.UpdateLinkById(id, l => l.PostAction = postAction);
return link;
}
public bool IsActive(string id) => _links.TryGetValue(id, out var link) && link.Active;
public List<TradeLink> GetLinks() => _links.Values.ToList();
public TradeLink? GetLink(string id) => _links.GetValueOrDefault(id);
private static string StripLive(string url) =>
System.Text.RegularExpressions.Regex.Replace(url, @"/live/?$", "");
private static string ExtractId(string url)
{
var parts = url.Split('/');
return parts.Length > 0 ? parts[^1] : url;
}
private static string ExtractLabel(string url)
{
try
{
var uri = new Uri(url);
var parts = uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
var poe2Idx = Array.IndexOf(parts, "poe2");
if (poe2Idx >= 0 && parts.Length > poe2Idx + 2)
{
var league = Uri.UnescapeDataString(parts[poe2Idx + 1]);
var searchId = parts[poe2Idx + 2];
return $"{league} / {searchId}";
}
}
catch { /* fallback */ }
return url.Length > 60 ? url[..60] : url;
}
}