Skip to content

Commit

Permalink
Use MessagePackReader \ MessagePackWriter to implement IHubProtocol f…
Browse files Browse the repository at this point in the history
…or server-side Blazor (#8687)

* Use MessagePackReader \ MessagePackWriter to implement IHubProtocol for server-side Blazor

Fixes #7311
  • Loading branch information
pranavkm committed Apr 1, 2019
1 parent 7f4dd27 commit d86c9b3
Show file tree
Hide file tree
Showing 16 changed files with 1,440 additions and 657 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[submodule "googletest"]
path = src/submodules/googletest
url = https://github.com/google/googletest

[submodule "src/submodules/MessagePack-CSharp"]
path = src/submodules/MessagePack-CSharp
url = https://github.com/aspnet/MessagePack-CSharp.git
4 changes: 3 additions & 1 deletion src/Components/Browser.JS/src/Boot.Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ async function boot() {
}

async function initializeConnection(circuitHandlers: CircuitHandler[]): Promise<signalR.HubConnection> {
const hubProtocol = new MessagePackHubProtocol();
(hubProtocol as any).name = 'blazorpack';
const connection = new signalR.HubConnectionBuilder()
.withUrl('_blazor')
.withHubProtocol(new MessagePackHubProtocol())
.withHubProtocol(hubProtocol)
.configureLogging(signalR.LogLevel.Information)
.build();

Expand Down
193 changes: 193 additions & 0 deletions src/Components/Server/src/BlazorPack/ArrayBufferWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

// Copied from https://github.com/dotnet/corefx/blob/b0751dcd4a419ba6731dcaa7d240a8a1946c934c/src/System.Text.Json/src/System/Text/Json/Serialization/ArrayBufferWriter.cs

using System;
using System.Buffers;
using System.Diagnostics;

namespace Microsoft.AspNetCore.Components.Server.BlazorPack
{
// Note: this is currently an internal class that will be replaced with a shared version.
internal sealed class ArrayBufferWriter<T> : IBufferWriter<T>, IDisposable
{
private T[] _rentedBuffer;
private int _index;

private const int MinimumBufferSize = 256;

public ArrayBufferWriter()
{
_rentedBuffer = ArrayPool<T>.Shared.Rent(MinimumBufferSize);
_index = 0;
}

public ArrayBufferWriter(int initialCapacity)
{
if (initialCapacity <= 0)
{
throw new ArgumentException(nameof(initialCapacity));
}

_rentedBuffer = ArrayPool<T>.Shared.Rent(initialCapacity);
_index = 0;
}

public ReadOnlyMemory<T> WrittenMemory
{
get
{
CheckIfDisposed();

return _rentedBuffer.AsMemory(0, _index);
}
}

public int WrittenCount
{
get
{
CheckIfDisposed();

return _index;
}
}

public int Capacity
{
get
{
CheckIfDisposed();

return _rentedBuffer.Length;
}
}

public int FreeCapacity
{
get
{
CheckIfDisposed();

return _rentedBuffer.Length - _index;
}
}

public void Clear()
{
CheckIfDisposed();

ClearHelper();
}

private void ClearHelper()
{
Debug.Assert(_rentedBuffer != null);

_rentedBuffer.AsSpan(0, _index).Clear();
_index = 0;
}

// Returns the rented buffer back to the pool
public void Dispose()
{
if (_rentedBuffer == null)
{
return;
}

ClearHelper();
ArrayPool<T>.Shared.Return(_rentedBuffer);
_rentedBuffer = null;
}

private void CheckIfDisposed()
{
if (_rentedBuffer == null)
{
ThrowObjectDisposedException();
}
}

private static void ThrowObjectDisposedException()
{
throw new ObjectDisposedException(nameof(ArrayBufferWriter<T>));
}

public void Advance(int count)
{
CheckIfDisposed();

if (count < 0)
throw new ArgumentException(nameof(count));

if (_index > _rentedBuffer.Length - count)
{
ThrowInvalidOperationException(_rentedBuffer.Length);
}

_index += count;
}

public Memory<T> GetMemory(int sizeHint = 0)
{
CheckIfDisposed();

CheckAndResizeBuffer(sizeHint);
return _rentedBuffer.AsMemory(_index);
}

public Span<T> GetSpan(int sizeHint = 0)
{
CheckIfDisposed();

CheckAndResizeBuffer(sizeHint);
return _rentedBuffer.AsSpan(_index);
}

private void CheckAndResizeBuffer(int sizeHint)
{
Debug.Assert(_rentedBuffer != null);

if (sizeHint < 0)
{
throw new ArgumentException(nameof(sizeHint));
}

if (sizeHint == 0)
{
sizeHint = MinimumBufferSize;
}

var availableSpace = _rentedBuffer.Length - _index;

if (sizeHint > availableSpace)
{
var growBy = Math.Max(sizeHint, _rentedBuffer.Length);

var newSize = checked(_rentedBuffer.Length + growBy);

var oldBuffer = _rentedBuffer;

_rentedBuffer = ArrayPool<T>.Shared.Rent(newSize);

Debug.Assert(oldBuffer.Length >= _index);
Debug.Assert(_rentedBuffer.Length >= _index);

var previousBuffer = oldBuffer.AsSpan(0, _index);
previousBuffer.CopyTo(_rentedBuffer);
previousBuffer.Clear();
ArrayPool<T>.Shared.Return(oldBuffer);
}

Debug.Assert(_rentedBuffer.Length - _index > 0);
Debug.Assert(_rentedBuffer.Length - _index >= sizeHint);
}

private static void ThrowInvalidOperationException(int capacity)
{
throw new InvalidOperationException($"Cannot advance past the end of the buffer, which has a size of {capacity}.");
}
}
}
Loading

0 comments on commit d86c9b3

Please sign in to comment.