// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNet.SignalR.Hubs
{
///
/// Common base class to simplify the implementation of IHubPipelineModules.
/// A module can intercept and customize various stages of hub processing such as connecting, reconnecting, disconnecting,
/// invoking server-side hub methods, invoking client-side hub methods, authorizing hub clients and rejoining hub groups.
/// A module can be activated by calling .
/// The combined modules added to the are invoked via the
/// interface.
///
public abstract class HubPipelineModule : IHubPipelineModule
{
///
/// Wraps a function that invokes a server-side hub method. Even if a client has not been authorized to connect
/// to a hub, it will still be authorized to invoke server-side methods on that hub unless it is prevented in
/// by not executing the invoke parameter.
///
/// A function that invokes a server-side hub method.
/// A wrapped function that invokes a server-side hub method.
public virtual Func> BuildIncoming(Func> invoke)
{
return context =>
{
if (OnBeforeIncoming(context))
{
return invoke(context).OrEmpty()
.Then(result => OnAfterIncoming(result, context))
.Catch(ex => OnIncomingError(ex, context));
}
return TaskAsyncHelper.FromResult(null);
};
}
///
/// Wraps a function that is called when a client connects to the for each
/// the client connects to. By default, this results in the 's
/// OnConnected method being invoked.
///
/// A function to be called when a client connects to a hub.
/// A wrapped function to be called when a client connects to a hub.
public virtual Func BuildConnect(Func connect)
{
return hub =>
{
if (OnBeforeConnect(hub))
{
return connect(hub).OrEmpty().Then(h => OnAfterConnect(h), hub);
}
return TaskAsyncHelper.Empty;
};
}
///
/// Wraps a function that is called when a client reconnects to the for each
/// the client connects to. By default, this results in the 's
/// OnReconnected method being invoked.
///
/// A function to be called when a client reconnects to a hub.
/// A wrapped function to be called when a client reconnects to a hub.
public virtual Func BuildReconnect(Func reconnect)
{
return (hub) =>
{
if (OnBeforeReconnect(hub))
{
return reconnect(hub).OrEmpty().Then(h => OnAfterReconnect(h), hub);
}
return TaskAsyncHelper.Empty;
};
}
///
/// Wraps a function that is called when a client disconnects from the for each
/// the client was connected to. By default, this results in the 's
/// OnDisconnected method being invoked.
///
/// A function to be called when a client disconnects from a hub.
/// A wrapped function to be called when a client disconnects from a hub.
public virtual Func BuildDisconnect(Func disconnect)
{
return hub =>
{
if (OnBeforeDisconnect(hub))
{
return disconnect(hub).OrEmpty().Then(h => OnAfterDisconnect(h), hub);
}
return TaskAsyncHelper.Empty;
};
}
///
/// Wraps a function to be called before a client subscribes to signals belonging to the hub described by the
/// . By default, the will look for attributes on the
/// to help determine if the client is authorized to subscribe to method invocations for the
/// described hub.
/// The function returns true if the client is authorized to subscribe to client-side hub method
/// invocations; false, otherwise.
///
///
/// A function that dictates whether or not the client is authorized to connect to the described Hub.
///
///
/// A wrapped function that dictates whether or not the client is authorized to connect to the described Hub.
///
public virtual Func BuildAuthorizeConnect(Func authorizeConnect)
{
return (hubDescriptor, request) =>
{
if (OnBeforeAuthorizeConnect(hubDescriptor, request))
{
return authorizeConnect(hubDescriptor, request);
}
return false;
};
}
///
/// Wraps a function that determines which of the groups belonging to the hub described by the
/// the client should be allowed to rejoin.
/// By default, clients will rejoin all the groups they were in prior to reconnecting.
///
/// A function that determines which groups the client should be allowed to rejoin.
/// A wrapped function that determines which groups the client should be allowed to rejoin.
public virtual Func, IList> BuildRejoiningGroups(Func, IList> rejoiningGroups)
{
return rejoiningGroups;
}
///
/// Wraps a function that invokes a client-side hub method.
///
/// A function that invokes a client-side hub method.
/// A wrapped function that invokes a client-side hub method.
public virtual Func BuildOutgoing(Func send)
{
return context =>
{
if (OnBeforeOutgoing(context))
{
return send(context).OrEmpty().Then(ctx => OnAfterOutgoing(ctx), context);
}
return TaskAsyncHelper.Empty;
};
}
///
/// This method is called before the AuthorizeConnect components of any modules added later to the
/// are executed. If this returns false, then those later-added modules will not run and the client will not be allowed
/// to subscribe to client-side invocations of methods belonging to the hub defined by the .
///
/// A description of the hub the client is trying to subscribe to.
/// The connect request of the client trying to subscribe to the hub.
/// true, if the client is authorized to connect to the hub, false otherwise.
protected virtual bool OnBeforeAuthorizeConnect(HubDescriptor hubDescriptor, IRequest request)
{
return true;
}
///
/// This method is called before the connect components of any modules added later to the are
/// executed. If this returns false, then those later-added modules and the method will
/// not be run.
///
/// The hub the client has connected to.
///
/// true, if the connect components of later added modules and the method should be executed;
/// false, otherwise.
///
protected virtual bool OnBeforeConnect(IHub hub)
{
return true;
}
///
/// This method is called after the connect components of any modules added later to the are
/// executed and after is executed, if at all.
///
/// The hub the client has connected to.
protected virtual void OnAfterConnect(IHub hub)
{
}
///
/// This method is called before the reconnect components of any modules added later to the are
/// executed. If this returns false, then those later-added modules and the method will
/// not be run.
///
/// The hub the client has reconnected to.
///
/// true, if the reconnect components of later added modules and the method should be executed;
/// false, otherwise.
///
protected virtual bool OnBeforeReconnect(IHub hub)
{
return true;
}
///
/// This method is called after the reconnect components of any modules added later to the are
/// executed and after is executed, if at all.
///
/// The hub the client has reconnected to.
protected virtual void OnAfterReconnect(IHub hub)
{
}
///
/// This method is called before the outgoing components of any modules added later to the are
/// executed. If this returns false, then those later-added modules and the client-side hub method invocation(s) will not
/// be executed.
///
/// A description of the client-side hub method invocation.
///
/// true, if the outgoing components of later added modules and the client-side hub method invocation(s) should be executed;
/// false, otherwise.
///
protected virtual bool OnBeforeOutgoing(IHubOutgoingInvokerContext context)
{
return true;
}
///
/// This method is called after the outgoing components of any modules added later to the are
/// executed. This does not mean that all the clients have received the hub method invocation, but it does indicate indicate
/// a hub invocation message has successfully been published to a message bus.
///
/// A description of the client-side hub method invocation.
protected virtual void OnAfterOutgoing(IHubOutgoingInvokerContext context)
{
}
///
/// This method is called before the disconnect components of any modules added later to the are
/// executed. If this returns false, then those later-added modules and the method will
/// not be run.
///
/// The hub the client has disconnected from.
///
/// true, if the disconnect components of later added modules and the method should be executed;
/// false, otherwise.
///
protected virtual bool OnBeforeDisconnect(IHub hub)
{
return true;
}
///
/// This method is called after the disconnect components of any modules added later to the are
/// executed and after is executed, if at all.
///
/// The hub the client has disconnected from.
protected virtual void OnAfterDisconnect(IHub hub)
{
}
///
/// This method is called before the incoming components of any modules added later to the are
/// executed. If this returns false, then those later-added modules and the server-side hub method invocation will not
/// be executed. Even if a client has not been authorized to connect to a hub, it will still be authorized to invoke
/// server-side methods on that hub unless it is prevented in by not
/// executing the invoke parameter or prevented in by returning false.
///
/// A description of the server-side hub method invocation.
///
/// true, if the incoming components of later added modules and the server-side hub method invocation should be executed;
/// false, otherwise.
///
protected virtual bool OnBeforeIncoming(IHubIncomingInvokerContext context)
{
return true;
}
///
/// This method is called after the incoming components of any modules added later to the
/// and the server-side hub method have completed execution.
///
/// The return value of the server-side hub method
/// A description of the server-side hub method invocation.
/// The possibly new or updated return value of the server-side hub method
protected virtual object OnAfterIncoming(object result, IHubIncomingInvokerContext context)
{
return result;
}
///
/// This is called when an uncaught exception is thrown by a server-side hub method or the incoming component of a
/// module added later to the . Observing the exception using this method will not prevent
/// it from bubbling up to other modules.
///
/// The exception that was thrown during the server-side invocation.
/// A description of the server-side hub method invocation.
protected virtual void OnIncomingError(Exception ex, IHubIncomingInvokerContext context)
{
}
}
}