diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj
index a3759a3..b0ff00a 100644
--- a/MareSynchronos/MareSynchronos.csproj
+++ b/MareSynchronos/MareSynchronos.csproj
@@ -3,7 +3,7 @@
UmbraSync
UmbraSync
- 0.1.2.0
+ 0.1.4.1
diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs
index 12761b5..d357122 100644
--- a/MareSynchronos/Plugin.cs
+++ b/MareSynchronos/Plugin.cs
@@ -100,6 +100,7 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton();
collection.AddSingleton();
collection.AddSingleton();
+ collection.AddSingleton();
collection.AddSingleton();
collection.AddSingleton();
collection.AddSingleton();
diff --git a/MareSynchronos/Services/AutoDetect/AutoDetectRequestService.cs b/MareSynchronos/Services/AutoDetect/AutoDetectRequestService.cs
index cac9879..0ee9e31 100644
--- a/MareSynchronos/Services/AutoDetect/AutoDetectRequestService.cs
+++ b/MareSynchronos/Services/AutoDetect/AutoDetectRequestService.cs
@@ -1,6 +1,9 @@
using Microsoft.Extensions.Logging;
using MareSynchronos.WebAPI.AutoDetect;
using MareSynchronos.MareConfiguration;
+using MareSynchronos.Services;
+using MareSynchronos.Services.Mediator;
+using NotificationType = MareSynchronos.MareConfiguration.Models.NotificationType;
namespace MareSynchronos.Services.AutoDetect;
@@ -10,13 +13,17 @@ public class AutoDetectRequestService
private readonly DiscoveryConfigProvider _configProvider;
private readonly DiscoveryApiClient _client;
private readonly MareConfigService _configService;
+ private readonly DalamudUtilService _dalamud;
+ private readonly MareMediator _mediator;
- public AutoDetectRequestService(ILogger logger, DiscoveryConfigProvider configProvider, DiscoveryApiClient client, MareConfigService configService)
+ public AutoDetectRequestService(ILogger logger, DiscoveryConfigProvider configProvider, DiscoveryApiClient client, MareConfigService configService, MareMediator mediator, DalamudUtilService dalamudUtilService)
{
_logger = logger;
_configProvider = configProvider;
_client = client;
_configService = configService;
+ _mediator = mediator;
+ _dalamud = dalamudUtilService;
}
public async Task SendRequestAsync(string token, CancellationToken ct = default)
@@ -24,14 +31,34 @@ public class AutoDetectRequestService
if (!_configService.Current.AllowAutoDetectPairRequests)
{
_logger.LogDebug("Nearby request blocked: AllowAutoDetectPairRequests is disabled");
+ _mediator.Publish(new NotificationMessage("Nearby request blocked", "Enable 'Allow pair requests' in Settings to send requests.", NotificationType.Info));
return false;
}
var endpoint = _configProvider.RequestEndpoint;
if (string.IsNullOrEmpty(endpoint))
{
_logger.LogDebug("No request endpoint configured");
+ _mediator.Publish(new NotificationMessage("Nearby request failed", "Server does not expose request endpoint.", NotificationType.Error));
return false;
}
- return await _client.SendRequestAsync(endpoint!, token, ct).ConfigureAwait(false);
+ string? displayName = null;
+ try
+ {
+ var me = await _dalamud.RunOnFrameworkThread(() => _dalamud.GetPlayerCharacter()).ConfigureAwait(false);
+ displayName = me?.Name.TextValue;
+ }
+ catch { }
+
+ _logger.LogInformation("Nearby: sending pair request via {endpoint}", endpoint);
+ var ok = await _client.SendRequestAsync(endpoint!, token, displayName, ct).ConfigureAwait(false);
+ if (ok)
+ {
+ _mediator.Publish(new NotificationMessage("Nearby request sent", "The other user will receive a request notification.", NotificationType.Info));
+ }
+ else
+ {
+ _mediator.Publish(new NotificationMessage("Nearby request failed", "The server rejected the request. Try again soon.", NotificationType.Warning));
+ }
+ return ok;
}
}
diff --git a/MareSynchronos/Services/AutoDetect/DiscoveryConfigProvider.cs b/MareSynchronos/Services/AutoDetect/DiscoveryConfigProvider.cs
index 8e9fbd2..248aefc 100644
--- a/MareSynchronos/Services/AutoDetect/DiscoveryConfigProvider.cs
+++ b/MareSynchronos/Services/AutoDetect/DiscoveryConfigProvider.cs
@@ -50,7 +50,7 @@ public class DiscoveryConfigProvider
root.NearbyDiscovery?.Hydrate();
_config = root;
_lastLoad = DateTimeOffset.UtcNow;
- _logger.LogDebug("Loaded Nearby well-known (stapled), enabled={enabled}", NearbyEnabled);
+ _logger.LogInformation("Loaded Nearby well-known (stapled), enabled={enabled}, expires={exp}", NearbyEnabled, _config?.NearbyDiscovery?.SaltExpiresAt);
return true;
}
catch (Exception ex)
diff --git a/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs b/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs
index 1a35a1d..06a644b 100644
--- a/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs
+++ b/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs
@@ -25,6 +25,9 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
private bool _loggedLocalOnly;
private int _lastLocalCount = -1;
private int _lastMatchCount = -1;
+ private bool _loggedConfigReady;
+ private string? _lastSnapshotSig;
+ private volatile bool _isConnected;
public NearbyDiscoveryService(ILogger logger, MareMediator mediator,
MareConfigService config, DiscoveryConfigProvider configProvider, DalamudUtilService dalamudUtilService,
@@ -44,7 +47,8 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
public Task StartAsync(CancellationToken cancellationToken)
{
_loopCts = new CancellationTokenSource();
- _mediator.Subscribe(this, _ => _configProvider.TryLoadFromStapled());
+ _mediator.Subscribe(this, _ => { _isConnected = true; _configProvider.TryLoadFromStapled(); });
+ _mediator.Subscribe(this, _ => { _isConnected = false; _lastPublishedSignature = null; });
_ = Task.Run(() => Loop(_loopCts.Token));
return Task.CompletedTask;
}
@@ -65,7 +69,7 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
{
try
{
- if (!_config.Current.EnableAutoDetectDiscovery || !_dalamud.IsLoggedIn)
+ if (!_config.Current.EnableAutoDetectDiscovery || !_dalamud.IsLoggedIn || !_isConnected)
{
await Task.Delay(1000, ct).ConfigureAwait(false);
continue;
@@ -79,6 +83,11 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
await _configProvider.TryFetchFromServerAsync(ct).ConfigureAwait(false);
}
}
+ else if (!_loggedConfigReady && _configProvider.NearbyEnabled)
+ {
+ _loggedConfigReady = true;
+ _logger.LogInformation("Nearby: well-known loaded and enabled; refresh={refresh}s, expires={exp}", _configProvider.RefreshSec, _configProvider.SaltExpiresAt);
+ }
var entries = await GetLocalNearbyAsync().ConfigureAwait(false);
// Log when local count changes (including 0) to indicate activity
@@ -95,7 +104,7 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
try
{
var saltHex = Convert.ToHexString(_configProvider.Salt!);
- // map hash->index for result matching and reuse for publish
+ // map hash->index for result matching
Dictionary hashToIndex = new(StringComparer.Ordinal);
List hashes = new(entries.Count);
foreach (var (entry, idx) in entries.Select((e, i) => (e, i)))
@@ -105,35 +114,63 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
hashes.Add(h);
}
- // Publish local snapshot if endpoint is available (deduplicated)
+ // Debug snapshot once per change
+ try
+ {
+ var snapSig = string.Join(',', hashes.OrderBy(s => s, StringComparer.Ordinal)).GetHash256();
+ if (!string.Equals(snapSig, _lastSnapshotSig, StringComparison.Ordinal))
+ {
+ _lastSnapshotSig = snapSig;
+ var sample = entries.Take(5).Select(e =>
+ {
+ var hh = (saltHex + e.Name + e.WorldId.ToString()).GetHash256();
+ var shortH = hh.Length > 8 ? hh[..8] : hh;
+ return $"{e.Name}({e.WorldId})->{shortH}";
+ });
+ var saltShort = saltHex.Length > 8 ? saltHex[..8] : saltHex;
+ _logger.LogInformation("Nearby snapshot: {count} entries; salt={saltShort}…; samples=[{samples}]",
+ entries.Count, saltShort, string.Join(", ", sample));
+ }
+ }
+ catch { }
+
+ // Publish OUR presence (own hash) if endpoint is available (deduplicated)
if (!string.IsNullOrEmpty(_configProvider.PublishEndpoint))
{
string? displayName = null;
+ string? selfHash = null;
try
{
var me = await _dalamud.RunOnFrameworkThread(() => _dalamud.GetPlayerCharacter()).ConfigureAwait(false);
if (me != null)
{
displayName = me.Name.TextValue;
+ ushort meWorld = 0;
+ if (me is Dalamud.Game.ClientState.Objects.SubKinds.IPlayerCharacter mePc)
+ meWorld = (ushort)mePc.HomeWorld.RowId;
+ _logger.LogInformation("Nearby self ident: {name} ({world})", displayName, meWorld);
+ selfHash = (saltHex + displayName + meWorld.ToString()).GetHash256();
}
}
catch { /* ignore */ }
- if (hashes.Count > 0)
+ if (!string.IsNullOrEmpty(selfHash))
{
- var sig = string.Join(',', hashes.OrderBy(s => s, StringComparer.Ordinal)).GetHash256();
+ var sig = selfHash!;
if (!string.Equals(sig, _lastPublishedSignature, StringComparison.Ordinal))
{
_lastPublishedSignature = sig;
- _logger.LogDebug("Nearby publish: {count} hashes (updated)", hashes.Count);
- _ = _api.PublishAsync(_configProvider.PublishEndpoint!, hashes, displayName, ct);
+ var shortSelf = selfHash!.Length > 8 ? selfHash[..8] : selfHash;
+ _logger.LogInformation("Nearby publish: self presence updated (hash={hash})", shortSelf);
+ var ok = await _api.PublishAsync(_configProvider.PublishEndpoint!, new[] { selfHash! }, displayName, ct).ConfigureAwait(false);
+ _logger.LogInformation("Nearby publish result: {result}", ok ? "success" : "failed");
}
else
{
_logger.LogDebug("Nearby publish skipped (no changes)");
}
}
- // else: no local entries; skip publish silently
+ // else: no self character available; skip publish silently
}
// Query for matches if endpoint is available
@@ -160,6 +197,7 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
}
}
}
+ _logger.LogInformation("Nearby: server returned {count} matches", allMatches.Count);
// Log change in number of Umbra matches
int matchCount = entries.Count(e => e.IsMatch);
@@ -206,7 +244,8 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
var localPos = local?.Position ?? Vector3.Zero;
int maxDist = Math.Clamp(_config.Current.AutoDetectMaxDistanceMeters, 5, 100);
- for (int i = 0; i < 200; i += 2)
+ int limit = Math.Min(200, _objectTable.Length);
+ for (int i = 0; i < limit; i++)
{
var obj = await _dalamud.RunOnFrameworkThread(() => _objectTable[i]).ConfigureAwait(false);
if (obj == null || obj.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue;
@@ -215,7 +254,7 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
float dist = local == null ? float.NaN : Vector3.Distance(localPos, obj.Position);
if (!float.IsNaN(dist) && dist > maxDist) continue;
- string name = obj.Name.ToString();
+ string name = obj.Name.TextValue;
ushort worldId = 0;
if (obj is Dalamud.Game.ClientState.Objects.SubKinds.IPlayerCharacter pc)
worldId = (ushort)pc.HomeWorld.RowId;
diff --git a/MareSynchronos/Services/AutoDetect/NearbyPendingService.cs b/MareSynchronos/Services/AutoDetect/NearbyPendingService.cs
new file mode 100644
index 0000000..ddc3855
--- /dev/null
+++ b/MareSynchronos/Services/AutoDetect/NearbyPendingService.cs
@@ -0,0 +1,70 @@
+using System.Collections.Concurrent;
+using System.Text.RegularExpressions;
+using MareSynchronos.Services.Mediator;
+using MareSynchronos.WebAPI;
+using Microsoft.Extensions.Logging;
+
+namespace MareSynchronos.Services.AutoDetect;
+
+public sealed class NearbyPendingService : IMediatorSubscriber
+{
+ private readonly ILogger _logger;
+ private readonly MareMediator _mediator;
+ private readonly ApiController _api;
+ private readonly ConcurrentDictionary _pending = new(StringComparer.Ordinal);
+ private static readonly Regex ReqRegex = new(@"^Nearby Request: (.+) \[(?[A-Z0-9]+)\]$", RegexOptions.Compiled);
+
+ public NearbyPendingService(ILogger logger, MareMediator mediator, ApiController api)
+ {
+ _logger = logger;
+ _mediator = mediator;
+ _api = api;
+ _mediator.Subscribe(this, OnNotification);
+ }
+
+ public MareMediator Mediator => _mediator;
+
+ public IReadOnlyDictionary Pending => _pending;
+
+ private void OnNotification(NotificationMessage msg)
+ {
+ // Watch info messages for Nearby request pattern
+ if (msg.Type != MareSynchronos.MareConfiguration.Models.NotificationType.Info) return;
+ var m = ReqRegex.Match(msg.Message);
+ if (!m.Success) return;
+ var uid = m.Groups["uid"].Value;
+ if (string.IsNullOrEmpty(uid)) return;
+ // Try to extract name as everything before space and '['
+ var name = msg.Message;
+ try
+ {
+ var idx = msg.Message.IndexOf(':');
+ if (idx >= 0) name = msg.Message[(idx + 1)..].Trim();
+ var br = name.LastIndexOf('[');
+ if (br > 0) name = name[..br].Trim();
+ }
+ catch { name = uid; }
+ _pending[uid] = name;
+ _logger.LogInformation("NearbyPending: received request from {uid} ({name})", uid, name);
+ }
+
+ public void Remove(string uid)
+ {
+ _pending.TryRemove(uid, out _);
+ }
+
+ public async Task AcceptAsync(string uid)
+ {
+ try
+ {
+ await _api.UserAddPair(new MareSynchronos.API.Dto.User.UserDto(new MareSynchronos.API.Data.UserData(uid))).ConfigureAwait(false);
+ _pending.TryRemove(uid, out _);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "NearbyPending: accept failed for {uid}", uid);
+ return false;
+ }
+ }
+}
diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs
index fada6b0..69f724c 100644
--- a/MareSynchronos/UI/CompactUI.cs
+++ b/MareSynchronos/UI/CompactUI.cs
@@ -44,6 +44,7 @@ public class CompactUi : WindowMediatorSubscriberBase
private readonly ServerConfigurationManager _serverManager;
private readonly Stopwatch _timeout = new();
private readonly CharaDataManager _charaDataManager;
+ private readonly Services.AutoDetect.NearbyPendingService _nearbyPending;
private readonly UidDisplayHandler _uidDisplayHandler;
private readonly UiSharedService _uiSharedService;
private bool _buttonState;
@@ -62,6 +63,7 @@ public class CompactUi : WindowMediatorSubscriberBase
public CompactUi(ILogger logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService,
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager,
+ Services.AutoDetect.NearbyPendingService nearbyPendingService,
PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "###UmbraSyncMainUI", performanceCollectorService)
{
@@ -73,6 +75,7 @@ public class CompactUi : WindowMediatorSubscriberBase
_fileTransferManager = fileTransferManager;
_uidDisplayHandler = uidDisplayHandler;
_charaDataManager = charaDataManager;
+ _nearbyPending = nearbyPendingService;
var tagHandler = new TagHandler(_serverManager);
_groupPanel = new(this, uiShared, _pairManager, chatService, uidDisplayHandler, _configService, _serverManager, _charaDataManager);
@@ -180,14 +183,6 @@ public class CompactUi : WindowMediatorSubscriberBase
}
ImGui.Separator();
using (ImRaii.PushId("transfers")) DrawTransfers();
- using (ImRaii.PushId("autosync"))
- {
- ImGui.SameLine();
- if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserPlus, "Nearby", (WindowContentWidth - ImGui.GetStyle().ItemSpacing.X) / 2))
- {
- Mediator.Publish(new UiToggleMessage(typeof(AutoDetectUi)));
- }
- }
TransferPartHeight = ImGui.GetCursorPosY() - TransferPartHeight;
using (ImRaii.PushId("group-user-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs);
using (ImRaii.PushId("grouping-popup")) _selectGroupForPairUi.Draw();
@@ -396,6 +391,16 @@ public class CompactUi : WindowMediatorSubscriberBase
: $"Nearby ({nearbyCount} Players)");
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) _nearbyOpen = !_nearbyOpen;
+ // Header action button to open Nearby window
+ var btnWidth = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.UserPlus, "Nearby");
+ var headerRight = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
+ ImGui.SameLine();
+ ImGui.SetCursorPosX(headerRight - btnWidth);
+ if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserPlus, "Nearby", btnWidth))
+ {
+ Mediator.Publish(new UiToggleMessage(typeof(AutoDetectUi)));
+ }
+
if (_nearbyOpen)
{
ImGui.Indent();
@@ -407,6 +412,34 @@ public class CompactUi : WindowMediatorSubscriberBase
{
UiSharedService.ColorTextWrapped("Open Nearby for details.", ImGuiColors.DalamudGrey3);
}
+ // Pending Nearby requests (Accept / Dismiss)
+ try
+ {
+ var inbox = _nearbyPending;
+ if (inbox != null && inbox.Pending.Count > 0)
+ {
+ ImGuiHelpers.ScaledDummy(6);
+ _uiSharedService.BigText("Requests");
+ foreach (var kv in inbox.Pending)
+ {
+ ImGui.AlignTextToFramePadding();
+ ImGui.TextUnformatted($"{kv.Value} [{kv.Key}]");
+ ImGui.SameLine();
+ if (_uiSharedService.IconButton(FontAwesomeIcon.Check))
+ {
+ _ = inbox.AcceptAsync(kv.Key);
+ }
+ UiSharedService.AttachToolTip("Accept and add as pair");
+ ImGui.SameLine();
+ if (_uiSharedService.IconButton(FontAwesomeIcon.Times))
+ {
+ inbox.Remove(kv.Key);
+ }
+ UiSharedService.AttachToolTip("Dismiss request");
+ }
+ }
+ }
+ catch { }
ImGui.Unindent();
ImGui.Separator();
}
@@ -530,21 +563,20 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.TextUnformatted(downloadText);
}
- var bottomButtonWidth = (WindowContentWidth - ImGui.GetStyle().ItemSpacing.X) / 2;
-
+ // Space for three equal-width buttons laid out precisely (avoid overlap/wrap)
+ var spacing = ImGui.GetStyle().ItemSpacing.X;
+ var bottomButtonWidth = (WindowContentWidth - spacing) / 2f;
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis", bottomButtonWidth))
{
Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
}
ImGui.SameLine();
-
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Running, "Character Data Hub", bottomButtonWidth))
{
Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi)));
}
-
- ImGui.SameLine();
+ ImGuiHelpers.ScaledDummy(2);
}
private void DrawUIDHeader()
diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs
index 36fdf14..11d3787 100644
--- a/MareSynchronos/UI/SettingsUi.cs
+++ b/MareSynchronos/UI/SettingsUi.cs
@@ -212,7 +212,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
ImGui.Separator();
- _uiShared.BigText("Nearby");
+ _uiShared.BigText("AutoDetect");
bool enableDiscovery = _configService.Current.EnableAutoDetectDiscovery;
if (ImGui.Checkbox("Enable Nearby detection (beta)", ref enableDiscovery))
{
diff --git a/MareSynchronos/UmbraSync.json b/MareSynchronos/UmbraSync.json
index 70ef498..da34e8d 100644
--- a/MareSynchronos/UmbraSync.json
+++ b/MareSynchronos/UmbraSync.json
@@ -8,7 +8,7 @@
"Tags": [
"customization"
],
- "IconUrl": "https://repo.umbra-sync.net/logo.png",
+ "IconUrl": "https://repo.umbra-sync.net/images/logo.png",
"RepoUrl": "https://repo.umbra-sync.net/plugin.json",
"CanUnloadAsync": true
}
diff --git a/MareSynchronos/WebAPI/AutoDetect/DiscoveryApiClient.cs b/MareSynchronos/WebAPI/AutoDetect/DiscoveryApiClient.cs
index 842a154..dd24560 100644
--- a/MareSynchronos/WebAPI/AutoDetect/DiscoveryApiClient.cs
+++ b/MareSynchronos/WebAPI/AutoDetect/DiscoveryApiClient.cs
@@ -11,6 +11,7 @@ public class DiscoveryApiClient
private readonly ILogger _logger;
private readonly TokenProvider _tokenProvider;
private readonly HttpClient _httpClient = new();
+ private static readonly JsonSerializerOptions JsonOpt = new() { PropertyNameCaseInsensitive = true };
public DiscoveryApiClient(ILogger logger, TokenProvider tokenProvider)
{
@@ -32,7 +33,7 @@ public class DiscoveryApiClient
var resp = await _httpClient.SendAsync(req, ct).ConfigureAwait(false);
resp.EnsureSuccessStatusCode();
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
- var result = JsonSerializer.Deserialize>(json) ?? [];
+ var result = JsonSerializer.Deserialize>(json, JsonOpt) ?? [];
return result;
}
catch (Exception ex)
@@ -42,7 +43,7 @@ public class DiscoveryApiClient
}
}
- public async Task SendRequestAsync(string endpoint, string token, CancellationToken ct)
+ public async Task SendRequestAsync(string endpoint, string token, string? displayName, CancellationToken ct)
{
try
{
@@ -50,10 +51,17 @@ public class DiscoveryApiClient
if (string.IsNullOrEmpty(jwt)) return false;
using var req = new HttpRequestMessage(HttpMethod.Post, endpoint);
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
- var body = JsonSerializer.Serialize(new { token });
+ var body = JsonSerializer.Serialize(new { token, displayName });
req.Content = new StringContent(body, Encoding.UTF8, "application/json");
var resp = await _httpClient.SendAsync(req, ct).ConfigureAwait(false);
- return resp.IsSuccessStatusCode;
+ if (!resp.IsSuccessStatusCode)
+ {
+ string txt = string.Empty;
+ try { txt = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false); } catch { }
+ _logger.LogWarning("Discovery request failed: {code} {reason} {body}", (int)resp.StatusCode, resp.ReasonPhrase, txt);
+ return false;
+ }
+ return true;
}
catch (Exception ex)
{