Skip to content

Commit 8cf0490

Browse files
committed
Другой алгоритм согласования для старых версий
1 parent 46bee4d commit 8cf0490

10 files changed

Lines changed: 227 additions & 40 deletions

File tree

src/1Script.sln

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OneScript.Web.Server", "One
6767
EndProject
6868
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumenterTests", "Tests\DocumenterTests\DocumenterTests.csproj", "{BD385142-E9B4-43C1-8F88-067F24E5AF6D}"
6969
EndProject
70+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSCode.DebugAdapter.Tests", "Tests\VSCode.DebugAdapter.Tests\VSCode.DebugAdapter.Tests.csproj", "{861F70F4-B10D-4E4E-865C-B8E900391424}"
71+
EndProject
7072
Global
7173
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7274
Debug|Any CPU = Debug|Any CPU
@@ -339,6 +341,18 @@ Global
339341
{BD385142-E9B4-43C1-8F88-067F24E5AF6D}.Release|Any CPU.Build.0 = Release|Any CPU
340342
{BD385142-E9B4-43C1-8F88-067F24E5AF6D}.Release|x86.ActiveCfg = Release|Any CPU
341343
{BD385142-E9B4-43C1-8F88-067F24E5AF6D}.Release|x86.Build.0 = Release|Any CPU
344+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
345+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|Any CPU.Build.0 = Debug|Any CPU
346+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|x86.ActiveCfg = Debug|Any CPU
347+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|x86.Build.0 = Debug|Any CPU
348+
{861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|Any CPU.ActiveCfg = Debug|Any CPU
349+
{861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|Any CPU.Build.0 = Debug|Any CPU
350+
{861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|x86.ActiveCfg = Debug|Any CPU
351+
{861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|x86.Build.0 = Debug|Any CPU
352+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Release|Any CPU.ActiveCfg = Release|Any CPU
353+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Release|Any CPU.Build.0 = Release|Any CPU
354+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Release|x86.ActiveCfg = Release|Any CPU
355+
{861F70F4-B10D-4E4E-865C-B8E900391424}.Release|x86.Build.0 = Release|Any CPU
342356
EndGlobalSection
343357
GlobalSection(SolutionProperties) = preSolution
344358
HideSolutionNode = FALSE
@@ -351,6 +365,7 @@ Global
351365
{0F5E6099-39BA-41CF-B55F-357F7DF4DE00} = {91059C5B-526C-4B81-B106-99DEFF542D1F}
352366
{2F264379-B3B4-44B3-9CBA-A4B0AF3D8785} = {91059C5B-526C-4B81-B106-99DEFF542D1F}
353367
{BD385142-E9B4-43C1-8F88-067F24E5AF6D} = {91059C5B-526C-4B81-B106-99DEFF542D1F}
368+
{861F70F4-B10D-4E4E-865C-B8E900391424} = {91059C5B-526C-4B81-B106-99DEFF542D1F}
354369
EndGlobalSection
355370
GlobalSection(ExtensibilityGlobals) = postSolution
356371
SolutionGuid = {A4A871EF-C5A7-478F-907E-31C69A869973}

src/OneScript.DebugProtocol/OneScript.DebugProtocol.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<Configurations>Debug;Release;LinuxDebug</Configurations>
88
<AssemblyTitle>1Script Debug Protocol common objects and DTO's</AssemblyTitle>
99
<Platforms>AnyCPU</Platforms>
10-
<!--Нацеливание на net461 нужно для сборки дебаг-адаптера под net461 без лишних DLL-->
10+
<!--Нацеливание на net4 нужно для сборки дебаг-адаптера под net4 без лишних DLL-->
1111
<TargetFrameworks>net48;$(TargetFrameworkVersion)</TargetFrameworks>
1212
</PropertyGroup>
1313

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*----------------------------------------------------------
2+
This Source Code Form is subject to the terms of the
3+
Mozilla Public License, v.2.0. If a copy of the MPL
4+
was not distributed with this file, You can obtain one
5+
at http://mozilla.org/MPL/2.0/.
6+
----------------------------------------------------------*/
7+
8+
using System;
9+
using System.IO;
10+
using System.Text;
11+
12+
namespace OneScript.DebugProtocol.TcpServer
13+
{
14+
internal class BinaryFormatWriter : IDisposable
15+
{
16+
private readonly BinaryWriter _writer;
17+
18+
public BinaryFormatWriter(Stream target)
19+
{
20+
_writer = new BinaryWriter(target, Encoding.UTF8, leaveOpen: true);
21+
}
22+
23+
public void WriteHeader(int rootId, int headerId)
24+
{
25+
_writer.Write((byte)0);
26+
_writer.Write(rootId);
27+
_writer.Write(headerId);
28+
_writer.Write(1);
29+
_writer.Write(0);
30+
}
31+
32+
public void WriteStringRecord(int objectId, string data)
33+
{
34+
var bytes = Encoding.UTF8.GetBytes(data);
35+
if (bytes.Length > 127)
36+
throw new ArgumentOutOfRangeException(nameof(data), "Length encoding not supported for strings more than 127 bytes");
37+
38+
_writer.Write((byte)6);
39+
_writer.Write(objectId);
40+
_writer.Write((byte)bytes.Length);
41+
_writer.Write(bytes, 0, bytes.Length);
42+
}
43+
44+
public void WriteEnd()
45+
{
46+
_writer.Write((byte)11);
47+
}
48+
49+
public void Close()
50+
{
51+
Dispose();
52+
}
53+
54+
public void Dispose()
55+
{
56+
_writer.Flush();
57+
_writer.Dispose();
58+
}
59+
}
60+
}

src/OneScript.DebugProtocol/TcpServer/FormatReconcileUtils.cs

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,32 @@ This Source Code Form is subject to the terms of the
55
at http://mozilla.org/MPL/2.0/.
66
----------------------------------------------------------*/
77
using System;
8+
using System.IO;
9+
using System.Text;
810

911
namespace OneScript.DebugProtocol.TcpServer
1012
{
1113
public static class FormatReconcileUtils
1214
{
1315
/// <summary>
14-
/// Массив байт, который вызовет SerializationException при чтении его через BinaryFormatter
15-
/// И при этом оставит поток пустым, для следующего валидного сообщения
16-
/// <see>[MS-NRBF] .NET Remoting: Binary Format Data Structure</see>
16+
/// Специальный пакет, который будет принят двоичным десериализатором старого движка, но который потом
17+
/// упадет на приведении типов.
18+
/// В новом движке он будет принят, как команда для обмена версией формата.
1719
/// </summary>
18-
public static readonly byte[] FORMAT_RECONCILE_MAGIC =
20+
public static byte[] GetReconcileMagic()
1921
{
20-
0x11, // RecordTypeEnum
21-
0,0,0,0, // RootId
22-
0,0,0,0, // HeaderId
23-
0x00, 0x0A, 0x00, 0x0A, // Version Major
24-
0xAA, 0xAA, 0xAA, 0xAA // Version Minor,
25-
};
22+
using (var memoryStream = new MemoryStream(128))
23+
{
24+
using (var writer = new BinaryFormatWriter(memoryStream))
25+
{
26+
writer.WriteHeader(1, 1);
27+
writer.WriteStringRecord(1, "1C1C1C");
28+
writer.WriteEnd();
29+
}
30+
31+
return memoryStream.ToArray();
32+
}
33+
}
2634

2735
/// <summary>
2836
/// Ответ на запрос формата
@@ -48,17 +56,29 @@ public static bool CheckReconcilePrefix(byte[] data)
4856
return true;
4957
}
5058

51-
public static bool CheckReconcileRequest(byte[] data)
59+
public static bool CheckReconcileRequest(Stream stream)
5260
{
53-
for (int i = 0; i < FORMAT_RECONCILE_MAGIC.Length; i++)
61+
var magic = GetReconcileMagic();
62+
var buffer = new byte[magic.Length];
63+
ReadStream(stream, buffer, buffer.Length);
64+
for (int i = 0; i < magic.Length; i++)
5465
{
55-
if (data[i] != FORMAT_RECONCILE_MAGIC[i])
66+
if (buffer[i] != magic[i])
5667
return false;
5768
}
5869

5970
return true;
6071
}
6172

73+
public static void WriteReconcileResponse(Stream target, short transport, short version)
74+
{
75+
var formatInfo = EncodeFormatMarker(transport, version);
76+
77+
using var binaryWriter = new BinaryWriter(target, Encoding.UTF8, true);
78+
binaryWriter.Write(FORMAT_RECONCILE_RESPONSE_PREFIX);
79+
binaryWriter.Write(formatInfo);
80+
}
81+
6282
public static int EncodeFormatMarker(short transport, short dataVersion)
6383
{
6484
var marker = transport << 16;
@@ -72,5 +92,20 @@ public static (int, int) DecodeFormatMarker(int marker)
7292

7393
return (transport, dataVersion);
7494
}
95+
96+
private static void ReadStream(Stream stream, byte[] buffer, int length)
97+
{
98+
int readPosition = 0;
99+
int bytesReceived = 0;
100+
101+
while (bytesReceived < length)
102+
{
103+
bytesReceived = stream.Read(buffer, readPosition, length - bytesReceived);
104+
if (bytesReceived == 0)
105+
throw new IOException("Unexpected end of stream");
106+
107+
readPosition += bytesReceived;
108+
}
109+
}
75110
}
76111
}

src/OneScript.DebugServices/Internal/DelayedConnectionChannel.cs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,37 +69,15 @@ private void ReconcileFormat()
6969
_listener = null;
7070

7171
var tcpStream = tcpClient.GetStream();
72-
73-
var buffer = new byte[FormatReconcileUtils.FORMAT_RECONCILE_MAGIC.Length];
74-
ReadStream(tcpStream, buffer, buffer.Length);
7572

76-
if (FormatReconcileUtils.CheckReconcileRequest(buffer))
73+
if (FormatReconcileUtils.CheckReconcileRequest(tcpStream))
7774
{
7875
// Да, это наш фейковый заголовок
79-
var formatInfo = FormatReconcileUtils.EncodeFormatMarker(JSON_FORMAT_MARKER, SUPPORTED_FORMAT_VERSION);
80-
81-
using var binaryWriter = new BinaryWriter(tcpStream, Encoding.UTF8, true);
82-
binaryWriter.Write(FormatReconcileUtils.FORMAT_RECONCILE_RESPONSE_PREFIX);
83-
binaryWriter.Write(formatInfo);
76+
FormatReconcileUtils.WriteReconcileResponse(tcpStream, JSON_FORMAT_MARKER, SUPPORTED_FORMAT_VERSION);
8477
}
8578
_reconciled = true;
8679
_connectedChannel = new JsonDtoChannel(tcpClient);
8780
}
88-
89-
private void ReadStream(Stream stream, byte[] buffer, int length)
90-
{
91-
int readPosition = 0;
92-
int bytesReceived = 0;
93-
94-
while (bytesReceived < length)
95-
{
96-
bytesReceived = stream.Read(buffer, readPosition, length - bytesReceived);
97-
if (bytesReceived == 0)
98-
throw new IOException("Unexpected end of stream");
99-
100-
readPosition += bytesReceived;
101-
}
102-
}
10381

10482
public bool Connected => _connectedChannel?.Connected ?? false;
10583
}

src/Tests/OneScript.DebugProtocol.Test/OneScript.DebugProtocol.Test.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,8 @@
3232
<ProjectReference Include="..\..\ScriptEngine\ScriptEngine.csproj" />
3333
</ItemGroup>
3434

35+
<ItemGroup>
36+
<Compile Remove="FormatReconcileTest.cs" />
37+
</ItemGroup>
38+
3539
</Project>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
using System;
3+
using System.IO;
4+
using System.Runtime.Serialization.Formatters.Binary;
5+
using FluentAssertions;
6+
using OneScript.DebugProtocol.TcpServer;
7+
using Xunit;
8+
9+
namespace VSCode.DebugAdapter.Tests
10+
{
11+
public class ReconcileForOlderVersionTests
12+
{
13+
[Fact]
14+
public void CanReadReconcileViaBinaryFormatter()
15+
{
16+
using (var stream = new MemoryStream(FormatReconcileUtils.GetReconcileMagic()))
17+
{
18+
var reader = new BinaryFormatter();
19+
var value = reader.Deserialize(stream);
20+
value.Should().Be("1C1C1C");
21+
}
22+
}
23+
24+
[Fact]
25+
public void ExchangeReconcileVersions()
26+
{
27+
using (var stream = new MemoryStream(FormatReconcileUtils.GetReconcileMagic()))
28+
{
29+
using(var response = new MemoryStream())
30+
{
31+
if (FormatReconcileUtils.CheckReconcileRequest(stream))
32+
{
33+
FormatReconcileUtils.WriteReconcileResponse(response, 1, 1);
34+
}
35+
36+
var data = response.ToArray();
37+
Assert.True(FormatReconcileUtils.CheckReconcilePrefix(data));
38+
Assert.Equal(FormatReconcileUtils.FORMAT_RECONCILE_RESPONSE_PREFIX.Length + sizeof(int), data.Length);
39+
40+
var frmt = BitConverter.ToInt32(data, FormatReconcileUtils.FORMAT_RECONCILE_RESPONSE_PREFIX.Length);
41+
var (transport, version) = FormatReconcileUtils.DecodeFormatMarker(frmt);
42+
Assert.Equal(1, transport);
43+
Assert.Equal(1, version);
44+
}
45+
}
46+
}
47+
}
48+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net48</TargetFramework>
5+
<Configurations>Debug;Release;LinuxDebug</Configurations>
6+
<Platforms>AnyCPU</Platforms>
7+
<LangVersion>7.3</LangVersion>
8+
<GenerateRuntimeConfigDevFile>true</GenerateRuntimeConfigDevFile>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
14+
<PackageReference Include="xunit" Version="2.5.3"/>
15+
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
16+
<PackageReference Include="FluentAssertions" Version="5.10.3" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<ProjectReference Include="..\..\OneScript.DebugProtocol\OneScript.DebugProtocol.csproj" />
21+
</ItemGroup>
22+
23+
</Project>

src/VSCode.DebugAdapter/Transport/ConnectionFactory.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ public static TcpClient Connect(int port)
2424

2525
var client = new TcpClient();
2626
TryConnect(client, debuggerUri);
27+
var waitSec = 15;
28+
Log.Information("Waiting {waitSec} seconds", waitSec);
29+
Thread.Sleep(waitSec * 1000);
30+
Log.Information("Waiting completed");
2731

2832
return client;
2933
}

src/VSCode.DebugAdapter/Transport/DebugClientFactory.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ private void ReconcileDataFormat(TcpClient client)
6161
{
6262
Log.Verbose("Sending reconcile message");
6363
var stream = client.GetStream();
64-
stream.Write(FormatReconcileUtils.FORMAT_RECONCILE_MAGIC, 0, FormatReconcileUtils.FORMAT_RECONCILE_MAGIC.Length);
64+
var magic = FormatReconcileUtils.GetReconcileMagic();
65+
stream.Write(magic, 0, magic.Length);
6566

6667
var pollResult = client.Client
6768
.Poll(FormatReconcileUtils.FORMAT_RECONCILE_TIMEOUT.Milliseconds * 1000, SelectMode.SelectRead);
@@ -93,6 +94,7 @@ private void ReconcileDataFormat(TcpClient client)
9394
{
9495
Log.Verbose("Received data is not reconcile message");
9596
SelectSafestFormat();
97+
EmptyIncomingBuffer(client);
9698
return;
9799
}
98100

@@ -116,15 +118,34 @@ private void ReconcileDataFormat(TcpClient client)
116118
}
117119
else
118120
{
121+
Log.Verbose("We waited for full reconcile data, but it hadn't arrived");
119122
SelectSafestFormat();
123+
EmptyIncomingBuffer(client);
120124
}
121125
}
122126
else
123127
{
128+
Log.Verbose("No reconciliation response");
124129
SelectSafestFormat();
125130
}
126131
}
127132

133+
private void EmptyIncomingBuffer(TcpClient client)
134+
{
135+
if (client.Available == 0)
136+
return;
137+
138+
var buf = new byte[1024];
139+
do
140+
{
141+
var hasBytes = client.Available;
142+
var bytesRead = client.GetStream().Read(buf, 0, Math.Min(hasBytes, buf.Length));
143+
if (bytesRead == 0)
144+
return;
145+
146+
} while (client.Available > 0);
147+
}
148+
128149
private void ReadStream(BinaryReader reader, byte[] buffer, int length)
129150
{
130151
int readPosition = 0;
@@ -142,7 +163,6 @@ private void ReadStream(BinaryReader reader, byte[] buffer, int length)
142163

143164
private void SelectSafestFormat()
144165
{
145-
Log.Verbose("Reconcilation failed, selecting safest format");
146166
_protocolVersion = ProtocolVersions.SafestVersion;
147167
_transport = TransportProtocols.Binary;
148168
}

0 commit comments

Comments
 (0)