Skip to content

Commit dc909b3

Browse files
Copilotnixel2007
andcommitted
Fix debug adapter reconnection in attach mode
- Modified DefaultDebugService.Disconnect to not throw StopServiceException when terminate=false - Updated DelayedConnectionChannel to support reconnection by keeping listener alive - Modified DefaultMessageServer to continue on IOException/ObjectDisposedException instead of stopping - Added thread-safe reconnection logic with proper state reset Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com>
1 parent 9f47c0f commit dc909b3

4 files changed

Lines changed: 117 additions & 27 deletions

File tree

opm.ospx

-402 KB
Binary file not shown.

src/OneScript.DebugProtocol/TcpServer/DefaultMessageServer.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This Source Code Form is subject to the terms of the
66
----------------------------------------------------------*/
77

88
using System;
9+
using System.IO;
910
using System.Threading;
1011
using OneScript.DebugProtocol.Abstractions;
1112

@@ -83,7 +84,15 @@ private void RunCommandsLoop()
8384
}
8485
catch (ObjectDisposedException)
8586
{
86-
_serverStopped = true;
87+
// Connection closed, but don't stop server - allow reconnection
88+
// The DelayedConnectionChannel will wait for a new connection
89+
continue;
90+
}
91+
catch (IOException)
92+
{
93+
// Connection lost, but don't stop server - allow reconnection
94+
// The DelayedConnectionChannel will wait for a new connection
95+
continue;
8796
}
8897
catch (ThreadInterruptedException)
8998
{

src/OneScript.DebugServices/DefaultDebugService.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,10 @@ public void Disconnect(bool terminate)
216216
_breakpointManager.Clear();
217217
_threadManager.ReleaseAllThreads();
218218

219-
throw new StopServiceException();
219+
if (terminate)
220+
{
221+
throw new StopServiceException();
222+
}
220223
}
221224

222225
public int[] GetThreads()

src/OneScript.DebugServices/Internal/DelayedConnectionChannel.cs

Lines changed: 103 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace OneScript.DebugServices.Internal
1717
{
1818
internal class DelayedConnectionChannel : ICommunicationChannel
1919
{
20-
private TcpListener _listener;
20+
private readonly TcpListener _listener;
2121
private ICommunicationChannel _connectedChannel;
2222

2323
// NB! должен быть согласован с перечислением TransportProtocols в адаптере
@@ -26,6 +26,7 @@ internal class DelayedConnectionChannel : ICommunicationChannel
2626
private const short SUPPORTED_FORMAT_VERSION = 3;
2727

2828
private bool _reconciled;
29+
private readonly object _lock = new object();
2930

3031
public DelayedConnectionChannel(TcpListener listener)
3132
{
@@ -34,50 +35,127 @@ public DelayedConnectionChannel(TcpListener listener)
3435

3536
public void Dispose()
3637
{
37-
_listener?.Stop();
38-
_listener = null;
39-
_connectedChannel?.Dispose();
38+
lock (_lock)
39+
{
40+
_listener?.Stop();
41+
_connectedChannel?.Dispose();
42+
}
4043
}
4144

4245
public void Write(object data)
4346
{
44-
if(_connectedChannel == null)
45-
throw new InvalidOperationException("No client connected");
46-
47-
_connectedChannel.Write(data);
47+
lock (_lock)
48+
{
49+
if (_connectedChannel == null)
50+
throw new InvalidOperationException("No client connected");
51+
52+
try
53+
{
54+
_connectedChannel.Write(data);
55+
}
56+
catch (IOException)
57+
{
58+
// Connection lost, reset for reconnection
59+
ResetConnection();
60+
throw;
61+
}
62+
catch (ObjectDisposedException)
63+
{
64+
// Connection lost, reset for reconnection
65+
ResetConnection();
66+
throw;
67+
}
68+
}
4869
}
4970

5071
public T Read<T>()
5172
{
5273
ReconcileFormat();
53-
return _connectedChannel.Read<T>();
74+
try
75+
{
76+
return _connectedChannel.Read<T>();
77+
}
78+
catch (IOException)
79+
{
80+
// Connection lost, reset for reconnection
81+
lock (_lock)
82+
{
83+
ResetConnection();
84+
}
85+
throw;
86+
}
87+
catch (ObjectDisposedException)
88+
{
89+
// Connection lost, reset for reconnection
90+
lock (_lock)
91+
{
92+
ResetConnection();
93+
}
94+
throw;
95+
}
5496
}
5597

5698
public object Read()
5799
{
58100
ReconcileFormat();
59-
return _connectedChannel.Read();
101+
try
102+
{
103+
return _connectedChannel.Read();
104+
}
105+
catch (IOException)
106+
{
107+
// Connection lost, reset for reconnection
108+
lock (_lock)
109+
{
110+
ResetConnection();
111+
}
112+
throw;
113+
}
114+
catch (ObjectDisposedException)
115+
{
116+
// Connection lost, reset for reconnection
117+
lock (_lock)
118+
{
119+
ResetConnection();
120+
}
121+
throw;
122+
}
60123
}
61124

62125
private void ReconcileFormat()
63126
{
64-
if (_reconciled)
65-
return;
66-
67-
_listener.Start();
68-
var tcpClient = _listener.AcceptTcpClient();
69-
_listener.Stop();
70-
_listener = null;
71-
72-
var tcpStream = tcpClient.GetStream();
73-
74-
if (FormatReconcileUtils.CheckReconcileRequest(tcpStream))
127+
lock (_lock)
75128
{
76-
// Да, это наш фейковый заголовок
77-
FormatReconcileUtils.WriteReconcileResponse(tcpStream, JSON_FORMAT_MARKER, SUPPORTED_FORMAT_VERSION);
129+
if (_reconciled && _connectedChannel?.Connected == true)
130+
return;
131+
132+
// Reset state if previous connection was lost
133+
if (_reconciled && _connectedChannel?.Connected == false)
134+
{
135+
ResetConnection();
136+
}
137+
138+
_listener.Start();
139+
var tcpClient = _listener.AcceptTcpClient();
140+
_listener.Stop();
141+
142+
var tcpStream = tcpClient.GetStream();
143+
144+
if (FormatReconcileUtils.CheckReconcileRequest(tcpStream))
145+
{
146+
// Да, это наш фейковый заголовок
147+
FormatReconcileUtils.WriteReconcileResponse(tcpStream, JSON_FORMAT_MARKER, SUPPORTED_FORMAT_VERSION);
148+
}
149+
_reconciled = true;
150+
_connectedChannel = new JsonDtoChannel(tcpClient);
78151
}
79-
_reconciled = true;
80-
_connectedChannel = new JsonDtoChannel(tcpClient);
152+
}
153+
154+
private void ResetConnection()
155+
{
156+
_connectedChannel?.Dispose();
157+
_connectedChannel = null;
158+
_reconciled = false;
81159
}
82160

83161
public bool Connected => _connectedChannel?.Connected ?? false;

0 commit comments

Comments
 (0)