22using System . IO . Pipes ;
33using System . Threading ;
44using System . Threading . Tasks ;
5- using Microsoft . Extensions . Configuration ;
65using Microsoft . Extensions . Logging ;
6+ using Microsoft . Extensions . Options ;
77using StreamJsonRpc ;
88using Uno . Extensions ;
99using Uno . UI . RemoteControl . Messaging . IdeChannel ;
@@ -17,22 +17,21 @@ namespace Uno.UI.RemoteControl.Host.IdeChannel;
1717internal class IdeChannelServer : IIdeChannel , IDisposable
1818{
1919 private readonly ILogger _logger ;
20- private readonly IConfiguration _configuration ;
20+ private readonly IDisposable ? _configSubscription ;
2121
22- private readonly Task < bool > _initializeTask ;
22+ private Task < bool > _initializeTask ;
2323 private NamedPipeServerStream ? _pipeServer ;
2424 private JsonRpc ? _rpcServer ;
2525 private Proxy ? _proxy ;
2626
27- public IdeChannelServer ( ILogger < IdeChannelServer > logger , IConfiguration configuration )
27+ public IdeChannelServer ( ILogger < IdeChannelServer > logger , IOptionsMonitor < IdeChannelServerOptions > config )
2828 {
2929 _logger = logger ;
30- _configuration = configuration ;
3130
32- _initializeTask = Task . Run ( InitializeServer ) ;
31+ _initializeTask = Task . Run ( ( ) => InitializeServer ( config . CurrentValue . ChannelId ) ) ;
32+ _configSubscription = config . OnChange ( opts => _initializeTask = InitializeServer ( opts . ChannelId ) ) ;
3333 }
3434
35-
3635 #region IIdeChannel
3736
3837 /// <inheritdoc />
@@ -65,33 +64,63 @@ public async ValueTask<bool> WaitForReady(CancellationToken ct = default)
6564 /// <summary>
6665 /// Initialize as dev-server (cf. IdeChannelClient for init as IDE)
6766 /// </summary>
68- private async Task < bool > InitializeServer ( )
67+ private async Task < bool > InitializeServer ( Guid channelId )
6968 {
70- if ( ! Guid . TryParse ( _configuration [ "ideChannel" ] , out var ideChannel ) )
69+ try
7170 {
72- _logger . LogDebug ( "No IDE Channel ID specified, skipping." ) ;
73- return false ;
71+ // First we remove the proxy to prevent messages being sent while we are re-initializing
72+ _proxy = null ;
73+
74+ // Dispose any existing server
75+ _rpcServer ? . Dispose ( ) ;
76+ if ( _pipeServer is { } server )
77+ {
78+ server . Disconnect ( ) ;
79+ await server . DisposeAsync ( ) ;
80+ }
81+ }
82+ catch ( Exception error )
83+ {
84+ _logger . LogWarning ( error , "An error occurred while disposing the existing IDE channel server. Continuing initialization." ) ;
7485 }
86+
87+ try
88+ {
89+ if ( channelId == Guid . Empty )
90+ {
91+ return false ;
92+ }
7593
76- _pipeServer = new NamedPipeServerStream (
77- pipeName : ideChannel . ToString ( ) ,
78- direction : PipeDirection . InOut ,
79- maxNumberOfServerInstances : 1 ,
80- transmissionMode : PipeTransmissionMode . Byte ,
81- options : PipeOptions . Asynchronous | PipeOptions . WriteThrough ) ;
94+ _pipeServer = new NamedPipeServerStream (
95+ pipeName : channelId . ToString ( ) ,
96+ direction : PipeDirection . InOut ,
97+ maxNumberOfServerInstances : 1 ,
98+ transmissionMode : PipeTransmissionMode . Byte ,
99+ options : PipeOptions . Asynchronous | PipeOptions . WriteThrough ) ;
82100
83- await _pipeServer . WaitForConnectionAsync ( ) ;
101+ await _pipeServer . WaitForConnectionAsync ( ) ;
84102
85- if ( _logger . IsEnabled ( LogLevel . Debug ) )
86- {
87- _logger . LogDebug ( "IDE Connected" ) ;
88- }
103+ _proxy = new ( this ) ;
104+ _rpcServer = JsonRpc . Attach ( _pipeServer , _proxy ) ;
89105
90- _proxy = new ( this ) ;
91- _rpcServer = JsonRpc . Attach ( _pipeServer , _proxy ) ;
106+ if ( _logger . IsEnabled ( LogLevel . Debug ) )
107+ {
108+ _logger . LogDebug ( "IDE channel successfully initialized." ) ;
109+ }
92110
93- _ = StartKeepAliveAsync ( ) ;
94- return true ;
111+ _ = StartKeepAliveAsync ( ) ;
112+
113+ return true ;
114+ }
115+ catch ( Exception error )
116+ {
117+ if ( _logger . IsEnabled ( LogLevel . Error ) )
118+ {
119+ _logger . LogError ( error , "Failed to init the IDE channel." ) ;
120+ }
121+
122+ return false ;
123+ }
95124 }
96125
97126 private async Task StartKeepAliveAsync ( )
@@ -108,6 +137,7 @@ private async Task StartKeepAliveAsync()
108137 /// <inheritdoc />
109138 public void Dispose ( )
110139 {
140+ _configSubscription ? . Dispose ( ) ;
111141 _rpcServer ? . Dispose ( ) ;
112142 _pipeServer ? . Dispose ( ) ;
113143 }
0 commit comments