Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/Microsoft.Teams.Apps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,7 @@ from host startup; normal shutdown does not raise a disconnect event.
These events are experimental and observational. Handlers run synchronously, may run concurrently across
geos, and should be short and thread-safe. Observer failures are logged without interrupting delivery or
other observers. `SocketMode` is null when Socket Mode is disabled. Read-only diagnostics are available through
`SocketMode.Status` (aggregate), `SocketMode.GeoStatuses` (a per-geo snapshot), `SocketMode.GeoList`, and
`SocketMode.NegotiateUrl` (the resolved endpoint for the first geo).
`SocketMode.Status` (aggregate), `SocketMode.GeoStatuses` (a per-geo snapshot), and `SocketMode.GeoList`.
Negotiation failures expose `SocketModeNegotiateException.StatusCode`, `.RetryAfter` (a nullable `TimeSpan`),
and `.IsAuthError` for HTTP 401/403. Downstream SignalR negotiation errors are not classified as terminal
service-negotiation rejections.
Expand Down
7 changes: 0 additions & 7 deletions src/Microsoft.Teams.Apps/SocketMode/SocketModeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,4 @@ internal SocketModeObserver(Func<SocketModeTransport> getTransport, SocketModeEv

/// <summary>Gets the resolved geo identifiers the transport connects to.</summary>
public IReadOnlyList<string> GeoList => _transport.Value.GeoList;

/// <summary>
/// Gets the resolved negotiation endpoint for the first configured geo, for diagnostics.
/// Each geo connects to its own endpoint.
/// </summary>
/// <remarks>This URL is managed by the SDK and is for diagnostics only. Do not depend on it; it may change in the future.</remarks>
public Uri NegotiateUrl => _transport.Value.NegotiateUrl;
}
1 change: 1 addition & 0 deletions src/Microsoft.Teams.Apps/SocketMode/SocketModeOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public sealed class SocketModeOptions
/// Gets or sets the geos to connect, one connection each.
/// Defaults to <c>amer</c>, <c>emea</c>, and <c>apac</c>, including when the list is empty.
/// Override this to connect to a different set of geos.
/// Entries must be non-empty and unique, ignoring case.
/// </summary>
public IReadOnlyList<string> Geos { get; set; } = SocketModeProtocol.DefaultGeos;

Expand Down
5 changes: 1 addition & 4 deletions src/Microsoft.Teams.Apps/SocketMode/SocketModeTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,6 @@ internal IReadOnlyDictionary<string, SocketModeStatus> GeoStatuses
/// <summary>Gets a snapshot of the resolved geo identifiers.</summary>
internal IReadOnlyList<string> GeoList => Array.AsReadOnly(_geos.Select(geo => geo.Geo).ToArray());

/// <summary>Gets the resolved negotiation endpoint for the first geo.</summary>
internal Uri NegotiateUrl => _geos[0].NegotiateUri;

/// <inheritdoc />
TimeSpan IGeoSocketOwner.StartupTimeout => _options.StartupTimeout;

Expand Down Expand Up @@ -513,7 +510,7 @@ private static bool IsInvoke(SocketActivityEnvelope envelope, CoreActivity activ
throw new ArgumentException("Socket Mode geos must not contain an empty string.", nameof(geos));
}

if (new HashSet<string>(geos, StringComparer.Ordinal).Count != geos.Count)
if (new HashSet<string>(geos, StringComparer.OrdinalIgnoreCase).Count != geos.Count)
{
throw new ArgumentException("Socket Mode geos must not contain duplicates.", nameof(geos));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ public async Task HostedService_StartsEveryGeoDispatchesToTheAppAndStops()
SocketModeTransport transport = provider.GetRequiredService<SocketModeTransport>();
Assert.Equal(SocketModeStatus.Idle, socket.Status);
Assert.Equal(["amer", "emea"], socket.GeoList);
Assert.Equal(new Uri("https://amer.botapi.skype.com/v3/websockets/connect"), socket.NegotiateUrl);
Assert.Empty(socket.GeoStatuses);

await hosted.StartAsync(CancellationToken.None);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public async Task Diagnostics_AreLazyAndDoNotConnect()
observer.Events.Ready += (_, _) => { };
Assert.Equal(0, created);
Assert.Equal(SocketModeStatus.Idle, observer.Status);
Assert.Equal(new Uri("https://emea.botapi.skype.com/v3/websockets/connect"), observer.NegotiateUrl);
Assert.Equal(["emea"], observer.GeoList);
Assert.Empty(observer.GeoStatuses);
Assert.Equal(1, created);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public async Task StartAsync_ConnectsEveryDefaultGeo(bool emptyGeos)
[Theory]
[InlineData(new object[] { new[] { "emea" } })]
[InlineData(new object[] { new[] { "custom-geo", "other-geo" } })]
[InlineData(new object[] { new[] { "amer", "AMER" } })]
[InlineData(new object[] { new[] { "AMER" } })]
[InlineData(new object[] { new[] { "amer.amer" } })]
public async Task StartAsync_ConnectsConfiguredGeos(string[] geos)
{
Expand All @@ -76,6 +76,7 @@ public async Task StartAsync_ConnectsConfiguredGeos(string[] geos)
[InlineData(new object[] { new[] { "" } })]
[InlineData(new object[] { new[] { "amer", "" } })]
[InlineData(new object[] { new[] { "amer", "amer" } })]
[InlineData(new object[] { new[] { "amer", "AMER" } })]
public void Constructor_RejectsInvalidGeos(string[]? geos)
{
Assert.Throws<ArgumentException>(() => new Harness(new SocketModeTransportOptions { Geos = geos! }).Transport);
Expand Down
Loading