Upgraded SignalR to 1.2.2

This commit is contained in:
Keivan Beigi
2015-02-07 07:02:45 -08:00
parent 15b0bc0333
commit 127e38feb7
33 changed files with 367 additions and 239 deletions

View File

@@ -33,8 +33,10 @@ namespace Microsoft.AspNet.SignalR.Messaging
_escapedKey = minifiedKey;
}
public static void WriteCursors(TextWriter textWriter, IList<Cursor> cursors)
public static void WriteCursors(TextWriter textWriter, IList<Cursor> cursors, string prefix)
{
textWriter.Write(prefix);
for (int i = 0; i < cursors.Count; i++)
{
if (i > 0)
@@ -48,7 +50,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
}
}
private static void WriteUlongAsHexToBuffer(ulong value, TextWriter textWriter)
internal static void WriteUlongAsHexToBuffer(ulong value, TextWriter textWriter)
{
// This tracks the length of the output and serves as the index for the next character to be written into the pBuffer.
// The length could reach up to 16 characters, so at least that much space should remain in the pBuffer.
@@ -114,17 +116,17 @@ namespace Microsoft.AspNet.SignalR.Messaging
return sb.ToString();
}
public static List<Cursor> GetCursors(string cursor)
public static List<Cursor> GetCursors(string cursor, string prefix)
{
return GetCursors(cursor, s => s);
return GetCursors(cursor, prefix, s => s);
}
public static List<Cursor> GetCursors(string cursor, Func<string, string> keyMaximizer)
public static List<Cursor> GetCursors(string cursor, string prefix, Func<string, string> keyMaximizer)
{
return GetCursors(cursor, (key, state) => ((Func<string, string>)state).Invoke(key), keyMaximizer);
return GetCursors(cursor, prefix, (key, state) => ((Func<string, string>)state).Invoke(key), keyMaximizer);
}
public static List<Cursor> GetCursors(string cursor, Func<string, object, string> keyMaximizer, object state)
public static List<Cursor> GetCursors(string cursor, string prefix, Func<string, object, string> keyMaximizer, object state)
{
// Technically GetCursors should never be called with a null value, so this is extra cautious
if (String.IsNullOrEmpty(cursor))
@@ -132,6 +134,14 @@ namespace Microsoft.AspNet.SignalR.Messaging
throw new FormatException(Resources.Error_InvalidCursorFormat);
}
// If the cursor does not begin with the prefix stream, it isn't necessarily a formatting problem.
// The cursor with a different prefix might have had different, but also valid, formatting.
// Null should be returned so new cursors will be generated
if (!cursor.StartsWith(prefix, StringComparison.Ordinal))
{
return null;
}
var signals = new HashSet<string>();
var cursors = new List<Cursor>();
string currentKey = null;
@@ -143,8 +153,10 @@ namespace Microsoft.AspNet.SignalR.Messaging
var sbEscaped = new StringBuilder();
Cursor parsedCursor;
foreach (var ch in cursor)
for (int i = prefix.Length; i < cursor.Length; i++)
{
var ch = cursor[i];
// escape can only be true if we are consuming the key
if (escape)
{

View File

@@ -3,7 +3,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Infrastructure;
@@ -11,6 +13,8 @@ namespace Microsoft.AspNet.SignalR.Messaging
{
internal class DefaultSubscription : Subscription
{
internal static string _defaultCursorPrefix = GetCursorPrefix();
private List<Cursor> _cursors;
private List<Topic> _cursorTopics;
@@ -36,7 +40,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
else
{
// Ensure delegate continues to use the C# Compiler static delegate caching optimization.
_cursors = Cursor.GetCursors(cursor, (k, s) => UnminifyCursor(k, s), stringMinifier) ?? GetCursorsFromEventKeys(EventKeys, topics);
_cursors = Cursor.GetCursors(cursor, _defaultCursorPrefix, (k, s) => UnminifyCursor(k, s), stringMinifier) ?? GetCursorsFromEventKeys(EventKeys, topics);
}
_cursorTopics = new List<Topic>();
@@ -126,7 +130,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
{
lock (_cursors)
{
Cursor.WriteCursors(textWriter, _cursors);
Cursor.WriteCursors(textWriter, _cursors, _defaultCursorPrefix);
}
}
@@ -196,6 +200,22 @@ namespace Microsoft.AspNet.SignalR.Messaging
return list;
}
private static string GetCursorPrefix()
{
using (var rng = new RNGCryptoServiceProvider())
{
var data = new byte[4];
rng.GetBytes(data);
using (var writer = new StringWriter(CultureInfo.InvariantCulture))
{
var randomValue = (ulong)BitConverter.ToUInt32(data, 0);
Cursor.WriteUlongAsHexToBuffer(randomValue, writer);
return "d-" + writer.ToString() + "-";
}
}
}
private static ulong GetMessageId(TopicLookup topics, string key)
{
Topic topic;

View File

@@ -233,7 +233,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
}
finally
{
if (!subscription.UnsetQueued() || workTask.IsFaulted)
if (!subscription.UnsetQueued() || workTask.IsFaulted || workTask.IsCanceled)
{
// If we don't have more work to do just make the subscription null
subscription = null;
@@ -271,7 +271,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
Trace.TraceEvent(TraceEventType.Error, 0, "Work failed for " + subscription.Identity + ": " + task.Exception.GetBaseException());
}
if (moreWork && !task.IsFaulted)
if (moreWork && !task.IsFaulted && !task.IsCanceled)
{
PumpImpl(taskCompletionSource, subscription);
}
@@ -295,10 +295,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
Trace.TraceEvent(TraceEventType.Verbose, 0, "Dispoing the broker");
//Check if OS is not Windows and exit
var platform = (int)Environment.OSVersion.Platform;
if ((platform == 4) || (platform == 6) || (platform == 128))
if (MonoUtility.IsRunningMono)
{
return;
}

View File

@@ -15,6 +15,9 @@ namespace Microsoft.AspNet.SignalR.Messaging
private static readonly List<ArraySegment<Message>> _emptyList = new List<ArraySegment<Message>>();
public readonly static MessageResult TerminalMessage = new MessageResult(terminal: true);
/// <summary>
/// Gets an <see cref="T:IList{Message}"/> associated with the result.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an optimization to avoid allocations.")]
public IList<ArraySegment<Message>> Messages { get; private set; }

View File

@@ -12,6 +12,8 @@ namespace Microsoft.AspNet.SignalR.Messaging
{
public class ScaleoutSubscription : Subscription
{
private const string _scaleoutCursorPrefix = "s-";
private readonly IList<ScaleoutMappingStore> _streams;
private readonly List<Cursor> _cursors;
@@ -40,10 +42,15 @@ namespace Microsoft.AspNet.SignalR.Messaging
}
else
{
cursors = Cursor.GetCursors(cursor);
cursors = Cursor.GetCursors(cursor, _scaleoutCursorPrefix);
// If the cursor had a default prefix, "d-", cursors might be null
if (cursors == null)
{
cursors = new List<Cursor>();
}
// If the streams don't match the cursors then throw it out
if (cursors.Count != _streams.Count)
else if (cursors.Count != _streams.Count)
{
cursors.Clear();
}
@@ -63,7 +70,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
public override void WriteCursor(TextWriter textWriter)
{
Cursor.WriteCursors(textWriter, _cursors);
Cursor.WriteCursors(textWriter, _cursors, _scaleoutCursorPrefix);
}
[SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists", Justification = "The list needs to be populated")]

View File

@@ -120,13 +120,7 @@ namespace Microsoft.AspNet.SignalR.Messaging
WorkImpl(tcs);
// Fast Path
if (tcs.Task.IsCompleted)
{
return tcs.Task;
}
return FinishAsync(tcs);
return tcs.Task;
}
public bool SetQueued()
@@ -140,19 +134,6 @@ namespace Microsoft.AspNet.SignalR.Messaging
return Interlocked.CompareExchange(ref _state, State.Idle, State.Working) != State.Working;
}
private static Task FinishAsync(TaskCompletionSource<object> tcs)
{
return tcs.Task.ContinueWith(task =>
{
if (task.IsFaulted)
{
return TaskAsyncHelper.FromError(task.Exception);
}
return TaskAsyncHelper.Empty;
}).FastUnwrap();
}
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "We have a sync and async code path.")]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to avoid user code taking the process down.")]
private void WorkImpl(TaskCompletionSource<object> taskCompletionSource)
@@ -200,7 +181,14 @@ namespace Microsoft.AspNet.SignalR.Messaging
}
catch (Exception ex)
{
taskCompletionSource.TrySetUnwrappedException(ex);
if (ex.InnerException is TaskCanceledException)
{
taskCompletionSource.TrySetCanceled();
}
else
{
taskCompletionSource.TrySetUnwrappedException(ex);
}
}
}
else
@@ -233,6 +221,10 @@ namespace Microsoft.AspNet.SignalR.Messaging
{
taskCompletionSource.TrySetUnwrappedException(task.Exception);
}
else if (task.IsCanceled)
{
taskCompletionSource.TrySetCanceled();
}
else if (task.Result)
{
WorkImpl(taskCompletionSource);