Skip to content

Commit 0406c3a

Browse files
authored
Merge branch 'main' into copilot/update-event-handlers-to-concurrent-dictionary
2 parents 067c95a + 6415c40 commit 0406c3a

3 files changed

Lines changed: 33 additions & 77 deletions

File tree

dotnet/src/ActionDisposable.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
namespace GitHub.Copilot.SDK;
6+
7+
/// <summary>
8+
/// A disposable that invokes an action when disposed.
9+
/// </summary>
10+
internal sealed class ActionDisposable : IDisposable
11+
{
12+
private Action? _action;
13+
14+
public ActionDisposable(Action action)
15+
{
16+
_action = action;
17+
}
18+
19+
public void Dispose()
20+
{
21+
var action = Interlocked.Exchange(ref _action, null);
22+
action?.Invoke();
23+
}
24+
}

dotnet/src/Client.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,22 +1561,3 @@ public class ToolResultAIContent(ToolResultObject toolResult) : AIContent
15611561
{
15621562
public ToolResultObject Result => toolResult;
15631563
}
1564-
1565-
/// <summary>
1566-
/// A disposable that invokes an action when disposed.
1567-
/// </summary>
1568-
internal sealed class ActionDisposable : IDisposable
1569-
{
1570-
private Action? _action;
1571-
1572-
public ActionDisposable(Action action)
1573-
{
1574-
_action = action;
1575-
}
1576-
1577-
public void Dispose()
1578-
{
1579-
var action = Interlocked.Exchange(ref _action, null);
1580-
action?.Invoke();
1581-
}
1582-
}

dotnet/src/Session.cs

Lines changed: 9 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,8 @@ public partial class CopilotSession : IAsyncDisposable
4848
private readonly ConcurrentDictionary<SessionEventHandler, bool> _eventHandlers = new();
4949
private readonly Dictionary<string, AIFunction> _toolHandlers = new();
5050
private readonly JsonRpc _rpc;
51-
private PermissionRequestHandler? _permissionHandler;
52-
private readonly SemaphoreSlim _permissionHandlerLock = new(1, 1);
53-
private UserInputHandler? _userInputHandler;
54-
private readonly SemaphoreSlim _userInputHandlerLock = new(1, 1);
51+
private volatile PermissionRequestHandler? _permissionHandler;
52+
private volatile UserInputHandler? _userInputHandler;
5553
private SessionHooks? _hooks;
5654
private readonly SemaphoreSlim _hooksLock = new(1, 1);
5755
private SessionRpc? _sessionRpc;
@@ -247,7 +245,7 @@ void Handler(SessionEvent evt)
247245
public IDisposable On(SessionEventHandler handler)
248246
{
249247
_eventHandlers.TryAdd(handler, true);
250-
return new OnDisposeCall(() => _eventHandlers.TryRemove(handler, out _));
248+
return new ActionDisposable(() => _eventHandlers.TryRemove(handler, out _));
251249
}
252250

253251
/// <summary>
@@ -259,7 +257,7 @@ public IDisposable On(SessionEventHandler handler)
259257
/// </remarks>
260258
internal void DispatchEvent(SessionEvent sessionEvent)
261259
{
262-
foreach (var (handler, _) in _eventHandlers)
260+
foreach (var handler in _eventHandlers.Keys)
263261
{
264262
// We allow handler exceptions to propagate so they are not lost
265263
handler(sessionEvent);
@@ -301,15 +299,7 @@ internal void RegisterTools(ICollection<AIFunction> tools)
301299
/// </remarks>
302300
internal void RegisterPermissionHandler(PermissionRequestHandler handler)
303301
{
304-
_permissionHandlerLock.Wait();
305-
try
306-
{
307-
_permissionHandler = handler;
308-
}
309-
finally
310-
{
311-
_permissionHandlerLock.Release();
312-
}
302+
_permissionHandler = handler;
313303
}
314304

315305
/// <summary>
@@ -319,16 +309,7 @@ internal void RegisterPermissionHandler(PermissionRequestHandler handler)
319309
/// <returns>A task that resolves with the permission decision.</returns>
320310
internal async Task<PermissionRequestResult> HandlePermissionRequestAsync(JsonElement permissionRequestData)
321311
{
322-
await _permissionHandlerLock.WaitAsync();
323-
PermissionRequestHandler? handler;
324-
try
325-
{
326-
handler = _permissionHandler;
327-
}
328-
finally
329-
{
330-
_permissionHandlerLock.Release();
331-
}
312+
var handler = _permissionHandler;
332313

333314
if (handler == null)
334315
{
@@ -355,15 +336,7 @@ internal async Task<PermissionRequestResult> HandlePermissionRequestAsync(JsonEl
355336
/// <param name="handler">The handler to invoke when user input is requested.</param>
356337
internal void RegisterUserInputHandler(UserInputHandler handler)
357338
{
358-
_userInputHandlerLock.Wait();
359-
try
360-
{
361-
_userInputHandler = handler;
362-
}
363-
finally
364-
{
365-
_userInputHandlerLock.Release();
366-
}
339+
_userInputHandler = handler;
367340
}
368341

369342
/// <summary>
@@ -373,16 +346,7 @@ internal void RegisterUserInputHandler(UserInputHandler handler)
373346
/// <returns>A task that resolves with the user's response.</returns>
374347
internal async Task<UserInputResponse> HandleUserInputRequestAsync(UserInputRequest request)
375348
{
376-
await _userInputHandlerLock.WaitAsync();
377-
UserInputHandler? handler;
378-
try
379-
{
380-
handler = _userInputHandler;
381-
}
382-
finally
383-
{
384-
_userInputHandlerLock.Release();
385-
}
349+
var handler = _userInputHandler;
386350

387351
if (handler == null)
388352
{
@@ -590,20 +554,7 @@ await InvokeRpcAsync<object>(
590554
_eventHandlers.Clear();
591555
_toolHandlers.Clear();
592556

593-
await _permissionHandlerLock.WaitAsync();
594-
try
595-
{
596-
_permissionHandler = null;
597-
}
598-
finally
599-
{
600-
_permissionHandlerLock.Release();
601-
}
602-
}
603-
604-
private class OnDisposeCall(Action callback) : IDisposable
605-
{
606-
public void Dispose() => callback();
557+
_permissionHandler = null;
607558
}
608559

609560
internal record SendMessageRequest

0 commit comments

Comments
 (0)