Skip to content

Commit 2cdb721

Browse files
Rafal Maciagclaude
andcommitted
Add RocketWelder.BinaryProtocol package for WASM-compatible protocol decoding
- Extract VarintExtensions and BinaryFrameReader to separate WASM-compatible package - Update SDK to reference BinaryProtocol (project reference converts to package dependency) - Update preview-publish.yml and publish-csharp-nuget.yml workflows to publish both packages - Add release.sh script for production releases The BinaryProtocol package enables WASM clients (like rocket-welder2 Blazor) to decode streaming data without depending on SDK's native dependencies. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 81c30b3 commit 2cdb721

File tree

12 files changed

+656
-168
lines changed

12 files changed

+656
-168
lines changed

.github/workflows/preview-publish.yml

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,12 @@ jobs:
8181
- name: Update version in csproj
8282
run: |
8383
VERSION="${{ needs.preview-version.outputs.version }}"
84-
cd csharp/RocketWelder.SDK
84+
# Update BinaryProtocol version
85+
cd csharp/RocketWelder.BinaryProtocol
86+
sed -i "s/<Version>.*<\/Version>/<Version>$VERSION<\/Version>/" RocketWelder.BinaryProtocol.csproj
87+
cd ..
88+
# Update SDK version
89+
cd RocketWelder.SDK
8590
sed -i "s/<Version>.*<\/Version>/<Version>$VERSION<\/Version>/" RocketWelder.SDK.csproj
8691
8792
- name: Restore dependencies
@@ -92,11 +97,25 @@ jobs:
9297
working-directory: ./csharp
9398
run: dotnet build --configuration Release --no-restore
9499

95-
- name: Pack
100+
- name: Pack BinaryProtocol
101+
working-directory: ./csharp
102+
run: dotnet pack RocketWelder.BinaryProtocol/RocketWelder.BinaryProtocol.csproj --configuration Release --no-build --output ./nupkg /p:PackageVersion=${{ needs.preview-version.outputs.version }}
103+
104+
- name: Push BinaryProtocol to NuGet
105+
working-directory: ./csharp
106+
run: |
107+
dotnet nuget push ./nupkg/RocketWelder.BinaryProtocol.*.nupkg \
108+
--api-key ${{ secrets.NUGET_API_KEY }} \
109+
--source https://api.nuget.org/v3/index.json \
110+
--skip-duplicate
111+
env:
112+
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
113+
114+
- name: Pack SDK
96115
working-directory: ./csharp
97116
run: dotnet pack RocketWelder.SDK/RocketWelder.SDK.csproj --configuration Release --no-build --output ./nupkg /p:PackageVersion=${{ needs.preview-version.outputs.version }}
98117

99-
- name: Push to NuGet
118+
- name: Push SDK to NuGet
100119
working-directory: ./csharp
101120
run: |
102121
dotnet nuget push ./nupkg/RocketWelder.SDK.*.nupkg \
@@ -108,13 +127,16 @@ jobs:
108127

109128
- name: Summary
110129
run: |
111-
echo "## C# SDK Preview Published to NuGet" >> $GITHUB_STEP_SUMMARY
130+
echo "## C# Packages Preview Published to NuGet" >> $GITHUB_STEP_SUMMARY
112131
echo "" >> $GITHUB_STEP_SUMMARY
113132
echo "- **Version**: ${{ needs.preview-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
114-
echo "- **Package**: RocketWelder.SDK" >> $GITHUB_STEP_SUMMARY
115-
echo "- **NuGet**: https://www.nuget.org/packages/RocketWelder.SDK" >> $GITHUB_STEP_SUMMARY
116133
echo "" >> $GITHUB_STEP_SUMMARY
117-
echo "Install with:" >> $GITHUB_STEP_SUMMARY
134+
echo "### RocketWelder.BinaryProtocol" >> $GITHUB_STEP_SUMMARY
135+
echo '```bash' >> $GITHUB_STEP_SUMMARY
136+
echo 'dotnet add package RocketWelder.BinaryProtocol --version ${{ needs.preview-version.outputs.version }}' >> $GITHUB_STEP_SUMMARY
137+
echo '```' >> $GITHUB_STEP_SUMMARY
138+
echo "" >> $GITHUB_STEP_SUMMARY
139+
echo "### RocketWelder.SDK" >> $GITHUB_STEP_SUMMARY
118140
echo '```bash' >> $GITHUB_STEP_SUMMARY
119141
echo 'dotnet add package RocketWelder.SDK --version ${{ needs.preview-version.outputs.version }}' >> $GITHUB_STEP_SUMMARY
120142
echo '```' >> $GITHUB_STEP_SUMMARY

.github/workflows/publish-csharp-nuget.yml

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,13 @@ jobs:
4545
- name: Update version in csproj
4646
run: |
4747
VERSION="${{ steps.version.outputs.version }}"
48-
cd csharp/RocketWelder.SDK
49-
# Update version in .csproj file
48+
# Update BinaryProtocol version
49+
cd csharp/RocketWelder.BinaryProtocol
50+
sed -i "s/<Version>.*<\/Version>/<Version>$VERSION<\/Version>/" RocketWelder.BinaryProtocol.csproj
51+
sed -i "s/<PackageVersion>.*<\/PackageVersion>/<PackageVersion>$VERSION<\/PackageVersion>/" RocketWelder.BinaryProtocol.csproj
52+
cd ..
53+
# Update SDK version
54+
cd RocketWelder.SDK
5055
sed -i "s/<Version>.*<\/Version>/<Version>$VERSION<\/Version>/" RocketWelder.SDK.csproj
5156
sed -i "s/<PackageVersion>.*<\/PackageVersion>/<PackageVersion>$VERSION<\/PackageVersion>/" RocketWelder.SDK.csproj
5257
@@ -58,11 +63,25 @@ jobs:
5863
working-directory: ./csharp
5964
run: dotnet build --configuration Release --no-restore
6065

61-
- name: Pack
66+
- name: Pack BinaryProtocol
67+
working-directory: ./csharp
68+
run: dotnet pack RocketWelder.BinaryProtocol/RocketWelder.BinaryProtocol.csproj --configuration Release --no-build --output ./nupkg /p:PackageVersion=${{ steps.version.outputs.version }}
69+
70+
- name: Push BinaryProtocol to NuGet
71+
working-directory: ./csharp
72+
run: |
73+
dotnet nuget push ./nupkg/RocketWelder.BinaryProtocol.*.nupkg \
74+
--api-key ${{ secrets.NUGET_API_KEY }} \
75+
--source https://api.nuget.org/v3/index.json \
76+
--skip-duplicate
77+
env:
78+
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
79+
80+
- name: Pack SDK
6281
working-directory: ./csharp
6382
run: dotnet pack RocketWelder.SDK/RocketWelder.SDK.csproj --configuration Release --no-build --output ./nupkg /p:PackageVersion=${{ steps.version.outputs.version }}
64-
65-
- name: Push to NuGet
83+
84+
- name: Push SDK to NuGet
6685
working-directory: ./csharp
6786
run: |
6887
dotnet nuget push ./nupkg/RocketWelder.SDK.*.nupkg \
@@ -74,13 +93,18 @@ jobs:
7493

7594
- name: Summary
7695
run: |
77-
echo "## C# SDK Published to NuGet" >> $GITHUB_STEP_SUMMARY
96+
echo "## C# Packages Published to NuGet" >> $GITHUB_STEP_SUMMARY
7897
echo "" >> $GITHUB_STEP_SUMMARY
7998
echo "- **Version**: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
80-
echo "- **Package**: RocketWelder.SDK" >> $GITHUB_STEP_SUMMARY
81-
echo "- **NuGet**: https://www.nuget.org/packages/RocketWelder.SDK" >> $GITHUB_STEP_SUMMARY
8299
echo "" >> $GITHUB_STEP_SUMMARY
83-
echo "Install with:" >> $GITHUB_STEP_SUMMARY
100+
echo "### RocketWelder.BinaryProtocol" >> $GITHUB_STEP_SUMMARY
101+
echo "- **NuGet**: https://www.nuget.org/packages/RocketWelder.BinaryProtocol" >> $GITHUB_STEP_SUMMARY
102+
echo '```bash' >> $GITHUB_STEP_SUMMARY
103+
echo 'dotnet add package RocketWelder.BinaryProtocol --version ${{ steps.version.outputs.version }}' >> $GITHUB_STEP_SUMMARY
104+
echo '```' >> $GITHUB_STEP_SUMMARY
105+
echo "" >> $GITHUB_STEP_SUMMARY
106+
echo "### RocketWelder.SDK" >> $GITHUB_STEP_SUMMARY
107+
echo "- **NuGet**: https://www.nuget.org/packages/RocketWelder.SDK" >> $GITHUB_STEP_SUMMARY
84108
echo '```bash' >> $GITHUB_STEP_SUMMARY
85109
echo 'dotnet add package RocketWelder.SDK --version ${{ steps.version.outputs.version }}' >> $GITHUB_STEP_SUMMARY
86110
echo '```' >> $GITHUB_STEP_SUMMARY
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using System.Buffers.Binary;
2+
using System.Text;
3+
4+
namespace RocketWelder.BinaryProtocol;
5+
6+
/// <summary>
7+
/// Zero-allocation binary reader for parsing streaming protocol data.
8+
/// Designed for high-performance frame decoding in real-time video processing.
9+
/// </summary>
10+
public ref struct BinaryFrameReader
11+
{
12+
private readonly ReadOnlySpan<byte> _data;
13+
private int _position;
14+
15+
public BinaryFrameReader(ReadOnlySpan<byte> data)
16+
{
17+
_data = data;
18+
_position = 0;
19+
}
20+
21+
/// <summary>
22+
/// Returns true if there is more data to read.
23+
/// </summary>
24+
public bool HasMore => _position < _data.Length;
25+
26+
/// <summary>
27+
/// Current read position in the buffer.
28+
/// </summary>
29+
public int Position => _position;
30+
31+
/// <summary>
32+
/// Remaining bytes available to read.
33+
/// </summary>
34+
public int Remaining => _data.Length - _position;
35+
36+
/// <summary>
37+
/// Read a single byte.
38+
/// </summary>
39+
public byte ReadByte()
40+
{
41+
if (_position >= _data.Length)
42+
throw new EndOfStreamException("Unexpected end of data");
43+
return _data[_position++];
44+
}
45+
46+
/// <summary>
47+
/// Read an unsigned 64-bit integer (little-endian).
48+
/// </summary>
49+
public ulong ReadUInt64LE()
50+
{
51+
if (_position + 8 > _data.Length)
52+
throw new EndOfStreamException("Not enough data for UInt64");
53+
var value = BinaryPrimitives.ReadUInt64LittleEndian(_data.Slice(_position, 8));
54+
_position += 8;
55+
return value;
56+
}
57+
58+
/// <summary>
59+
/// Read a signed 32-bit integer (little-endian).
60+
/// </summary>
61+
public int ReadInt32LE()
62+
{
63+
if (_position + 4 > _data.Length)
64+
throw new EndOfStreamException("Not enough data for Int32");
65+
var value = BinaryPrimitives.ReadInt32LittleEndian(_data.Slice(_position, 4));
66+
_position += 4;
67+
return value;
68+
}
69+
70+
/// <summary>
71+
/// Read an unsigned 16-bit integer (little-endian).
72+
/// </summary>
73+
public ushort ReadUInt16LE()
74+
{
75+
if (_position + 2 > _data.Length)
76+
throw new EndOfStreamException("Not enough data for UInt16");
77+
var value = BinaryPrimitives.ReadUInt16LittleEndian(_data.Slice(_position, 2));
78+
_position += 2;
79+
return value;
80+
}
81+
82+
/// <summary>
83+
/// Read a 32-bit floating point (little-endian).
84+
/// </summary>
85+
public float ReadSingleLE()
86+
{
87+
if (_position + 4 > _data.Length)
88+
throw new EndOfStreamException("Not enough data for Single");
89+
var value = BinaryPrimitives.ReadSingleLittleEndian(_data.Slice(_position, 4));
90+
_position += 4;
91+
return value;
92+
}
93+
94+
/// <summary>
95+
/// Read a varint-encoded unsigned 32-bit integer.
96+
/// </summary>
97+
public uint ReadVarint()
98+
{
99+
uint result = 0;
100+
int shift = 0;
101+
102+
while (true)
103+
{
104+
if (_position >= _data.Length)
105+
throw new EndOfStreamException("Unexpected end of varint");
106+
107+
byte b = _data[_position++];
108+
result |= (uint)(b & 0x7F) << shift;
109+
110+
if ((b & 0x80) == 0)
111+
break;
112+
113+
shift += 7;
114+
if (shift >= 35)
115+
throw new InvalidDataException("Varint too long");
116+
}
117+
118+
return result;
119+
}
120+
121+
/// <summary>
122+
/// Read a ZigZag-encoded signed integer (varint format).
123+
/// </summary>
124+
public int ReadZigZagVarint()
125+
{
126+
uint encoded = ReadVarint();
127+
return encoded.ZigZagDecode();
128+
}
129+
130+
/// <summary>
131+
/// Read a UTF-8 encoded string of specified length.
132+
/// </summary>
133+
public string ReadString(int length)
134+
{
135+
if (_position + length > _data.Length)
136+
throw new EndOfStreamException($"Not enough data for string of length {length}");
137+
138+
var bytes = _data.Slice(_position, length);
139+
_position += length;
140+
return Encoding.UTF8.GetString(bytes);
141+
}
142+
143+
/// <summary>
144+
/// Skip a specified number of bytes.
145+
/// </summary>
146+
public void Skip(int count)
147+
{
148+
if (_position + count > _data.Length)
149+
throw new EndOfStreamException($"Cannot skip {count} bytes, only {Remaining} remaining");
150+
_position += count;
151+
}
152+
153+
/// <summary>
154+
/// Read raw bytes into a span.
155+
/// </summary>
156+
public void ReadBytes(Span<byte> destination)
157+
{
158+
if (_position + destination.Length > _data.Length)
159+
throw new EndOfStreamException($"Not enough data for {destination.Length} bytes");
160+
_data.Slice(_position, destination.Length).CopyTo(destination);
161+
_position += destination.Length;
162+
}
163+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net9.0;net10.0</TargetFrameworks>
5+
<LangVersion>latest</LangVersion>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
9+
10+
<!-- NuGet Package Settings -->
11+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
12+
<PackageId>RocketWelder.BinaryProtocol</PackageId>
13+
<Version>1.0.0</Version>
14+
<Authors>ModelingEvolution</Authors>
15+
<Company>ModelingEvolution</Company>
16+
<Copyright>Copyright © ModelingEvolution 2024</Copyright>
17+
<Description>WASM-compatible binary protocol encoders/decoders for RocketWelder streaming data (segmentation, keypoints, actions). Zero-allocation varint and zigzag encoding.</Description>
18+
<PackageTags>protocol;binary;varint;zigzag;streaming;wasm;blazor</PackageTags>
19+
<PackageProjectUrl>https://github.com/modelingevolution/rocket-welder-sdk</PackageProjectUrl>
20+
<RepositoryUrl>https://github.com/modelingevolution/rocket-welder-sdk</RepositoryUrl>
21+
<RepositoryType>git</RepositoryType>
22+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
23+
</PropertyGroup>
24+
25+
</Project>

0 commit comments

Comments
 (0)